Skip to content

Commit dc052e6

Browse files
committed
Resolve metadata cycles through non-generic value types with resilient layout.
The central thrust of this patch is to get these metadata initializations off of `swift_once` and onto the metadata-request system where we can properly detect and resolve dependencies. We do this by first introducing runtime support for resolving metadata requests for "in-place" initializations (committed previously) and then teaching IRGen to actually generate code to use them (this patch). A non-trivial amount of this patch is just renaming and refactoring some of existing infrastructure that was being used for in-place initializations to try to avoid unnecessary confusion. The remaining cases that are still using `swift_once` resolution of metadata initialization are: - non-generic classes that can't statically fill their superclass or have resilient internal layout - foreign type metadata Classes require more work because I'd like to switch at least the resilient-superclass case over to using a pattern much more like what we do with generic class instantiation. That is, I'd like in-place initialization to be reserved for classes that actually don't need relocation. Foreign metadata should also be updated to the request/dependency scheme before we declare ABI stability. I'm not sure why foreign metadata would ever require a type to be resolved, but let's assume it's possible. Fixes part of SR-7876.
1 parent dadb51e commit dc052e6

18 files changed

+551
-194
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Globals
5656
global ::= nominal-type 'Mr' // generic type completion function
5757
global ::= nominal-type 'Mi' // generic type instantiation function
5858
global ::= nominal-type 'MI' // generic type instantiation cache
59+
global ::= nominal-type 'Ml' // in-place type initialization cache
5960
global ::= nominal-type 'Mm' // class metaclass
6061
global ::= nominal-type 'Mn' // nominal type descriptor
6162
global ::= module 'MXM' // module descriptor

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ NODE(TypeMetadataAccessFunction)
183183
NODE(TypeMetadataCompletionFunction)
184184
NODE(TypeMetadataInstantiationCache)
185185
NODE(TypeMetadataInstantiationFunction)
186+
NODE(TypeMetadataInPlaceInitializationCache)
186187
NODE(TypeMetadataLazyCache)
187188
NODE(UncurriedFunctionType)
188189
#define REF_STORAGE(Name, ...) NODE(Name)

