Skip to content

Commit 9024768

Browse files
committed
Runtime: Flesh out swift_updateClassMetadata() to use _objc_realizeClassFromSwift()
1 parent 4cecc26 commit 9024768

File tree

1 file changed

+77
-38
lines changed

1 file changed

+77
-38
lines changed

stdlib/public/runtime/Metadata.cpp

Lines changed: 77 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#else
4444
#include <sys/mman.h>
4545
#include <unistd.h>
46+
#include <dlfcn.h>
4647
#endif
4748
#include "llvm/ADT/DenseMap.h"
4849
#include "llvm/ADT/Hashing.h"
@@ -2610,58 +2611,96 @@ swift::swift_initClassMetadata(ClassMetadata *self,
26102611
}
26112612

26122613
#if SWIFT_OBJC_INTEROP
2614+
2615+
// Suppress diagnostic about the availability of _objc_realizeClassFromSwift.
2616+
// We test availability with a nullptr check, but the compiler doesn't see that.
2617+
#pragma clang diagnostic push
2618+
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
2619+
26132620
void
26142621
swift::swift_updateClassMetadata(ClassMetadata *self,
26152622
ClassLayoutFlags layoutFlags,
26162623
size_t numFields,
26172624
const TypeLayout * const *fieldTypes,
26182625
size_t *fieldOffsets) {
2619-
#ifndef NDEBUG
2620-
// If there is a mangled superclass name, demangle it to the superclass
2621-
// type.
2626+
#ifndef OBJC_REALIZECLASSFROMSWIFT_DEFINED
2627+
// Temporary workaround until _objc_realizeClassFromSwift is in the SDK.
2628+
static auto _objc_realizeClassFromSwift =
2629+
(Class (*)(Class _Nullable, void* _Nullable))
2630+
dlsym(RTLD_NEXT, "_objc_realizeClassFromSwift");
2631+
#endif
2632+
2633+
bool requiresUpdate = (_objc_realizeClassFromSwift != nullptr);
2634+
2635+
// If we're on a newer runtime, we're going to be initializing the
2636+
// field offset vector. Realize the superclass metadata first, even
2637+
// though our superclass field references it statically.
26222638
const ClassMetadata *super = nullptr;
2623-
if (auto superclassNameBase = self->getDescription()->SuperclassType.get()) {
2624-
StringRef superclassName =
2625-
Demangle::makeSymbolicMangledNameStringRef(superclassNameBase);
2626-
SubstGenericParametersFromMetadata substitutions(self);
2627-
const Metadata *superclass =
2628-
_getTypeByMangledName(superclassName, substitutions);
2629-
if (!superclass) {
2630-
fatalError(0,
2631-
"failed to demangle superclass of %s from mangled name '%s'\n",
2632-
self->getDescription()->Name.get(),
2633-
superclassName.str().c_str());
2634-
}
26352639

2636-
#if SWIFT_OBJC_INTEROP
2637-
if (auto objcWrapper = dyn_cast<ObjCClassWrapperMetadata>(superclass))
2638-
superclass = objcWrapper->Class;
2640+
// In assert builds, realize the superclass metadata even if we're
2641+
// on an older runtime.
2642+
#ifndef NDEBUG
2643+
bool realizeSuperclass = true;
2644+
#else
2645+
bool realizeSuperclass = requiresUpdate;
26392646
#endif
26402647

2641-
super = cast<ClassMetadata>(superclass);
2642-
}
2648+
if (realizeSuperclass) {
2649+
if (auto superclassNameBase = self->getDescription()->SuperclassType.get()) {
2650+
StringRef superclassName =
2651+
Demangle::makeSymbolicMangledNameStringRef(superclassNameBase);
2652+
SubstGenericParametersFromMetadata substitutions(self);
2653+
const Metadata *superclass =
2654+
_getTypeByMangledName(superclassName, substitutions);
2655+
if (!superclass) {
2656+
fatalError(0,
2657+
"failed to demangle superclass of %s from mangled name '%s'\n",
2658+
self->getDescription()->Name.get(),
2659+
superclassName.str().c_str());
2660+
}
26432661

2644-
if (!super)
2645-
assert(self->Superclass == getRootSuperclass());
2646-
else
2647-
assert(self->Superclass == super);
2648-
#endif
2662+
if (auto objcWrapper = dyn_cast<ObjCClassWrapperMetadata>(superclass))
2663+
superclass = objcWrapper->Class;
26492664

2650-
// FIXME: Plumb this through
2651-
#if 1
2652-
swift_getInitializedObjCClass((Class)self);
2653-
#else
2654-
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets);
2655-
initObjCClass(self, numFields, fieldTypes, fieldOffsets);
2665+
super = cast<ClassMetadata>(superclass);
2666+
}
26562667

2657-
// Register this class with the runtime. This will also cause the
2658-
// runtime to slide the field offsets stored in the field offset
2659-
// globals. Note that the field offset vector is *not* updated;
2660-
// however we should not be using it for anything in a non-generic
2661-
// class.
2662-
swift_getInitializedObjCClassWithoutCallback(self);
2663-
#endif
2668+
// Check that it matches what's already in there.
2669+
if (!super)
2670+
assert(self->Superclass == getRootSuperclass());
2671+
else
2672+
assert(self->Superclass == super);
2673+
}
2674+
2675+
(void) super;
2676+
2677+
// If we're running on a older Objective-C runtime, just realize
2678+
// the class.
2679+
if (!requiresUpdate) {
2680+
// Realize the class. This causes the runtime to slide the field offsets
2681+
// stored in the field offset globals.
2682+
//
2683+
// Note that the field offset vector is *not* updated; however in
2684+
// Objective-C interop mode, we don't actually use the field offset vector
2685+
// of non-generic classes.
2686+
//
2687+
// In particular, class mirrors always use the Objective-C ivar descriptors,
2688+
// which point at field offset globals and not the field offset vector.
2689+
swift_getInitializedObjCClass((Class)self);
2690+
} else {
2691+
// Update the field offset vector using runtime type information; the layout
2692+
// of resilient types might be different than the statically-emitted layout.
2693+
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets);
2694+
2695+
// Copy field offset vector entries to the field offset globals.
2696+
initObjCClass(self, numFields, fieldTypes, fieldOffsets);
2697+
2698+
// See remark above about how this slides field offset globals.
2699+
_objc_realizeClassFromSwift((Class)self, (Class)self);
2700+
}
26642701
}
2702+
2703+
#pragma clang diagnostic pop
26652704
#endif
26662705

26672706
#ifndef NDEBUG

0 commit comments

Comments
 (0)