Merge pull request #79302 from mikeash/singleton-metadata-pointer

[IRGen] Emit a pointer from nominal type descriptor to concrete metadata.
This commit is contained in:
Mike Ash
2025-02-28 15:24:36 -05:00
committed by GitHub
7 changed files with 142 additions and 15 deletions

View File

@@ -3879,6 +3879,13 @@ struct TargetCanonicalSpecializedMetadatasCachingOnceToken {
TargetRelativeDirectPointer<Runtime, swift_once_t, /*Nullable*/ false> token;
};
template <typename Runtime>
struct TargetSingletonMetadataPointer {
TargetRelativeDirectPointer<Runtime, TargetMetadata<Runtime>,
/*Nullable*/ false>
metadata;
};
template <typename Runtime>
class swift_ptrauth_struct_context_descriptor(TypeContextDescriptor)
TargetTypeContextDescriptor : public TargetContextDescriptor<Runtime> {
@@ -3931,7 +3938,15 @@ public:
}
bool hasCanonicalMetadataPrespecializations() const {
return getTypeContextDescriptorFlags().hasCanonicalMetadataPrespecializations();
return this->isGeneric() &&
getTypeContextDescriptorFlags()
.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer();
}
bool hasSingletonMetadataPointer() const {
return !this->isGeneric() &&
getTypeContextDescriptorFlags()
.hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer();
}
bool hasLayoutString() const {
@@ -4123,7 +4138,8 @@ class swift_ptrauth_struct_context_descriptor(ClassDescriptor)
TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>,
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>,
InvertibleProtocolSet> {
InvertibleProtocolSet,
TargetSingletonMetadataPointer<Runtime>> {
private:
using TrailingGenericContextObjects =
swift::TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
@@ -4140,7 +4156,8 @@ private:
TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>,
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>,
InvertibleProtocolSet>;
InvertibleProtocolSet,
TargetSingletonMetadataPointer<Runtime>>;
using TrailingObjects =
typename TrailingGenericContextObjects::TrailingObjects;
@@ -4170,6 +4187,7 @@ public:
TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>;
using MetadataCachingOnceToken =
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>;
using SingletonMetadataPointer = TargetSingletonMetadataPointer<Runtime>;
using StoredPointer = typename Runtime::StoredPointer;
using StoredPointerDifference = typename Runtime::StoredPointerDifference;
@@ -4311,6 +4329,10 @@ private:
return this->hasCanonicalMetadataPrespecializations() ? 1 : 0;
}
size_t numTrailingObjects(OverloadToken<SingletonMetadataPointer>) const {
return this->hasSingletonMetadataPointer() ? 1 : 0;
}
public:
const TargetRelativeDirectPointer<Runtime, const void, /*nullable*/true> &
getResilientSuperclass() const {
@@ -4490,6 +4512,14 @@ public:
return box->token.get();
}
TargetMetadata<Runtime> *getSingletonMetadata() const {
if (!this->hasSingletonMetadataInitialization())
return nullptr;
auto box = this->template getTrailingObjects<SingletonMetadataPointer>();
return box->token.get();
}
/// Retrieve the set of protocols that are inverted by this type's
/// primary definition.
///
@@ -4537,7 +4567,8 @@ class swift_ptrauth_struct_context_descriptor(StructDescriptor)
TargetCanonicalSpecializedMetadatasListCount<Runtime>,
TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>,
InvertibleProtocolSet> {
InvertibleProtocolSet,
TargetSingletonMetadataPointer<Runtime>> {
public:
using ForeignMetadataInitialization =
TargetForeignMetadataInitialization<Runtime>;
@@ -4551,6 +4582,7 @@ public:
TargetCanonicalSpecializedMetadatasListEntry<Runtime>;
using MetadataCachingOnceToken =
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>;
using SingletonMetadataPointer = TargetSingletonMetadataPointer<Runtime>;
private:
using TrailingGenericContextObjects =
@@ -4561,7 +4593,8 @@ private:
MetadataListCount,
MetadataListEntry,
MetadataCachingOnceToken,
InvertibleProtocolSet>;
InvertibleProtocolSet,
TargetSingletonMetadataPointer<Runtime>>;
using TrailingObjects =
typename TrailingGenericContextObjects::TrailingObjects;
@@ -4595,6 +4628,10 @@ private:
return this->hasCanonicalMetadataPrespecializations() ? 1 : 0;
}
size_t numTrailingObjects(OverloadToken<SingletonMetadataPointer>) const {
return this->hasSingletonMetadataPointer() ? 1 : 0;
}
public:
using TrailingGenericContextObjects::getGenericContext;
using TrailingGenericContextObjects::getGenericContextHeader;
@@ -4648,6 +4685,14 @@ public:
return box->token.get();
}
TargetMetadata<Runtime> *getSingletonMetadata() const {
if (!this->hasSingletonMetadataInitialization())
return nullptr;
auto box = this->template getTrailingObjects<SingletonMetadataPointer>();
return box->token.get();
}
/// Retrieve the set of protocols that are inverted by this type's
/// primary definition.
///
@@ -4684,7 +4729,8 @@ class swift_ptrauth_struct_context_descriptor(EnumDescriptor)
TargetCanonicalSpecializedMetadatasListCount<Runtime>,
TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>,
InvertibleProtocolSet> {
InvertibleProtocolSet,
TargetSingletonMetadataPointer<Runtime>> {
public:
using SingletonMetadataInitialization =
TargetSingletonMetadataInitialization<Runtime>;
@@ -4698,6 +4744,7 @@ public:
TargetCanonicalSpecializedMetadatasListEntry<Runtime>;
using MetadataCachingOnceToken =
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>;
using SingletonMetadataPointer = TargetSingletonMetadataPointer<Runtime>;
private:
using TrailingGenericContextObjects =
@@ -4708,7 +4755,8 @@ private:
MetadataListCount,
MetadataListEntry,
MetadataCachingOnceToken,
InvertibleProtocolSet>;
InvertibleProtocolSet,
TargetSingletonMetadataPointer<Runtime>>;
using TrailingObjects =
typename TrailingGenericContextObjects::TrailingObjects;
@@ -4742,6 +4790,10 @@ private:
return this->hasCanonicalMetadataPrespecializations() ? 1 : 0;
}
size_t numTrailingObjects(OverloadToken<SingletonMetadataPointer>) const {
return this->hasSingletonMetadataPointer() ? 1 : 0;
}
public:
using TrailingGenericContextObjects::getGenericContext;
using TrailingGenericContextObjects::getGenericContextHeader;
@@ -4809,6 +4861,14 @@ public:
return box->token.get();
}
TargetMetadata<Runtime> *getSingletonMetadata() const {
if (!this->hasSingletonMetadataInitialization())
return nullptr;
auto box = this->template getTrailingObjects<SingletonMetadataPointer>();
return box->token.get();
}
/// Retrieve the set of protocols that are inverted by this type's
/// primary definition.
///

View File

@@ -1872,9 +1872,10 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
/// Meaningful for all type-descriptor kinds.
HasImportInfo = 2,
/// Set if the type descriptor has a pointer to a list of canonical
/// prespecializations.
HasCanonicalMetadataPrespecializations = 3,
/// Set if the generic type descriptor has a pointer to a list of canonical
/// prespecializations, or the non-generic type descriptor has a pointer to
/// its singleton metadata.
HasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer = 3,
/// Set if the metadata contains a pointer to a layout string
HasLayoutString = 4,
@@ -1959,7 +1960,10 @@ public:
FLAGSET_DEFINE_FLAG_ACCESSORS(HasImportInfo, hasImportInfo, setHasImportInfo)
FLAGSET_DEFINE_FLAG_ACCESSORS(HasCanonicalMetadataPrespecializations, hasCanonicalMetadataPrespecializations, setHasCanonicalMetadataPrespecializations)
FLAGSET_DEFINE_FLAG_ACCESSORS(
HasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer,
hasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer,
setHasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer)
FLAGSET_DEFINE_FLAG_ACCESSORS(HasLayoutString,
hasLayoutString,

View File

@@ -406,6 +406,10 @@ public:
/// arguments.
unsigned PrespecializeGenericMetadata : 1;
/// Emit pointers to the corresponding type metadata in non-public non-generic
/// type descriptors.
unsigned EmitSingletonMetadataPointers : 1;
/// The path to load legacy type layouts from.
StringRef ReadLegacyTypeInfoPath;
@@ -597,7 +601,8 @@ public:
LazyInitializeProtocolConformances(false),
IndirectAsyncFunctionPointer(false), IndirectCoroFunctionPointer(false),
CompactAbsoluteFunctionPointer(false), DisableLegacyTypeInfo(false),
PrespecializeGenericMetadata(false), UseIncrementalLLVMCodeGen(true),
PrespecializeGenericMetadata(false),
EmitSingletonMetadataPointers(false), UseIncrementalLLVMCodeGen(true),
UseTypeLayoutValueHandling(true), ForceStructTypeLayouts(false),
EnableLargeLoadableTypesReg2Mem(true),
EnableLayoutStringValueWitnesses(false),

View File

@@ -1116,6 +1116,10 @@ def prespecialize_generic_metadata : Flag<["-"], "prespecialize-generic-metadata
HelpText<"Statically specialize metadata for generic types at types that "
"are known to be used in source.">;
def emit_singleton_metadata_pointer : Flag<["-"], "emit-singleton-metadata-pointer">,
HelpText<"Emit a pointer to the corresponding type metadata into non-public "
"non-generic type descriptors.">;
def read_legacy_type_info_path_EQ : Joined<["-"], "read-legacy-type-info-path=">,
HelpText<"Read legacy type layout from the given path instead of default path">;

View File

@@ -3453,6 +3453,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
Opts.PrespecializeGenericMetadata = true;
}
if (Args.hasArg(OPT_emit_singleton_metadata_pointer)) {
Opts.EmitSingletonMetadataPointers = true;
}
if (const Arg *A = Args.getLastArg(OPT_read_legacy_type_info_path_EQ)) {
Opts.ReadLegacyTypeInfoPath = A->getValue();
}

View File

@@ -1589,7 +1589,8 @@ namespace {
void setCommonFlags(TypeContextDescriptorFlags &flags) {
setClangImportedFlags(flags);
setMetadataInitializationKind(flags);
setHasCanonicalMetadataPrespecializations(flags);
setHasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer(
flags);
}
void setClangImportedFlags(TypeContextDescriptorFlags &flags) {
@@ -1623,8 +1624,11 @@ namespace {
flags.setMetadataInitialization(MetadataInitialization);
}
void setHasCanonicalMetadataPrespecializations(TypeContextDescriptorFlags &flags) {
flags.setHasCanonicalMetadataPrespecializations(hasCanonicalMetadataPrespecializations());
void setHasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer(
TypeContextDescriptorFlags &flags) {
flags.setHasCanonicalMetadataPrespecializationsOrSingletonMetadataPointer(
hasCanonicalMetadataPrespecializations() ||
hasSingletonMetadataPointer());
}
bool hasCanonicalMetadataPrespecializations() {
@@ -1636,6 +1640,30 @@ namespace {
});
}
bool hasSingletonMetadataPointer() {
if (!IGM.IRGen.Opts.EmitSingletonMetadataPointers)
return false;
bool isGeneric = Type->isGenericContext();
bool noInitialization =
MetadataInitialization ==
TypeContextDescriptorFlags::NoMetadataInitialization;
auto isPublic = Type->getFormalAccessScope().isPublic();
auto kind = asImpl().getContextKind();
auto isSupportedKind = kind == ContextDescriptorKind::Class ||
kind == ContextDescriptorKind::Struct ||
kind == ContextDescriptorKind::Enum;
// Only emit a singleton metadata pointer if:
// The type is not generic (there's no single metadata if it's generic).
// The metadata doesn't require runtime initialization. (The metadata
// can't safely be accessed directly if it does.)
// The type is not public. (If it's public it can be found by symbol.)
// It's a class, struct, or enum.
return !isGeneric && noInitialization && !isPublic && isSupportedKind;
}
void maybeAddMetadataInitialization() {
switch (MetadataInitialization) {
case TypeContextDescriptorFlags::NoMetadataInitialization:
@@ -1724,6 +1752,14 @@ namespace {
B.addRelativeAddress(cachingOnceToken);
}
void maybeAddSingletonMetadataPointer() {
if (hasSingletonMetadataPointer()) {
auto type = Type->getDeclaredTypeInContext()->getCanonicalType();
auto metadata = IGM.getAddrOfTypeMetadata(type);
B.addRelativeAddress(metadata);
}
}
// Subclasses should provide:
// ContextDescriptorKind getContextKind();
// void addLayoutInfo();
@@ -1758,6 +1794,7 @@ namespace {
super::layout();
maybeAddCanonicalMetadataPrespecializations();
addInvertedProtocols();
maybeAddSingletonMetadataPointer();
}
ContextDescriptorKind getContextKind() {
@@ -1832,6 +1869,7 @@ namespace {
super::layout();
maybeAddCanonicalMetadataPrespecializations();
addInvertedProtocols();
maybeAddSingletonMetadataPointer();
}
ContextDescriptorKind getContextKind() {
@@ -1965,6 +2003,7 @@ namespace {
addObjCResilientClassStubInfo();
maybeAddCanonicalMetadataPrespecializations();
addInvertedProtocols();
maybeAddSingletonMetadataPointer();
}
void addIncompleteMetadataOrRelocationFunction() {

View File

@@ -0,0 +1,11 @@
// RUN: %target-swift-frontend -prespecialize-generic-metadata -target %module-target-future -emit-ir %s -emit-singleton-metadata-pointer | %FileCheck %s -DINT=i%target-ptrsize -DALIGNMENT=%target-alignment --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK --check-prefix=CHECK-%target-vendor --dump-input=always
// CHECK: @"$s4main23PrivateNongenericStructVMn" =
// CHECK-SAME: hidden constant <{ i32, i32, i32, i32, i32, i32, i32, i32 }>
// -- flags: struct, unique, has singleton metadata pointer
// CHECK-SAME: <{ i32 524369,
// -- 32-bit relative pointer to metadata
// CHECK-64-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr getelementptr inbounds (<{ {{.*}} }>, ptr @"$s4main23PrivateNongenericStructVMf", i32 0, i32 2) to i64)
// CHECK-32-SAME: i32 sub (i32 ptrtoint (ptr getelementptr inbounds (<{ {{.*}} }>, ptr @"$s4main23PrivateNongenericStructVMf", i32 0, i32 2) to i32)
internal struct PrivateNongenericStruct {}