Skip to content

Commit 4cecc26

Browse files
committed
IRGen: Emit Objective-C metadata update callbacks
1 parent a486e49 commit 4cecc26

File tree

15 files changed

+165
-9
lines changed

15 files changed

+165
-9
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ Globals
106106
global ::= nominal-type 'Mm' // class metaclass
107107
global ::= nominal-type 'Mn' // nominal type descriptor
108108
global ::= nominal-type 'Mu' // class method lookup function
109+
global ::= nominal-type 'MU' // ObjC metadata update callback function
109110
global ::= module 'MXM' // module descriptor
110111
global ::= context 'MXE' // extension descriptor
111112
global ::= context 'MXX' // anonymous context descriptor

include/swift/ABI/Class.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ enum class ObjCClassFlags : uint32_t {
4040
/// This class has the exception attribute.
4141
Exception = 0x00020,
4242

43+
/// This class provides a metadata update callback trailing the ro-data.
44+
/// Note that we're re-using the obsolete flag above.
45+
HasMetadataUpdateCallback = 0x00040,
46+
4347
/// (Obsolete) ARC-specific: this class has a .release_ivars method.
4448
HasIvarReleaser = 0x00040,
4549

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ NODE(Metatype)
122122
NODE(MetatypeRepresentation)
123123
NODE(Metaclass)
124124
NODE(MethodLookupFunction)
125+
NODE(ObjCMetadataUpdateFunction)
125126
CONTEXT_NODE(ModifyAccessor)
126127
CONTEXT_NODE(Module)
127128
CONTEXT_NODE(NativeOwningAddressor)

include/swift/IRGen/Linking.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ class LinkEntity {
151151
/// A swift metaclass-stub reference. The pointer is a ClassDecl*.
152152
SwiftMetaclassStub,
153153

154+
/// A callback used by newer Objective-C runtimes to initialize class
155+
/// metadata for classes where doesClassMetadataRequireUpdate() is true
156+
/// but doesClassMetadataRequireInitialization() is false.
157+
ObjCMetadataUpdateFunction,
158+
154159
/// A class metadata base offset global variable. This stores the offset
155160
/// of the immediate members of a class (generic parameters, field offsets,
156161
/// vtable offsets) in the class's metadata. The immediate members begin
@@ -565,6 +570,12 @@ class LinkEntity {
565570
return entity;
566571
}
567572

573+
static LinkEntity forObjCMetadataUpdateFunction(ClassDecl *decl) {
574+
LinkEntity entity;
575+
entity.setForDecl(Kind::ObjCMetadataUpdateFunction, decl);
576+
return entity;
577+
}
578+
568579
static LinkEntity forTypeMetadata(CanType concreteType,
569580
TypeMetadataAddress addr) {
570581
LinkEntity entity;

lib/Demangling/Demangler.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,8 @@ NodePointer Demangler::demangleMetatype() {
15401540
return createWithChild(Node::Kind::ProtocolDescriptor, popProtocol());
15411541
case 'u':
15421542
return createWithPoppedType(Node::Kind::MethodLookupFunction);
1543+
case 'U':
1544+
return createWithPoppedType(Node::Kind::ObjCMetadataUpdateFunction);
15431545
case 'B':
15441546
return createWithChild(Node::Kind::ReflectionMetadataBuiltinDescriptor,
15451547
popNode(Node::Kind::Type));

lib/Demangling/NodePrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ class NodePrinter {
404404
case Node::Kind::Number:
405405
case Node::Kind::ObjCAttribute:
406406
case Node::Kind::ObjCBlock:
407+
case Node::Kind::ObjCMetadataUpdateFunction:
407408
case Node::Kind::Owned:
408409
case Node::Kind::OwningAddressor:
409410
case Node::Kind::OwningMutableAddressor:
@@ -939,6 +940,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
939940
Printer << "method lookup function for ";
940941
print(Node->getChild(0));
941942
return nullptr;
943+
case Node::Kind::ObjCMetadataUpdateFunction:
944+
Printer << "ObjC metadata update function for ";
945+
print(Node->getChild(0));
946+
return nullptr;
942947
case Node::Kind::OutlinedBridgedMethod:
943948
Printer << "outlined bridged method (" << Node->getText() << ") of ";
944949
return nullptr;

lib/Demangling/OldRemangler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,10 @@ void Remangler::mangleMethodLookupFunction(Node *node) {
19731973
Out << "<method-lookup-function>";
19741974
}
19751975

1976+
void Remangler::mangleObjCMetadataUpdateFunction(Node *node) {
1977+
Out << "<objc-metadata-update-function>";
1978+
}
1979+
19761980
void Remangler::mangleEmptyList(Node *node) {
19771981
Out << "<empty>";
19781982
}

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,6 +1962,11 @@ void Remangler::mangleMethodLookupFunction(Node *node) {
19621962
Buffer << "Mu";
19631963
}
19641964

1965+
void Remangler::mangleObjCMetadataUpdateFunction(Node *node) {
1966+
mangleSingleChildNode(node);
1967+
Buffer << "MU";
1968+
}
1969+
19651970
void Remangler::mangleThrowsAnnotation(Node *node) {
19661971
Buffer << 'K';
19671972
}

lib/IRGen/GenClass.cpp

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,7 @@ namespace {
12331233
IGM.getObjCRuntimeBaseForSwiftRootClass(getClass()));
12341234
}
12351235

1236-
auto dataPtr = emitROData(ForMetaClass);
1236+
auto dataPtr = emitROData(ForMetaClass, DoesNotHaveUpdateCallback);
12371237
dataPtr = llvm::ConstantExpr::getPtrToInt(dataPtr, IGM.IntPtrTy);
12381238

12391239
llvm::Constant *fields[] = {
@@ -1357,12 +1357,14 @@ namespace {
13571357
return buildGlobalVariable(fields, "_PROTOCOL_");
13581358
}
13591359

1360-
void emitRODataFields(ConstantStructBuilder &b, ForMetaClass_t forMeta) {
1360+
void emitRODataFields(ConstantStructBuilder &b,
1361+
ForMetaClass_t forMeta,
1362+
HasUpdateCallback_t hasUpdater) {
13611363
assert(FieldLayout && "can't emit rodata for a category");
13621364

13631365
// struct _class_ro_t {
13641366
// uint32_t flags;
1365-
b.addInt32(unsigned(buildFlags(forMeta)));
1367+
b.addInt32(unsigned(buildFlags(forMeta, hasUpdater)));
13661368

13671369
// uint32_t instanceStart;
13681370
// uint32_t instanceSize;
@@ -1374,6 +1376,8 @@ namespace {
13741376
Size instanceStart;
13751377
Size instanceSize;
13761378
if (forMeta) {
1379+
assert(!hasUpdater);
1380+
13771381
// sizeof(struct class_t)
13781382
instanceSize = Size(5 * IGM.getPointerSize().getValue());
13791383
// historical nonsense
@@ -1420,24 +1424,36 @@ namespace {
14201424
// const property_list_t *baseProperties;
14211425
b.add(buildPropertyList(forMeta));
14221426

1427+
// If hasUpdater is true, the metadata update callback goes here.
1428+
if (hasUpdater) {
1429+
// Class _Nullable (*metadataUpdateCallback)(Class _Nonnull cls,
1430+
// void * _Nullable arg);
1431+
b.add(IGM.getAddrOfObjCMetadataUpdateFunction(
1432+
TheEntity.get<ClassDecl *>(),
1433+
NotForDefinition));
1434+
}
1435+
14231436
// };
14241437
}
14251438

1426-
llvm::Constant *emitROData(ForMetaClass_t forMeta) {
1439+
llvm::Constant *emitROData(ForMetaClass_t forMeta,
1440+
HasUpdateCallback_t hasUpdater) {
14271441
ConstantInitBuilder builder(IGM);
14281442
auto fields = builder.beginStruct();
1429-
emitRODataFields(fields, forMeta);
1443+
emitRODataFields(fields, forMeta, hasUpdater);
14301444

14311445
auto dataSuffix = forMeta ? "_METACLASS_DATA_" : "_DATA_";
14321446
return buildGlobalVariable(fields, dataSuffix);
14331447
}
14341448

14351449
private:
1436-
ObjCClassFlags buildFlags(ForMetaClass_t forMeta) {
1450+
ObjCClassFlags buildFlags(ForMetaClass_t forMeta,
1451+
HasUpdateCallback_t hasUpdater) {
14371452
ObjCClassFlags flags = ObjCClassFlags::CompiledByARC;
14381453

14391454
// Mark metaclasses as appropriate.
14401455
if (forMeta) {
1456+
assert(!hasUpdater);
14411457
flags |= ObjCClassFlags::Meta;
14421458

14431459
// Non-metaclasses need us to record things whether primitive
@@ -1448,6 +1464,9 @@ namespace {
14481464
flags |= ObjCClassFlags::HasCXXDestructorOnly;
14491465
}
14501466

1467+
if (hasUpdater)
1468+
flags |= ObjCClassFlags::HasMetadataUpdateCallback;
1469+
14511470
// FIXME: set ObjCClassFlags::Hidden when appropriate
14521471
return flags;
14531472
}
@@ -2065,6 +2084,34 @@ namespace {
20652084
};
20662085
} // end anonymous namespace
20672086

2087+
static llvm::Function *emitObjCMetadataUpdateFunction(IRGenModule &IGM,
2088+
ClassDecl *cls) {
2089+
llvm::Function *f =
2090+
IGM.getAddrOfObjCMetadataUpdateFunction(cls, ForDefinition);
2091+
f->setAttributes(IGM.constructInitialAttributes());
2092+
2093+
IRGenFunction IGF(IGM, f);
2094+
if (IGM.DebugInfo)
2095+
IGM.DebugInfo->emitArtificialFunction(IGF, f);
2096+
2097+
// Our parameters are the metadata pointer, and an argument for
2098+
// future use. We just ignore them.
2099+
Explosion params = IGF.collectParameters();
2100+
(void) params.claimAll();
2101+
2102+
// Just directly call our metadata accessor. This should actually
2103+
// return the same metadata; the Objective-C runtime enforces this.
2104+
auto type = cls->getDeclaredType()->getCanonicalType();
2105+
auto *metadata = IGF.emitTypeMetadataRef(type,
2106+
MetadataState::Complete)
2107+
.getMetadata();
2108+
IGF.Builder.CreateRet(
2109+
IGF.Builder.CreateBitCast(metadata,
2110+
IGM.ObjCClassPtrTy));
2111+
2112+
return f;
2113+
}
2114+
20682115
/// Emit the private data (RO-data) associated with a class.
20692116
llvm::Constant *irgen::emitClassPrivateData(IRGenModule &IGM,
20702117
ClassDecl *cls) {
@@ -2081,8 +2128,15 @@ llvm::Constant *irgen::emitClassPrivateData(IRGenModule &IGM,
20812128
// First, build the metaclass object.
20822129
builder.buildMetaclassStub();
20832130

2131+
HasUpdateCallback_t hasUpdater = DoesNotHaveUpdateCallback;
2132+
if (doesClassMetadataRequireUpdate(IGM, cls) &&
2133+
!doesClassMetadataRequireInitialization(IGM, cls)) {
2134+
hasUpdater = HasUpdateCallback;
2135+
emitObjCMetadataUpdateFunction(IGM, cls);
2136+
}
2137+
20842138
// Then build the class RO-data.
2085-
return builder.emitROData(ForClass);
2139+
return builder.emitROData(ForClass, hasUpdater);
20862140
}
20872141

20882142
std::pair<Size, Size>
@@ -2092,6 +2146,9 @@ irgen::emitClassPrivateDataFields(IRGenModule &IGM,
20922146
assert(IGM.ObjCInterop && "emitting RO-data outside of interop mode");
20932147
PrettyStackTraceDecl stackTraceRAII("emitting ObjC metadata for", cls);
20942148

2149+
// This should only be used with generic classes.
2150+
assert(cls->isGenericContext());
2151+
20952152
SILType selfType = getSelfType(cls);
20962153
auto &classTI = IGM.getTypeInfo(selfType).as<ClassTypeInfo>();
20972154

@@ -2105,15 +2162,20 @@ irgen::emitClassPrivateDataFields(IRGenModule &IGM,
21052162
assert(startOfClassRO.isMultipleOf(IGM.getPointerSize()));
21062163
{
21072164
auto classRO = init.beginStruct();
2108-
builder.emitRODataFields(classRO, ForClass);
2165+
2166+
// Note: an update callback is only ever used with the in-place
2167+
// initialization pattern, which precludes generic classes.
2168+
builder.emitRODataFields(classRO,
2169+
ForClass,
2170+
DoesNotHaveUpdateCallback);
21092171
classRO.finishAndAddTo(init);
21102172
}
21112173

21122174
Size startOfMetaclassRO = init.getNextOffsetFromGlobal();
21132175
assert(startOfMetaclassRO.isMultipleOf(IGM.getPointerSize()));
21142176
{
21152177
auto classRO = init.beginStruct();
2116-
builder.emitRODataFields(classRO, ForMetaClass);
2178+
builder.emitRODataFields(classRO, ForMetaClass, DoesNotHaveUpdateCallback);
21172179
classRO.finishAndAddTo(init);
21182180
}
21192181

lib/IRGen/GenClass.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ namespace irgen {
7070
ForMetaClass = true
7171
};
7272

73+
enum HasUpdateCallback_t : bool {
74+
DoesNotHaveUpdateCallback = false,
75+
HasUpdateCallback = true
76+
};
77+
7378
std::pair<Size,Size>
7479
emitClassPrivateDataFields(IRGenModule &IGM,
7580
ConstantStructBuilder &builder,

lib/IRGen/GenDecl.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2725,6 +2725,28 @@ IRGenModule::getAddrOfMetaclassObject(ClassDecl *decl,
27252725
return addr;
27262726
}
27272727

2728+
/// Fetch the declaration of an Objective-C metadata update callback.
2729+
llvm::Function *
2730+
IRGenModule::getAddrOfObjCMetadataUpdateFunction(ClassDecl *classDecl,
2731+
ForDefinition_t forDefinition) {
2732+
IRGen.noteUseOfTypeMetadata(classDecl);
2733+
2734+
LinkEntity entity = LinkEntity::forObjCMetadataUpdateFunction(classDecl);
2735+
llvm::Function *&entry = GlobalFuncs[entity];
2736+
if (entry) {
2737+
if (forDefinition) updateLinkageForDefinition(*this, entry, entity);
2738+
return entry;
2739+
}
2740+
2741+
// Class _Nullable callback(Class _Nonnull cls, void * _Nullable arg);
2742+
llvm::Type *params[] = { ObjCClassPtrTy, Int8PtrTy };
2743+
auto fnType = llvm::FunctionType::get(ObjCClassPtrTy, params, false);
2744+
Signature signature(fnType, llvm::AttributeList(), DefaultCC);
2745+
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
2746+
entry = createFunction(*this, link, signature);
2747+
return entry;
2748+
}
2749+
27282750
/// Fetch the type metadata access function for a non-generic type.
27292751
llvm::Function *
27302752
IRGenModule::getAddrOfTypeMetadataAccessFunction(CanType type,

lib/IRGen/IRGenMangler.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ class IRGenMangler : public Mangle::ASTMangler {
103103
return mangleNominalTypeSymbol(Decl, "Mm");
104104
}
105105

106+
std::string mangleObjCMetadataUpdateFunction(const ClassDecl *Decl) {
107+
return mangleNominalTypeSymbol(Decl, "MU");
108+
}
109+
106110
std::string mangleClassMetadataBaseOffset(const ClassDecl *Decl) {
107111
return mangleNominalTypeSymbol(Decl, "Mo");
108112
}

lib/IRGen/IRGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,9 @@ private: \
13091309
Address getAddrOfObjCClassRef(ClassDecl *D);
13101310
llvm::Constant *getAddrOfMetaclassObject(ClassDecl *D,
13111311
ForDefinition_t forDefinition);
1312+
llvm::Function *getAddrOfObjCMetadataUpdateFunction(ClassDecl *D,
1313+
ForDefinition_t forDefinition);
1314+
13121315
llvm::Function *getAddrOfSILFunction(SILFunction *f,
13131316
ForDefinition_t forDefinition);
13141317
llvm::Function *getAddrOfContinuationPrototype(CanSILFunctionType fnType);

lib/IRGen/Linking.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ std::string LinkEntity::mangleAsString() const {
148148
case Kind::SwiftMetaclassStub:
149149
return mangler.mangleClassMetaClass(cast<ClassDecl>(getDecl()));
150150

151+
case Kind::ObjCMetadataUpdateFunction:
152+
return mangler.mangleObjCMetadataUpdateFunction(cast<ClassDecl>(getDecl()));
153+
151154
case Kind::ClassMetadataBaseOffset: // class metadata base offset
152155
return mangler.mangleClassMetadataBaseOffset(cast<ClassDecl>(getDecl()));
153156

@@ -351,6 +354,7 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
351354
return SILLinkage::Private;
352355
}
353356

357+
case Kind::ObjCMetadataUpdateFunction:
354358
case Kind::TypeMetadataInstantiationCache:
355359
case Kind::TypeMetadataInstantiationFunction:
356360
case Kind::TypeMetadataSingletonInitializationCache:
@@ -615,6 +619,7 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
615619
case Kind::DefaultAssociatedConformanceAccessor:
616620
return false;
617621

622+
case Kind::ObjCMetadataUpdateFunction:
618623
case Kind::ValueWitness:
619624
case Kind::TypeMetadataAccessFunction:
620625
case Kind::TypeMetadataLazyCacheVariable:
@@ -785,6 +790,7 @@ const SourceFile *LinkEntity::getSourceFileForEmission() const {
785790
case Kind::ObjCClass:
786791
case Kind::ObjCMetaclass:
787792
case Kind::SwiftMetaclassStub:
793+
case Kind::ObjCMetadataUpdateFunction:
788794
case Kind::ClassMetadataBaseOffset:
789795
case Kind::PropertyDescriptor:
790796
case Kind::NominalTypeDescriptor:

0 commit comments

Comments
 (0)