include/swift/IRGen/Linking.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ class LinkEntity {
163163
/// The pointer is a NominalTypeDecl*.
164164
TypeMetadataInstantiationFunction,
165165

166+
/// The in-place initialization cache for a generic nominal type.
167+
/// The pointer is a NominalTypeDecl*.
168+
TypeMetadataInPlaceInitializationCache,
169+
166170
/// The completion function for a generic or resilient nominal type.
167171
/// The pointer is a NominalTypeDecl*.
168172
TypeMetadataCompletionFunction,
@@ -503,12 +507,19 @@ class LinkEntity {
503507
return entity;
504508
}
505509

506-
static LinkEntity forTypeMetadataInstantiationFunction(NominalTypeDecl *decl){
510+
static LinkEntity forTypeMetadataInstantiationFunction(NominalTypeDecl *decl) {
507511
LinkEntity entity;
508512
entity.setForDecl(Kind::TypeMetadataInstantiationFunction, decl);
509513
return entity;
510514
}
511515

516+
static LinkEntity forTypeMetadataInPlaceInitializationCache(
517+
NominalTypeDecl *decl) {
518+
LinkEntity entity;
519+
entity.setForDecl(Kind::TypeMetadataInPlaceInitializationCache, decl);
520+
return entity;
521+
}
522+
512523
static LinkEntity forTypeMetadataCompletionFunction(NominalTypeDecl *decl) {
513524
LinkEntity entity;
514525
entity.setForDecl(Kind::TypeMetadataCompletionFunction, decl);

lib/Demangling/Demangler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,9 @@ NodePointer Demangler::demangleMetatype() {
14691469
return createWithPoppedType(Node::Kind::TypeMetadataInstantiationFunction);
14701470
case 'r':
14711471
return createWithPoppedType(Node::Kind::TypeMetadataCompletionFunction);
1472+
case 'l':
1473+
return createWithPoppedType(
1474+
Node::Kind::TypeMetadataInPlaceInitializationCache);
14721475
case 'L':
14731476
return createWithPoppedType(Node::Kind::TypeMetadataLazyCache);
14741477
case 'm':

lib/Demangling/NodePrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ class NodePrinter {
429429
case Node::Kind::TypeMetadataCompletionFunction:
430430
case Node::Kind::TypeMetadataInstantiationCache:
431431
case Node::Kind::TypeMetadataInstantiationFunction:
432+
case Node::Kind::TypeMetadataInPlaceInitializationCache:
432433
case Node::Kind::TypeMetadataLazyCache:
433434
case Node::Kind::UncurriedFunctionType:
434435
#define REF_STORAGE(Name, ...) \
@@ -1509,6 +1510,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
15091510
Printer << "type metadata instantiation function for ";
15101511
print(Node->getChild(0));
15111512
return nullptr;
1513+
case Node::Kind::TypeMetadataInPlaceInitializationCache:
1514+
Printer << "type metadata in-place initialization cache for ";
1515+
print(Node->getChild(0));
1516+
return nullptr;
15121517
case Node::Kind::TypeMetadataCompletionFunction:
15131518
Printer << "type metadata completion function for ";
15141519
print(Node->getChild(0));

lib/Demangling/OldRemangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,11 @@ void Remangler::mangleTypeMetadataInstantiationFunction(Node *node) {
716716
mangleSingleChildNode(node); // type
717717
}
718718

719+
void Remangler::mangleTypeMetadataInPlaceInitializationCache(Node *node) {
720+
Out << "Ml";
721+
mangleSingleChildNode(node); // type
722+
}
723+
719724
void Remangler::mangleTypeMetadataCompletionFunction(Node *node) {
720725
Out << "Mr";
721726
mangleSingleChildNode(node); // type

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1766,6 +1766,11 @@ void Remangler::mangleTypeMetadataInstantiationFunction(Node *node) {
17661766
Buffer << "Mi";
17671767
}
17681768

1769+
void Remangler::mangleTypeMetadataInPlaceInitializationCache(Node *node) {
1770+
mangleSingleChildNode(node);
1771+
Buffer << "Ml";
1772+
}
1773+
17691774
void Remangler::mangleTypeMetadataCompletionFunction(Node *node) {
17701775
mangleSingleChildNode(node);
17711776
Buffer << "Mr";

lib/IRGen/GenDecl.cpp

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,7 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
14981498

14991499
case Kind::TypeMetadataInstantiationCache:
15001500
case Kind::TypeMetadataInstantiationFunction:
1501+
case Kind::TypeMetadataInPlaceInitializationCache:
15011502
case Kind::TypeMetadataCompletionFunction:
15021503
case Kind::TypeMetadataPattern:
15031504
return SILLinkage::Private;
@@ -1715,6 +1716,7 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
17151716
case Kind::AnonymousDescriptor:
17161717
case Kind::TypeMetadataInstantiationCache:
17171718
case Kind::TypeMetadataInstantiationFunction:
1719+
case Kind::TypeMetadataInPlaceInitializationCache:
17181720
case Kind::TypeMetadataCompletionFunction:
17191721
case Kind::TypeMetadataPattern:
17201722
return false;
@@ -2500,8 +2502,6 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment,
25002502
// forward declaration.
25012503
if (definitionType) {
25022504
assert(existing->isDeclaration() && "already defined");
2503-
assert(entry->getType()->getPointerElementType() == defaultType
2504-
|| entry->getType()->getPointerElementType() == definition.getType());
25052505
updateLinkageForDefinition(*this, existing, entity);
25062506

25072507
// If the existing entry is a variable of the right type,
@@ -2548,7 +2548,7 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment,
25482548
// new variable.
25492549
if (entry) {
25502550
auto existing = cast<llvm::GlobalValue>(entry);
2551-
auto castVar = getElementBitCast(var, defaultType);
2551+
auto castVar = llvm::ConstantExpr::getBitCast(var, entry->getType());
25522552
existing->replaceAllUsesWith(castVar);
25532553
existing->eraseFromParent();
25542554
}
@@ -3271,8 +3271,45 @@ IRGenModule::getAddrOfTypeMetadataLazyCacheVariable(CanType type,
32713271
ForDefinition_t forDefinition) {
32723272
assert(!type->hasArchetype() && !type->hasTypeParameter());
32733273
LinkEntity entity = LinkEntity::forTypeMetadataLazyCacheVariable(type);
3274-
return getAddrOfLLVMVariable(entity, getPointerAlignment(), forDefinition,
3275-
TypeMetadataPtrTy, DebugTypeInfo());
3274+
auto variable =
3275+
getAddrOfLLVMVariable(entity, getPointerAlignment(), forDefinition,
3276+
TypeMetadataPtrTy, DebugTypeInfo());
3277+
3278+
// Zero-initialize if we're asking for a definition.
3279+
if (forDefinition) {
3280+
cast<llvm::GlobalVariable>(variable)->setInitializer(
3281+
llvm::ConstantPointerNull::get(TypeMetadataPtrTy));
3282+
}
3283+
3284+
return variable;
3285+
}
3286+
3287+
llvm::Constant *
3288+
IRGenModule::getAddrOfTypeMetadataInPlaceInitializationCache(
3289+
NominalTypeDecl *D,
3290+
ForDefinition_t forDefinition) {
3291+
// Build the cache type.
3292+
llvm::Type *cacheTy;
3293+
if (isa<StructDecl>(D) || isa<EnumDecl>(D)) {
3294+
// This is struct InPlaceValueMetadataCache.
3295+
cacheTy = llvm::StructType::get(getLLVMContext(),
3296+
{TypeMetadataPtrTy, Int8PtrTy});
3297+
} else {
3298+
llvm_unreachable("in-place initialization for classes not yet supported");
3299+
}
3300+
3301+
LinkEntity entity = LinkEntity::forTypeMetadataInPlaceInitializationCache(D);
3302+
auto variable =
3303+
getAddrOfLLVMVariable(entity, getPointerAlignment(), forDefinition,
3304+
cacheTy, DebugTypeInfo());
3305+
3306+
// Zero-initialize if we're asking for a definition.
3307+
if (forDefinition) {
3308+
cast<llvm::GlobalVariable>(variable)->setInitializer(
3309+
llvm::Constant::getNullValue(cacheTy));
3310+
}
3311+
3312+
return variable;
32763313
}
32773314

32783315
/// Define the metadata for a type.
@@ -4274,9 +4311,17 @@ IRGenModule::getAddrOfWitnessTableLazyCacheVariable(
42744311
assert(!conformingType->hasArchetype());
42754312
LinkEntity entity =
42764313
LinkEntity::forProtocolWitnessTableLazyCacheVariable(conf, conformingType);
4277-
return getAddrOfLLVMVariable(entity, getPointerAlignment(),
4278-
forDefinition, WitnessTablePtrTy,
4279-
DebugTypeInfo());
4314+
auto variable = getAddrOfLLVMVariable(entity, getPointerAlignment(),
4315+
forDefinition, WitnessTablePtrTy,
4316+
DebugTypeInfo());
4317+
4318+
// Zero-initialize if we're asking for a definition.
4319+
if (forDefinition) {
4320+
cast<llvm::GlobalVariable>(variable)->setInitializer(
4321+
llvm::ConstantPointerNull::get(WitnessTablePtrTy));
4322+
}
4323+
4324+
return variable;
42804325
}
42814326

42824327
/// Look up the address of a witness table.

0 commit comments

Comments
 (0)