Skip to content

Commit f0e5e19

Browse files
committed
IRGen: Access concrete type metadata by mangled name.
When we generate code that asks for complete metadata for a fully concrete specific type that doesn't have trivial metadata access, like `(Int, String)` or `[String: [Any]]`, generate a cache variable that points to a mangled name, and use a common accessor function that turns that cache variable into a pointer to the instantiated metadata. This saves a bunch of code size, and should have minimal runtime impact, since the demangling of any string only has to happen once. This mostly just works, though it exposed a couple of issues: - Mangling a type ref including objc protocols didn't cause the objc protocol record to get instantiated. Fixed as part of this patch. - The runtime type demangler doesn't correctly handle retroactive conformances. If there are multiple retroactive conformances in a process at runtime, then even though the mangled string refers to a specific conformance, the runtime still just picks one without listening to the mangler. This is left to fix later, rdar://problem/53828345. There is some more follow-up work that we can do to further improve the gains: - We could improve the runtime-provided entry points, adding versions that don't require size to be cached, and which can handle arbitrary metadata requests. This would allow for mangled names to also be used for incomplete metadata accesses and improve code size of some generic type accessors. However, we'd only be able to take advantage of the new entry points in OSes that ship a new runtime. - We could choose to always symbolic reference all type references, which would generally reduce the size of mangled strings, as well as make runtime demangling more efficient, since it wouldn't need to hit the runtime caches. This would however require that we be able to handle symbolic references across files in the MetadataReader in order to avoid regressing remote mirror functionality.
1 parent 21bac19 commit f0e5e19

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+643
-534
lines changed

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ NODE(TypeMetadataCompletionFunction)
211211
NODE(TypeMetadataInstantiationCache)
212212
NODE(TypeMetadataInstantiationFunction)
213213
NODE(TypeMetadataSingletonInitializationCache)
214+
NODE(TypeMetadataDemanglingCache)
214215
NODE(TypeMetadataLazyCache)
215216
NODE(UncurriedFunctionType)
216217
NODE(UnknownIndex)

