Skip to content

[metadata prespecialization] Cross-module: structs and enums. #32354

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ Globals

global ::= global 'MK' // instantiation cache associated with global

global ::= global 'MJ' // noncanonical specialized generic type metadata instantiation cache associated with global
global ::= global 'MN' // noncanonical specialized generic type metadata for global

A direct symbol resolves directly to the address of an object. An
indirect symbol resolves to the address of a pointer to the object.
They are distinct manglings to make a certain class of bugs
Expand Down
6 changes: 3 additions & 3 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,12 @@ NODE(OpaqueTypeDescriptorAccessorVar)
NODE(OpaqueReturnType)
CONTEXT_NODE(OpaqueReturnTypeOf)

// Added in Swift 5.3
// Added in Swift 5.4
NODE(CanonicalSpecializedGenericMetaclass)
NODE(CanonicalSpecializedGenericTypeMetadataAccessFunction)

// Added in Swift 5.4
NODE(MetadataInstantiationCache)
NODE(NoncanonicalSpecializedGenericTypeMetadata)
NODE(NoncanonicalSpecializedGenericTypeMetadataCache)

#undef CONTEXT_NODE
#undef NODE
29 changes: 29 additions & 0 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,16 @@ class LinkEntity {
/// An access function for prespecialized type metadata.
/// The pointer is a canonical TypeBase*.
CanonicalSpecializedGenericTypeMetadataAccessFunction,

/// Metadata for a specialized generic type which cannot be statically
/// guaranteed to be canonical and so must be canonicalized.
/// The pointer is a canonical TypeBase*.
NoncanonicalSpecializedGenericTypeMetadata,

/// A cache variable for noncanonical specialized type metadata, to be
/// passed to swift_getCanonicalSpecializedMetadata.
/// The pointer is a canonical TypeBase*.
NoncanonicalSpecializedGenericTypeMetadataCacheVariable,
};
friend struct llvm::DenseMapInfo<LinkEntity>;

Expand Down Expand Up @@ -1045,6 +1055,24 @@ class LinkEntity {
return entity;
}

static LinkEntity
forNoncanonicalSpecializedGenericTypeMetadata(CanType theType) {
LinkEntity entity;
entity.setForType(Kind::NoncanonicalSpecializedGenericTypeMetadata,
theType);
entity.Data |= LINKENTITY_SET_FIELD(
MetadataAddress, unsigned(TypeMetadataAddress::FullMetadata));
return entity;
}


static LinkEntity
forNoncanonicalSpecializedGenericTypeMetadataCacheVariable(CanType theType) {
LinkEntity entity;
entity.setForType(Kind::NoncanonicalSpecializedGenericTypeMetadataCacheVariable, theType);
return entity;
}

void mangle(llvm::raw_ostream &out) const;
void mangle(SmallVectorImpl<char> &buffer) const;
std::string mangleAsString() const;
Expand Down Expand Up @@ -1152,6 +1180,7 @@ class LinkEntity {
}
TypeMetadataAddress getMetadataAddress() const {
assert(getKind() == Kind::TypeMetadata ||
getKind() == Kind::NoncanonicalSpecializedGenericTypeMetadata ||
getKind() == Kind::ObjCResilientClassStub);
return (TypeMetadataAddress)LINKENTITY_GET_FIELD(Data, MetadataAddress);
}
Expand Down
11 changes: 8 additions & 3 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1911,12 +1911,14 @@ NodePointer Demangler::demangleMetatype() {
case 'j':
return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessorKey,
popNode());
case 'K':
return createWithChild(Node::Kind::MetadataInstantiationCache,
popNode());
case 'J':
return createWithChild(Node::Kind::NoncanonicalSpecializedGenericTypeMetadataCache, popNode());
case 'k':
return createWithChild(Node::Kind::OpaqueTypeDescriptorAccessorVar,
popNode());
case 'K':
return createWithChild(Node::Kind::MetadataInstantiationCache,
popNode());
case 'l':
return createWithPoppedType(
Node::Kind::TypeMetadataSingletonInitializationCache);
Expand All @@ -1929,6 +1931,9 @@ NodePointer Demangler::demangleMetatype() {
Node::Kind::CanonicalSpecializedGenericMetaclass);
case 'n':
return createWithPoppedType(Node::Kind::NominalTypeDescriptor);
case 'N':
return createWithPoppedType(
Node::Kind::NoncanonicalSpecializedGenericTypeMetadata);
case 'o':
return createWithPoppedType(Node::Kind::ClassMetadataBaseOffset);
case 'p':
Expand Down
10 changes: 10 additions & 0 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,8 @@ class NodePrinter {
case Node::Kind::OpaqueReturnTypeOf:
case Node::Kind::CanonicalSpecializedGenericMetaclass:
case Node::Kind::CanonicalSpecializedGenericTypeMetadataAccessFunction:
case Node::Kind::NoncanonicalSpecializedGenericTypeMetadata:
case Node::Kind::NoncanonicalSpecializedGenericTypeMetadataCache:
return false;
}
printer_unreachable("bad node kind");
Expand Down Expand Up @@ -2438,6 +2440,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
Printer << "metadata instantiation cache for ";
print(Node->getChild(0));
return nullptr;
case Node::Kind::NoncanonicalSpecializedGenericTypeMetadata:
Printer << "noncanonical specialized generic type metadata for ";
print(Node->getChild(0));
return nullptr;
case Node::Kind::NoncanonicalSpecializedGenericTypeMetadataCache:
Printer << "cache variable for noncanonical specialized generic type metadata for ";
print(Node->getChild(0));
return nullptr;
}
printer_unreachable("bad node kind!");
}
Expand Down
10 changes: 10 additions & 0 deletions lib/Demangling/OldRemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2147,6 +2147,16 @@ void Remangler::mangleCanonicalSpecializedGenericTypeMetadataAccessFunction(
Buffer << "Mb";
}

