Runtime: Flesh out swift_updateClassMetadata() to use _objc_realizeClassFromSwift()

This commit is contained in:
Slava Pestov
2018-10-18 16:21:42 -07:00
parent 4cecc268dc
commit 9024768b0e

View File

@@ -43,6 +43,7 @@
#else #else
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include <dlfcn.h>
#endif #endif
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Hashing.h" #include "llvm/ADT/Hashing.h"
@@ -2610,58 +2611,96 @@ swift::swift_initClassMetadata(ClassMetadata *self,
} }
#if SWIFT_OBJC_INTEROP #if SWIFT_OBJC_INTEROP
// Suppress diagnostic about the availability of _objc_realizeClassFromSwift.
// We test availability with a nullptr check, but the compiler doesn't see that.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
void void
swift::swift_updateClassMetadata(ClassMetadata *self, swift::swift_updateClassMetadata(ClassMetadata *self,
ClassLayoutFlags layoutFlags, ClassLayoutFlags layoutFlags,
size_t numFields, size_t numFields,
const TypeLayout * const *fieldTypes, const TypeLayout * const *fieldTypes,
size_t *fieldOffsets) { size_t *fieldOffsets) {
#ifndef NDEBUG #ifndef OBJC_REALIZECLASSFROMSWIFT_DEFINED
// If there is a mangled superclass name, demangle it to the superclass // Temporary workaround until _objc_realizeClassFromSwift is in the SDK.
// type. static auto _objc_realizeClassFromSwift =
(Class (*)(Class _Nullable, void* _Nullable))
dlsym(RTLD_NEXT, "_objc_realizeClassFromSwift");
#endif
bool requiresUpdate = (_objc_realizeClassFromSwift != nullptr);
// If we're on a newer runtime, we're going to be initializing the
// field offset vector. Realize the superclass metadata first, even
// though our superclass field references it statically.
const ClassMetadata *super = nullptr; const ClassMetadata *super = nullptr;
if (auto superclassNameBase = self->getDescription()->SuperclassType.get()) {
StringRef superclassName = // In assert builds, realize the superclass metadata even if we're
Demangle::makeSymbolicMangledNameStringRef(superclassNameBase); // on an older runtime.
SubstGenericParametersFromMetadata substitutions(self); #ifndef NDEBUG
const Metadata *superclass = bool realizeSuperclass = true;
_getTypeByMangledName(superclassName, substitutions); #else
if (!superclass) { bool realizeSuperclass = requiresUpdate;
fatalError(0, #endif
"failed to demangle superclass of %s from mangled name '%s'\n",
self->getDescription()->Name.get(), if (realizeSuperclass) {
superclassName.str().c_str()); if (auto superclassNameBase = self->getDescription()->SuperclassType.get()) {
StringRef superclassName =
Demangle::makeSymbolicMangledNameStringRef(superclassNameBase);
SubstGenericParametersFromMetadata substitutions(self);
const Metadata *superclass =
_getTypeByMangledName(superclassName, substitutions);
if (!superclass) {
fatalError(0,
"failed to demangle superclass of %s from mangled name '%s'\n",
self->getDescription()->Name.get(),
superclassName.str().c_str());
}
if (auto objcWrapper = dyn_cast<ObjCClassWrapperMetadata>(superclass))
superclass = objcWrapper->Class;
super = cast<ClassMetadata>(superclass);
} }
#if SWIFT_OBJC_INTEROP // Check that it matches what's already in there.
if (auto objcWrapper = dyn_cast<ObjCClassWrapperMetadata>(superclass)) if (!super)
superclass = objcWrapper->Class; assert(self->Superclass == getRootSuperclass());
#endif else
assert(self->Superclass == super);
super = cast<ClassMetadata>(superclass);
} }
if (!super) (void) super;
assert(self->Superclass == getRootSuperclass());
else
assert(self->Superclass == super);
#endif
// FIXME: Plumb this through // If we're running on a older Objective-C runtime, just realize
#if 1 // the class.
swift_getInitializedObjCClass((Class)self); if (!requiresUpdate) {
#else // Realize the class. This causes the runtime to slide the field offsets
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets); // stored in the field offset globals.
initObjCClass(self, numFields, fieldTypes, fieldOffsets); //
// Note that the field offset vector is *not* updated; however in
// Objective-C interop mode, we don't actually use the field offset vector
// of non-generic classes.
//
// In particular, class mirrors always use the Objective-C ivar descriptors,
// which point at field offset globals and not the field offset vector.
swift_getInitializedObjCClass((Class)self);
} else {
// Update the field offset vector using runtime type information; the layout
// of resilient types might be different than the statically-emitted layout.
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets);
// Register this class with the runtime. This will also cause the // Copy field offset vector entries to the field offset globals.
// runtime to slide the field offsets stored in the field offset initObjCClass(self, numFields, fieldTypes, fieldOffsets);
// globals. Note that the field offset vector is *not* updated;
// however we should not be using it for anything in a non-generic // See remark above about how this slides field offset globals.
// class. _objc_realizeClassFromSwift((Class)self, (Class)self);
swift_getInitializedObjCClassWithoutCallback(self); }
#endif
} }
#pragma clang diagnostic pop
#endif #endif
#ifndef NDEBUG #ifndef NDEBUG