include/swift/IRGen/Linking.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,10 @@ class LinkEntity {
368368
/// The pointer is a canonical TypeBase*.
369369
TypeMetadataLazyCacheVariable,
370370

371+
/// A lazy cache variable for fetching type metadata from a mangled name.
372+
/// The pointer is a canonical TypeBase*.
373+
TypeMetadataDemanglingCacheVariable,
374+
371375
/// A reflection metadata descriptor for a builtin or imported type.
372376
ReflectionBuiltinDescriptor,
373377

@@ -705,6 +709,12 @@ class LinkEntity {
705709
return entity;
706710
}
707711

712+
static LinkEntity forTypeMetadataDemanglingCacheVariable(CanType type) {
713+
LinkEntity entity;
714+
entity.setForType(Kind::TypeMetadataDemanglingCacheVariable, type);
715+
return entity;
716+
}
717+
708718
static LinkEntity forClassMetadataBaseOffset(ClassDecl *decl) {
709719
LinkEntity entity;
710720
entity.setForDecl(Kind::ClassMetadataBaseOffset, decl);

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1190,7 +1190,7 @@ FUNCTION(IsOptionalType,
11901190
FUNCTION(Once, swift_once, C_CC, AlwaysAvailable,
11911191
RETURNS(VoidTy),
11921192
ARGS(OnceTy->getPointerTo(), Int8PtrTy, Int8PtrTy),
1193-
ATTRS())
1193+
ATTRS(NoUnwind))
11941194

11951195
// void swift_registerProtocols(const ProtocolRecord *begin,
11961196
// const ProtocolRecord *end)
@@ -1398,6 +1398,17 @@ FUNCTION(IntToFloat64, swift_intToFloat64, SwiftCC, AlwaysAvailable,
13981398
ARGS(SizeTy->getPointerTo(), SizeTy),
13991399
ATTRS(NoUnwind, ReadOnly))
14001400

1401+
// const Metadata *swift_getTypeByMangledNameInContext(
1402+
// const char *typeNameStart,
1403+
// size_t typeNameLength,
1404+
// const TargetContextDescriptor<InProcess> *context,
1405+
// const void * const *genericArgs)
1406+
FUNCTION(GetTypeByMangledNameInContext, swift_getTypeByMangledNameInContext,
1407+
SwiftCC, AlwaysAvailable,
1408+
RETURNS(TypeMetadataPtrTy),
1409+
ARGS(Int8PtrTy, SizeTy, TypeContextDescriptorPtrTy, Int8PtrPtrTy),
1410+
ATTRS(NoUnwind, ArgMemOnly))
1411+
14011412
#undef RETURNS
14021413
#undef ARGS
14031414
#undef ATTRS

lib/Demangling/Demangler.cpp

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,36 +1788,50 @@ NodePointer Demangler::demangleImplFunctionType() {
17881788

17891789
NodePointer Demangler::demangleMetatype() {
17901790
switch (nextChar()) {
1791+
case 'a':
1792+
return createWithPoppedType(Node::Kind::TypeMetadataAccessFunction);
1793+
case 'A':
1794+
return createWithChild(Node::Kind::ReflectionMetadataAssocTypeDescriptor,
1795+
popProtocolConformance());
1796+
case 'B':
1797+
return createWithChild(Node::Kind::ReflectionMetadataBuiltinDescriptor,
1798+
popNode(Node::Kind::Type));
17911799
case 'c':
17921800
return createWithChild(Node::Kind::ProtocolConformanceDescriptor,
17931801
popProtocolConformance());
1802+
case 'C': {
1803+
NodePointer Ty = popNode(Node::Kind::Type);
1804+
if (!Ty || !isAnyGeneric(Ty->getChild(0)->getKind()))
1805+
return nullptr;
1806+
return createWithChild(Node::Kind::ReflectionMetadataSuperclassDescriptor,
1807+
Ty->getChild(0));
1808+
}
1809+
case 'D':
1810+
return createWithPoppedType(Node::Kind::TypeMetadataDemanglingCache);
17941811
case 'f':
17951812
return createWithPoppedType(Node::Kind::FullTypeMetadata);
1796-
case 'P':
1797-
return createWithPoppedType(Node::Kind::GenericTypeMetadataPattern);
1798-
case 'a':
1799-
return createWithPoppedType(Node::Kind::TypeMetadataAccessFunction);
1813+
case 'F':
1814+
return createWithChild(Node::Kind::ReflectionMetadataFieldDescriptor,
1815+
popNode(Node::Kind::Type));
18001816
case 'g':
18011817
return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessor,
18021818
popNode());
18031819
case 'h':
18041820
return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessorImpl,
18051821
popNode());
1822+
case 'i':
1823+
return createWithPoppedType(Node::Kind::TypeMetadataInstantiationFunction);
1824+
case 'I':
1825+
return createWithPoppedType(Node::Kind::TypeMetadataInstantiationCache);
18061826
case 'j':
18071827
return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessorKey,
18081828
popNode());
18091829
case 'k':
18101830
return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessorVar,
18111831
popNode());
1812-
case 'I':
1813-
return createWithPoppedType(Node::Kind::TypeMetadataInstantiationCache);
1814-
case 'i':
1815-
return createWithPoppedType(Node::Kind::TypeMetadataInstantiationFunction);
1816-
case 'r':
1817-
return createWithPoppedType(Node::Kind::TypeMetadataCompletionFunction);
18181832
case 'l':
18191833
return createWithPoppedType(
1820-
Node::Kind::TypeMetadataSingletonInitializationCache);
1834+
Node::Kind::TypeMetadataSingletonInitializationCache);
18211835
case 'L':
18221836
return createWithPoppedType(Node::Kind::TypeMetadataLazyCache);
18231837
case 'm':
@@ -1828,35 +1842,23 @@ NodePointer Demangler::demangleMetatype() {
18281842
return createWithPoppedType(Node::Kind::ClassMetadataBaseOffset);
18291843
case 'p':
18301844
return createWithChild(Node::Kind::ProtocolDescriptor, popProtocol());
1845+
case 'P':
1846+
return createWithPoppedType(Node::Kind::GenericTypeMetadataPattern);
18311847
case 'Q':
18321848
return createWithChild(Node::Kind::OpaqueTypeDescriptor, popNode());
1849+
case 'r':
1850+
return createWithPoppedType(Node::Kind::TypeMetadataCompletionFunction);
1851+
case 's':
1852+
return createWithPoppedType(Node::Kind::ObjCResilientClassStub);
18331853
case 'S':
18341854
return createWithChild(Node::Kind::ProtocolSelfConformanceDescriptor,
18351855
popProtocol());
1856+
case 't':
1857+
return createWithPoppedType(Node::Kind::FullObjCResilientClassStub);
18361858
case 'u':
18371859
return createWithPoppedType(Node::Kind::MethodLookupFunction);
18381860
case 'U':
18391861
return createWithPoppedType(Node::Kind::ObjCMetadataUpdateFunction);
1840-
case 's':
1841-
return createWithPoppedType(Node::Kind::ObjCResilientClassStub);
1842-
case 't':
1843-
return createWithPoppedType(Node::Kind::FullObjCResilientClassStub);
1844-
case 'B':
1845-
return createWithChild(Node::Kind::ReflectionMetadataBuiltinDescriptor,
1846-
popNode(Node::Kind::Type));
1847-
case 'F':
1848-
return createWithChild(Node::Kind::ReflectionMetadataFieldDescriptor,
1849-
popNode(Node::Kind::Type));
1850-
case 'A':
1851-
return createWithChild(Node::Kind::ReflectionMetadataAssocTypeDescriptor,
1852-
popProtocolConformance());
1853-
case 'C': {
1854-
NodePointer Ty = popNode(Node::Kind::Type);
1855-
if (!Ty || !isAnyGeneric(Ty->getChild(0)->getKind()))
1856-
return nullptr;
1857-
return createWithChild(Node::Kind::ReflectionMetadataSuperclassDescriptor,
1858-
Ty->getChild(0));
1859-
}
18601862
case 'V':
18611863
return createWithChild(Node::Kind::PropertyDescriptor,
18621864
popNode(isEntity));

lib/Demangling/NodePrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ class NodePrinter {
472472
case Node::Kind::TypeMetadataInstantiationCache:
473473
case Node::Kind::TypeMetadataInstantiationFunction:
474474
case Node::Kind::TypeMetadataSingletonInitializationCache:
475+
case Node::Kind::TypeMetadataDemanglingCache:
475476
case Node::Kind::TypeMetadataLazyCache:
476477
case Node::Kind::UncurriedFunctionType:
477478
#define REF_STORAGE(Name, ...) \
@@ -1679,6 +1680,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
16791680
Printer << "type metadata completion function for ";
16801681
print(Node->getChild(0));
16811682
return nullptr;
1683+
case Node::Kind::TypeMetadataDemanglingCache:
1684+
Printer << "demangling cache variable for type metadata for ";
1685+
print(Node->getChild(0));
1686+
return nullptr;
16821687
case Node::Kind::TypeMetadataLazyCache:
16831688
Printer << "lazy cache variable for type metadata for ";
16841689
print(Node->getChild(0));

lib/Demangling/OldRemangler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,10 @@ void Remangler::mangleTypeMetadataCompletionFunction(Node *node) {
513513
mangleSingleChildNode(node); // type
514514
}
515515

516+
void Remangler::mangleTypeMetadataDemanglingCache(Node *node) {
517+
unreachable("not supported");
518+
}
519+
516520
void Remangler::mangleTypeMetadataLazyCache(Node *node) {
517521
Buffer << "ML";
518522
mangleSingleChildNode(node); // type

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,11 @@ void Remangler::mangleTypeMetadataCompletionFunction(Node *node) {
20652065
Buffer << "Mr";
20662066
}
20672067

2068+
void Remangler::mangleTypeMetadataDemanglingCache(Node *node) {
2069+
mangleChildNodes(node);
2070+
Buffer << "MD";
2071+
}
2072+
20682073
void Remangler::mangleTypeMetadataLazyCache(Node *node) {
20692074
mangleChildNodes(node);
20702075
Buffer << "ML";

lib/IRGen/GenBuiltin.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,18 +799,24 @@ if (Builtin.ID == BuiltinValueKind::id) { \
799799

800800
// If we know the platform runtime's "done" value, emit the check inline.
801801
llvm::BasicBlock *doneBB = nullptr;
802+
803+
llvm::BasicBlock *beforeBB = IGF.Builder.GetInsertBlock();
802804

803805
if (auto ExpectedPred = IGF.IGM.TargetInfo.OnceDonePredicateValue) {
804806
auto PredValue = IGF.Builder.CreateLoad(PredPtr,
805807
IGF.IGM.getPointerAlignment());
806808
auto ExpectedPredValue = llvm::ConstantInt::getSigned(IGF.IGM.OnceTy,
807809
*ExpectedPred);
808810
auto PredIsDone = IGF.Builder.CreateICmpEQ(PredValue, ExpectedPredValue);
811+
PredIsDone = IGF.Builder.CreateExpect(PredIsDone,
812+
llvm::ConstantInt::get(IGF.IGM.Int1Ty, 1));
809813

810814
auto notDoneBB = IGF.createBasicBlock("once_not_done");
811815
doneBB = IGF.createBasicBlock("once_done");
812816

813817
IGF.Builder.CreateCondBr(PredIsDone, doneBB, notDoneBB);
818+
819+
IGF.Builder.SetInsertPoint(&IGF.CurFn->back());
814820
IGF.Builder.emitBlock(notDoneBB);
815821
}
816822

@@ -822,6 +828,7 @@ if (Builtin.ID == BuiltinValueKind::id) { \
822828
// If we emitted the "done" check inline, join the branches.
823829
if (auto ExpectedPred = IGF.IGM.TargetInfo.OnceDonePredicateValue) {
824830
IGF.Builder.CreateBr(doneBB);
831+
IGF.Builder.SetInsertPoint(beforeBB);
825832
IGF.Builder.emitBlock(doneBB);
826833
// We can assume the once predicate is in the "done" state now.
827834
auto PredValue = IGF.Builder.CreateLoad(PredPtr,

lib/IRGen/GenCall.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,8 +1538,6 @@ void CallEmission::emitToUnmappedExplosion(Explosion &out) {
15381538
// for methods that have covariant ABI-compatible overrides.
15391539
auto expectedNativeResultType = nativeSchema.getExpandedType(IGF.IGM);
15401540
if (result->getType() != expectedNativeResultType) {
1541-
assert(origFnType->getLanguage() == SILFunctionLanguage::C ||
1542-
origFnType->getRepresentation() == SILFunctionTypeRepresentation::Method);
15431541
result =
15441542
IGF.coerceValue(result, expectedNativeResultType, IGF.IGM.DataLayout);
15451543
}

lib/IRGen/GenDecl.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,14 @@ void IRGenerator::noteUseOfTypeGlobals(NominalTypeDecl *type,
12481248
RequireMetadata_t requireMetadata) {
12491249
if (!type)
12501250
return;
1251+
1252+
// Force emission of ObjC protocol descriptors used by type refs.
1253+
if (auto proto = dyn_cast<ProtocolDecl>(type)) {
1254+
if (proto->isObjC()) {
1255+
PrimaryIGM->getAddrOfObjCProtocolRecord(proto, NotForDefinition);
1256+
return;
1257+
}
1258+
}
12511259

12521260
if (!hasLazyMetadata(type))
12531261
return;
@@ -3411,22 +3419,29 @@ IRGenModule::getAddrOfGenericTypeMetadataAccessFunction(
34113419
/// Get or create a type metadata cache variable. These are an
34123420
/// implementation detail of type metadata access functions.
34133421
llvm::Constant *
3414-
IRGenModule::getAddrOfTypeMetadataLazyCacheVariable(CanType type,
3415-
ForDefinition_t forDefinition) {
3422+
IRGenModule::getAddrOfTypeMetadataLazyCacheVariable(CanType type) {
34163423
assert(!type->hasArchetype() && !type->hasTypeParameter());
34173424
LinkEntity entity = LinkEntity::forTypeMetadataLazyCacheVariable(type);
34183425
auto variable =
3419-
getAddrOfLLVMVariable(entity, forDefinition, DebugTypeInfo());
3426+
getAddrOfLLVMVariable(entity, ForDefinition, DebugTypeInfo());
34203427

34213428
// Zero-initialize if we're asking for a definition.
3422-
if (forDefinition) {
3423-
cast<llvm::GlobalVariable>(variable)->setInitializer(
3424-
llvm::ConstantPointerNull::get(TypeMetadataPtrTy));
3425-
}
3429+
cast<llvm::GlobalVariable>(variable)->setInitializer(
3430+
llvm::ConstantPointerNull::get(TypeMetadataPtrTy));
34263431

34273432
return variable;
34283433
}
34293434

3435+
/// Get or create a type metadata cache variable. These are an
3436+
/// implementation detail of type metadata access functions.
3437+
llvm::Constant *
3438+
IRGenModule::getAddrOfTypeMetadataDemanglingCacheVariable(CanType type,
3439+
ConstantInit definition) {
3440+
assert(!type->hasArchetype() && !type->hasTypeParameter());
3441+
LinkEntity entity = LinkEntity::forTypeMetadataDemanglingCacheVariable(type);
3442+
return getAddrOfLLVMVariable(entity, definition, DebugTypeInfo());
3443+
}
3444+
34303445
llvm::Constant *
34313446
IRGenModule::getAddrOfTypeMetadataSingletonInitializationCache(
34323447
NominalTypeDecl *D,

lib/IRGen/GenKeyPath.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ getInitializerForComputedComponent(IRGenModule &IGM,
651651
static llvm::Constant *
652652
emitMetadataTypeRefForKeyPath(IRGenModule &IGM, CanType type) {
653653
// Produce a mangled name for the type.
654-
auto constant = IGM.getTypeRef(type, MangledTypeRefRole::Metadata);
654+
auto constant = IGM.getTypeRef(type, MangledTypeRefRole::Metadata).first;
655655

656656
// Mask the bottom bit to tell the key path runtime this is a mangled name
657657
// rather than a direct reference.

lib/IRGen/GenMeta.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ namespace {
470470
void addExtendedContext() {
471471
auto string = IGM.getTypeRef(E->getSelfInterfaceType(),
472472
E->getGenericSignature(),
473-
MangledTypeRefRole::Metadata);
473+
MangledTypeRefRole::Metadata).first;
474474
B.addRelativeAddress(string);
475475
}
476476

@@ -1594,7 +1594,8 @@ namespace {
15941594
GenericSignature *genericSig = getType()->getGenericSignature();
15951595
B.addRelativeAddress(IGM.getTypeRef(superclassType->getCanonicalType(),
15961596
genericSig,
1597-
MangledTypeRefRole::Metadata));
1597+
MangledTypeRefRole::Metadata)
1598+
.first);
15981599
} else {
15991600
B.addInt32(0);
16001601
}
@@ -1685,7 +1686,7 @@ namespace {
16851686
->getCanonicalType(O->getOpaqueInterfaceGenericSignature());
16861687

16871688
B.addRelativeAddress(IGM.getTypeRef(underlyingType,
1688-
MangledTypeRefRole::Metadata));
1689+
MangledTypeRefRole::Metadata).first);
16891690

16901691
auto opaqueType = O->getDeclaredInterfaceType()
16911692
->castTo<OpaqueTypeArchetypeType>();
@@ -4266,7 +4267,7 @@ static void addGenericRequirement(IRGenModule &IGM, ConstantStructBuilder &B,
42664267

42674268
B.addInt(IGM.Int32Ty, flags.getIntValue());
42684269
auto typeName =
4269-
IGM.getTypeRef(paramType, nullptr, MangledTypeRefRole::Metadata);
4270+
IGM.getTypeRef(paramType, nullptr, MangledTypeRefRole::Metadata).first;
42704271
B.addRelativeAddress(typeName);
42714272
addReference();
42724273
}
@@ -4334,7 +4335,7 @@ GenericRequirementsMetadata irgen::addGenericRequirements(
43344335
auto flags = GenericRequirementFlags(abiKind, false, false);
43354336
auto typeName =
43364337
IGM.getTypeRef(requirement.getSecondType(), nullptr,
4337-
MangledTypeRefRole::Metadata);
4338+
MangledTypeRefRole::Metadata).first;
43384339

43394340
addGenericRequirement(IGM, B, metadata, sig, flags,
43404341
requirement.getFirstType(),

lib/IRGen/GenProto.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1432,7 +1432,7 @@ llvm::Constant *IRGenModule::getAssociatedTypeWitness(Type type,
14321432
auto role = inProtocolContext
14331433
? MangledTypeRefRole::DefaultAssociatedTypeWitness
14341434
: MangledTypeRefRole::Metadata;
1435-
auto typeRef = getTypeRef(type, /*generic signature*/nullptr, role);
1435+
auto typeRef = getTypeRef(type, /*generic signature*/nullptr, role).first;
14361436

14371437
// Set the low bit to indicate that this is a mangled name.
14381438
auto witness = llvm::ConstantExpr::getPtrToInt(typeRef, IntPtrTy);

0 commit comments

Comments
 (0)