void Remangler::mangleNoncanonicalSpecializedGenericTypeMetadata(Node *node) {
mangleSingleChildNode(node);
Buffer << "MN";
}

void Remangler::mangleNoncanonicalSpecializedGenericTypeMetadataCache(Node *node) {
mangleSingleChildNode(node);
Buffer << "MJ";
}

/// The top-level interface to the remangler.
std::string Demangle::mangleNodeOld(NodePointer node) {
if (!node) return "";
Expand Down
10 changes: 10 additions & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2552,6 +2552,16 @@ void Remangler::mangleMetadataInstantiationCache(Node *node) {
Buffer << "MK";
}

void Remangler::mangleNoncanonicalSpecializedGenericTypeMetadata(Node *node) {
mangleSingleChildNode(node);
Buffer << "MN";
}

void Remangler::mangleNoncanonicalSpecializedGenericTypeMetadataCache(Node *node) {
mangleSingleChildNode(node);
Buffer << "MJ";
}

} // anonymous namespace

/// The top-level interface to the remangler.
Expand Down
81 changes: 66 additions & 15 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1426,7 +1426,22 @@ void IRGenerator::noteUseOfCanonicalSpecializedMetadataAccessor(
}
}

static bool typeKindCanBePrespecialized(TypeKind theKind) {
switch (theKind) {
case TypeKind::Struct:
case TypeKind::BoundGenericStruct:
case TypeKind::Enum:
case TypeKind::BoundGenericEnum:
case TypeKind::Class:
case TypeKind::BoundGenericClass:
return true;
default:
return false;
}
}

void IRGenerator::noteUseOfSpecializedGenericTypeMetadata(CanType type) {
assert(typeKindCanBePrespecialized(type->getKind()));
auto key = type->getAnyNominal();
assert(key);
assert(key->isGenericContext());
Expand Down Expand Up @@ -3736,6 +3751,22 @@ IRGenModule::getAddrOfTypeMetadataLazyCacheVariable(CanType type) {
return variable;
}

llvm::Constant *
IRGenModule::getAddrOfNoncanonicalSpecializedGenericTypeMetadataCacheVariable(CanType type) {
assert(!type->hasArchetype() && !type->hasTypeParameter());
LinkEntity entity = LinkEntity::forNoncanonicalSpecializedGenericTypeMetadataCacheVariable(type);
if (auto &entry = GlobalVars[entity]) {
return entry;
}
auto variable =
getAddrOfLLVMVariable(entity, ForDefinition, DebugTypeInfo());

cast<llvm::GlobalVariable>(variable)->setInitializer(
llvm::ConstantPointerNull::get(TypeMetadataPtrTy));

return variable;
}

/// Get or create a type metadata cache variable. These are an
/// implementation detail of type metadata access functions.
llvm::Constant *
Expand Down Expand Up @@ -3817,6 +3848,9 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType,
llvm::StringRef section) {
assert(init);

auto isPrespecialized = concreteType->getAnyGeneric() &&
concreteType->getAnyGeneric()->isGenericContext();

if (isPattern) {
assert(isConstant && "Type metadata patterns must be constant");
auto addr = getAddrOfTypeMetadataPattern(concreteType->getAnyNominal(),
Expand Down Expand Up @@ -3844,7 +3878,13 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType,
adjustmentIndex = MetadataAdjustmentIndex::ValueType;
}

auto entity = LinkEntity::forTypeMetadata(concreteType, addrKind);
auto entity =
(isPrespecialized &&
!irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable(
*this, concreteType))
? LinkEntity::forNoncanonicalSpecializedGenericTypeMetadata(
concreteType)
: LinkEntity::forTypeMetadata(concreteType, addrKind);

auto DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType),
entity.getDefaultDeclarationType(*this)->getPointerTo(),
Expand All @@ -3868,9 +3908,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType,

// Don't define the alias for foreign type metadata or prespecialized generic
// metadata, since neither is ABI.
if ((nominal && requiresForeignTypeMetadata(nominal)) ||
(concreteType->getAnyGeneric() &&
concreteType->getAnyGeneric()->isGenericContext()))
if ((nominal && requiresForeignTypeMetadata(nominal)) || isPrespecialized)
return var;

// For concrete metadata, declare the alias to its address point.
Expand All @@ -3892,13 +3930,18 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType,
}

/// Fetch the declaration of the (possibly uninitialized) metadata for a type.
llvm::Constant *IRGenModule::getAddrOfTypeMetadata(CanType concreteType) {
return getAddrOfTypeMetadata(concreteType,
SymbolReferenceKind::Absolute).getDirectValue();
llvm::Constant *
IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
TypeMetadataCanonicality canonicality) {
return getAddrOfTypeMetadata(concreteType, SymbolReferenceKind::Absolute,
canonicality)
.getDirectValue();
}

ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
SymbolReferenceKind refKind) {
ConstantReference
IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
SymbolReferenceKind refKind,
TypeMetadataCanonicality canonicality) {
assert(!isa<UnboundGenericType>(concreteType));

auto nominal = concreteType->getAnyNominal();
Expand Down Expand Up @@ -3952,12 +3995,20 @@ ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
Optional<LinkEntity> entity;
DebugTypeInfo DbgTy;

if (fullMetadata) {
entity = LinkEntity::forTypeMetadata(concreteType,
TypeMetadataAddress::FullMetadata);
} else {
entity = LinkEntity::forTypeMetadata(concreteType,
TypeMetadataAddress::AddressPoint);
switch (canonicality) {
case TypeMetadataCanonicality::Canonical:
if (fullMetadata) {
entity = LinkEntity::forTypeMetadata(concreteType,
TypeMetadataAddress::FullMetadata);
} else {
entity = LinkEntity::forTypeMetadata(concreteType,
TypeMetadataAddress::AddressPoint);
}
break;
case TypeMetadataCanonicality::Noncanonical:
entity =
LinkEntity::forNoncanonicalSpecializedGenericTypeMetadata(concreteType);
break;
}
DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType),
defaultVarTy->getPointerTo(), Size(0),
Expand Down
9 changes: 6 additions & 3 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1977,8 +1977,9 @@ void irgen::emitLazySpecializedGenericTypeMetadata(IRGenModule &IGM,
*type.getClassOrBoundGenericClass());
break;
default:
llvm_unreachable("Cannot statically specialize types of kind other than "
"struct and enum.");
llvm_unreachable(
"Cannot statically specialize metadata for generic types of"
"kind other than struct, enum, and class.");
}
}

Expand Down Expand Up @@ -3476,7 +3477,9 @@ namespace {
MetadataTrailingFlags flags = super::getTrailingFlags();

flags.setIsStaticSpecialization(true);
flags.setIsCanonicalStaticSpecialization(true);
flags.setIsCanonicalStaticSpecialization(
irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable(
IGM, type));

return flags;
}
Expand Down
8 changes: 8 additions & 0 deletions lib/IRGen/IRGenMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ class IRGenMangler : public Mangle::ASTMangler {
return mangleTypeSymbol(type, "N");
}

std::string mangleNoncanonicalTypeMetadata(Type type) {
return mangleTypeSymbol(type, "MN");
}

std::string mangleNoncanonicalSpecializedGenericTypeMetadataCache(Type type) {
return mangleTypeSymbol(type, "MJ");
}

std::string mangleTypeMetadataPattern(const NominalTypeDecl *decl) {
return mangleNominalTypeSymbol(decl, "MP");
}
Expand Down
17 changes: 14 additions & 3 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,11 @@ enum class MangledTypeRefRole {
DefaultAssociatedTypeWitness,
};

enum class TypeMetadataCanonicality : bool {
Noncanonical,
Canonical,
};

/// IRGenModule - Primary class for emitting IR for global declarations.
///
class IRGenModule {
Expand Down Expand Up @@ -1392,9 +1397,14 @@ private: \

TypeEntityReference getTypeEntityReference(GenericTypeDecl *D);

llvm::Constant *getAddrOfTypeMetadata(CanType concreteType);
ConstantReference getAddrOfTypeMetadata(CanType concreteType,
SymbolReferenceKind kind);
llvm::Constant *
getAddrOfTypeMetadata(CanType concreteType,
TypeMetadataCanonicality canonicality =
TypeMetadataCanonicality::Canonical);
ConstantReference
getAddrOfTypeMetadata(CanType concreteType, SymbolReferenceKind kind,
TypeMetadataCanonicality canonicality =
TypeMetadataCanonicality::Canonical);
llvm::Constant *getAddrOfTypeMetadataPattern(NominalTypeDecl *D);
llvm::Constant *getAddrOfTypeMetadataPattern(NominalTypeDecl *D,
ConstantInit init,
Expand All @@ -1420,6 +1430,7 @@ private: \
llvm::Constant *getAddrOfTypeMetadataLazyCacheVariable(CanType type);
llvm::Constant *getAddrOfTypeMetadataDemanglingCacheVariable(CanType type,
ConstantInit definition);
llvm::Constant *getAddrOfNoncanonicalSpecializedGenericTypeMetadataCacheVariable(CanType type);

llvm::Constant *getAddrOfClassMetadataBounds(ClassDecl *D,
ForDefinition_t forDefinition);
Expand Down
Loading