Skip to content

Reorganize TypeContextDescriptorFlags to be a bit more semantic #18253

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
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
124 changes: 98 additions & 26 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -1180,35 +1180,51 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
// Generic flags build upwards from 0.
// Type-specific flags build downwards from 15.

/// Set if the type represents an imported C tag type.
/// Set if the type supports reflection. C and Objective-C enums
/// currently don't.
///
/// Meaningful for all type-descriptor kinds.
IsCTag = 0,
IsReflectable = 0,

/// Set if the type represents an imported C typedef type.
/// Whether there's something unusual about how the metadata is
/// initialized.
///
/// Meaningful for all type-descriptor kinds.
IsCTypedef = 1,

/// Set if the type supports reflection. C and Objective-C enums
/// currently don't.
MetadataInitialization = 1,
MetadataInitialization_width = 2,

/// The namespace of the imported declaration that gave rise to this type.
/// Some languages (most importantly, C/C++/Objective-C) have different
/// symbol namespaces in which types can be declared; for example,
/// `struct A` and `typedef ... A` can be declared in the same scope and
/// resolve to unrelated types. When these declarations are imported,
/// there are several possible ways to distinguish them in Swift, e.g.
/// by implicitly renaming them; however, the external name used for
/// mangling and metadata must be stable and so is based on the original
/// declared name. Therefore, in these languages, we privilege one
/// symbol namespace as the default (although which may depend on the
/// type kind), and declarations from the other(s) must be marked in
/// order to differentiate them.
///
/// Meaningful for all type-descriptor kinds.
IsReflectable = 2,
ImportNamespace = 3,
ImportNamespace_width = 3,

/// Set if the type is a Clang-importer-synthesized related entity. After
/// the null terminator for the type name is another null-terminated string
/// containing the tag that discriminates the entity from other synthesized
/// declarations associated with the same declaration.
IsSynthesizedRelatedEntity = 3,

/// Set if the type requires non-trivial but non-generic metadata
/// initialization. It may or may not be truly "in place" depending
/// on the kind of metadata.
/// Set if the type is an importer-synthesized related entity.
/// A related entity is an entity synthesized in response to an imported
/// type which is not the type itself; for example, when the importer
/// sees an ObjC error domain, it creates an error-wrapper type (a
/// related entity) and a Code enum (not a related entity because it's
/// exactly the original type).
///
/// The name and import namespace (together with the parent context)
/// identify the original declaration.
///
/// Currently only meaningful for value descriptors, but will be
/// extended to class descriptors.
HasInPlaceMetadataInitialization = 4,
/// If this flag is set, then after the null terminator for the type name
/// is another null-terminated string containing the tag that discriminates
/// the entity from other synthesized declarations associated with the
/// same declaration.
IsSynthesizedRelatedEntity = 6,

/// Set if the context descriptor is includes metadata for dynamically
/// constructing a class's vtables at metadata instantiation time.
Expand Down Expand Up @@ -1237,18 +1253,74 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
explicit TypeContextDescriptorFlags(uint16_t bits) : FlagSet(bits) {}
constexpr TypeContextDescriptorFlags() {}

FLAGSET_DEFINE_FLAG_ACCESSORS(IsCTag, isCTag, setIsCTag)
FLAGSET_DEFINE_FLAG_ACCESSORS(IsCTypedef, isCTypedef, setIsCTypedef)
FLAGSET_DEFINE_FLAG_ACCESSORS(IsReflectable, isReflectable, setIsReflectable)

enum MetadataInitializationKind {
/// There are either no special rules for initializing the metadata
/// or the metadata is generic. (Genericity is set in the
/// non-kind-specific descriptor flags.)
NoMetadataInitialization = 0,

/// The type requires non-trivial singleton initialization using the
/// "in-place" code pattern.
InPlaceMetadataInitialization = 1,

// We only have two bits here, so if you add a third special kind,
// include more flag bits in its out-of-line storage.
};

FLAGSET_DEFINE_FIELD_ACCESSORS(MetadataInitialization,
MetadataInitialization_width,
MetadataInitializationKind,
getMetadataInitialization,
setMetadataInitialization)

bool hasInPlaceMetadataInitialization() const {
return getMetadataInitialization() == InPlaceMetadataInitialization;
}

enum ImportNamespaceKind {
/// The type comes the default namespace for its language.
DefaultNamespace = 0,

// The behavior for C imported types is complicated in ways that don't
// entirely make sense according to the design laid out in the comment
// on the ImportNamespace field. The rules are basically:
// - Classes are assumed to come from Objective-C by default.
// ObjC classes are in the ordinary namespace in C.
// - Protocols are assumed to come from Objective-C by default.
// ObjC protocols are in their own namespace in C.
// - Structs and enums seem to always get either CTag or CTypedef.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct. Structs, enums, and unions always get CTag. CTypedef is only for typedefs with the swift_wrapper attribute.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, and for CF types.

// It would probably make more sense to assume they come from the
// tag namespace in C and then just use CTypedef as an override.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This part is still fine, though. We would never map a class or protocol to a struct.)


/// The type comes from an imported C tag type.
CTag = 1,

/// The type comes from an imported C typedef type.
CTypedef = 2,

// We only have three bits here, so be judicious about adding new
// namespaces.
};

FLAGSET_DEFINE_FIELD_ACCESSORS(ImportNamespace,
ImportNamespace_width,
ImportNamespaceKind,
getImportNamespace,
setImportNamespace)

bool isCTag() const {
return getImportNamespace() == CTag;
}
bool isCTypedef() const {
return getImportNamespace() == CTypedef;
}

FLAGSET_DEFINE_FLAG_ACCESSORS(IsSynthesizedRelatedEntity,
isSynthesizedRelatedEntity,
setIsSynthesizedRelatedEntity)

FLAGSET_DEFINE_FLAG_ACCESSORS(HasInPlaceMetadataInitialization,
hasInPlaceMetadataInitialization,
setHasInPlaceMetadataInitialization)

FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable,
class_hasVTable,
class_setHasVTable)
Expand Down
31 changes: 17 additions & 14 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,20 +822,25 @@ namespace {
IGM.setTrueConstGlobal(var);
return var;
}

void setCommonFlags(TypeContextDescriptorFlags &flags) {
setClangImportedFlags(flags);
setMetadataInitializationKind(flags);
}

/// Flags to indicate Clang-imported declarations so we mangle them
/// consistently at runtime.
void getClangImportedFlags(TypeContextDescriptorFlags &flags) const {
void setClangImportedFlags(TypeContextDescriptorFlags &flags) {
if (Type->getAttrs().getAttribute<ClangImporterSynthesizedTypeAttr>()) {
flags.setIsSynthesizedRelatedEntity(true);
}

if (auto clangDecl = Mangle::ASTMangler::getClangDeclForMangling(Type)) {
if (isa<clang::TagDecl>(clangDecl)) {
flags.setIsCTag(true);
flags.setImportNamespace(TypeContextDescriptorFlags::CTag);
} else if (isa<clang::TypedefNameDecl>(clangDecl)
|| isa<clang::ObjCCompatibleAliasDecl>(clangDecl)) {
flags.setIsCTypedef(true);
flags.setImportNamespace(TypeContextDescriptorFlags::CTypedef);
}
}
}
Expand All @@ -859,9 +864,11 @@ namespace {
return HasInPlaceMetadataInitialization;
}

void setHasInPlaceMetadataInitialization(TypeContextDescriptorFlags &flags){
flags.setHasInPlaceMetadataInitialization(
HasInPlaceMetadataInitialization);
void setMetadataInitializationKind(TypeContextDescriptorFlags &flags) {
if (HasInPlaceMetadataInitialization) {
flags.setMetadataInitialization(
TypeContextDescriptorFlags::InPlaceMetadataInitialization);
}
}

void maybeAddInPlaceMetadataInitialization() {
Expand Down Expand Up @@ -1011,9 +1018,7 @@ namespace {
flags.setIsReflectable(
!IGM.shouldEmitOpaqueTypeMetadataRecord(getType()));

setHasInPlaceMetadataInitialization(flags);

getClangImportedFlags(flags);
setCommonFlags(flags);
return flags.getOpaqueValue();
}
};
Expand Down Expand Up @@ -1071,9 +1076,7 @@ namespace {

flags.setIsReflectable(Strategy.isReflectable());

setHasInPlaceMetadataInitialization(flags);

getClangImportedFlags(flags);
setCommonFlags(flags);
return flags.getOpaqueValue();
}
};
Expand Down Expand Up @@ -1130,6 +1133,8 @@ namespace {
// Classes are always reflectable.
flags.setIsReflectable(true);

setCommonFlags(flags);

if (!getType()->isForeign()) {
if (MetadataLayout->areImmediateMembersNegative())
flags.class_setAreImmediateMembersNegative(true);
Expand All @@ -1145,8 +1150,6 @@ namespace {
flags.class_setSuperclassReferenceKind(SuperClassRef->getKind());
}

getClangImportedFlags(flags);

return flags.getOpaqueValue();
}

Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/cf.sil
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

// CHECK-64: @"$SSo24CCMutableRefrigeratorRefaMn" = linkonce_odr hidden constant
// -- is imported C typedef, is class, is nonunique
// CHECK-64-SAME: <i32 0x0006_0010>
// CHECK-64-SAME: <i32 0x0011_0010>
// CHECK-64-SAME: [[MUTABLE_REFRIGERATOR_NAME]]

// CHECK-64: @"$SSo24CCMutableRefrigeratorRefaN" = linkonce_odr hidden global <{ {{.*}} }> <{
Expand Down
16 changes: 8 additions & 8 deletions test/IRGen/class_metadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ class A {}

// CHECK: [[A_NAME:@.*]] = private constant [2 x i8] c"A\00"
// CHECK-LABEL: @"$S14class_metadata1ACMn" =
// Flags. -2147221424 == 0x8004_0050 == HasVTable | Reflectable | Unique | Class
// CHECK-SAME: i32 -2147221424,
// Flags. -2147418032 == 0x8001_0050 == HasVTable | Reflectable | Unique | Class
// CHECK-SAME: i32 -2147418032,
// Parent.
// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
// Name.
Expand Down Expand Up @@ -33,8 +33,8 @@ class B : A {}

// CHECK: [[B_NAME:@.*]] = private constant [2 x i8] c"B\00"
// CHECK-LABEL: @"$S14class_metadata1BCMn" =
// Flags. 262224 == 0x0004_0050 == Reflectable | Unique | Class
// CHECK-SAME: i32 262224,
// Flags. 65616 == 0x0001_0050 == Reflectable | Unique | Class
// CHECK-SAME: i32 65616,
// Parent.
// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
// Name.
Expand All @@ -53,8 +53,8 @@ class C<T> : B {}

// CHECK: [[C_NAME:@.*]] = private constant [2 x i8] c"C\00"
// CHECK-LABEL: @"$S14class_metadata1CCMn" =
// Flags. 262352 == 0x0004_00d0 == Reflectable | Generic | Unique | Class
// CHECK-SAME: i32 262352,
// Flags. 65744 == 0x0001_00d0 == Reflectable | Generic | Unique | Class
// CHECK-SAME: i32 65744,
// Parent.
// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
// Name.
Expand Down Expand Up @@ -104,8 +104,8 @@ class D : E {}

// CHECK: [[D_NAME:@.*]] = private constant [2 x i8] c"D\00"
// CHECK-LABEL: @"$S14class_metadata1DCMn" =
// Flags. 268697680 == 0x1004_0050 == Reflectable | IndirectSuperclass | Unique | Class
// CHECK-SAME: i32 268697680,
// Flags. 268501072 == 0x1001_0050 == Reflectable | IndirectSuperclass | Unique | Class
// CHECK-SAME: i32 268501072,
// Parent.
// CHECK-SAME: i32 {{.*}} @"$S14class_metadataMXM"
// Name.
Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/class_resilience.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

// CHECK: @"$S16class_resilience14ResilientChildCMn" = {{(protected )?}}{{(dllexport )?}}constant <{{.*}}> <{
// -- flags: class, unique, reflectable, has vtable, has resilient superclass
// CHECK-SAME: <i32 0xD004_0050>
// CHECK-SAME: <i32 0xD001_0050>
// -- name:
// CHECK-SAME: [15 x i8]* [[RESILIENTCHILD_NAME]]
// -- num fields
Expand Down
8 changes: 4 additions & 4 deletions test/IRGen/enum_resilience.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ import resilient_struct
// CHECK-SAME: internal global { %swift.type*, i8* } zeroinitializer, align

// CHECK: @"$S15enum_resilience24EnumWithResilientPayloadOMn" = {{.*}}constant
// 1310802 == 0x00140052
// 0x0010 - HasInPlaceMetadataInitialization
// 0x0014 - IsReflectable
// 196690 == 0x00030052
// 0x0002 - InPlaceMetadataInitialization
// 0x0001 - IsReflectable
// 0x 0040 - IsUnique
// 0x 0012 - Enum
// CHECK-SAME: i32 1310802,
// CHECK-SAME: i32 196690,
// CHECK-SAME: @"$S15enum_resilience24EnumWithResilientPayloadOMl"
// CHECK-SAME: @"$S15enum_resilience24EnumWithResilientPayloadOMf", i32 0, i32 1)
// CHECK-SAME: @"$S15enum_resilience24EnumWithResilientPayloadOMr"
Expand Down
4 changes: 2 additions & 2 deletions test/IRGen/generic_classes.sil
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Swift

// CHECK-LABEL: @"$S15generic_classes11RootGenericCMn" =
// -- flags: class, generic, unique, reflectable, has vtable
// CHECK-SAME: <i32 0x8004_00D0>
// CHECK-SAME: <i32 0x8001_00D0>
// -- name
// CHECK-SAME: [12 x i8]* [[ROOTGENERIC_NAME]]
// -- negative size in words
Expand Down Expand Up @@ -80,7 +80,7 @@ import Swift
// CHECK: [[ROOTNONGENERIC_NAME:@.*]] = private constant [15 x i8] c"RootNonGeneric\00"
// CHECK: @"$S15generic_classes14RootNonGenericCMn" = hidden constant <{ {{.*}} %swift.method_descriptor }> <{
// -- flags: class, unique, has vtable, reflectable
// CHECK-SAME: <i32 0x8004_0050>
// CHECK-SAME: <i32 0x8001_0050>
// -- name
// CHECK-SAME: [15 x i8]* [[ROOTNONGENERIC_NAME]]
// -- num fields
Expand Down
4 changes: 2 additions & 2 deletions test/IRGen/generic_structs.sil
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import Builtin
// CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [14 x i8] c"SingleDynamic\00"
// CHECK: @"$S15generic_structs13SingleDynamicVMn" = hidden constant
// -- flags: struct, unique, generic, reflectable
// CHECK-SAME: <i32 0x0004_00D1>
// CHECK-SAME: <i32 0x0001_00D1>
// -- name
// CHECK-SAME: [14 x i8]* [[SINGLEDYNAMIC_NAME]]
// -- field count
Expand All @@ -65,7 +65,7 @@ import Builtin
// CHECK: [[DYNAMICWITHREQUIREMENTS_NAME:@.*]] = private constant [24 x i8] c"DynamicWithRequirements\00"
// CHECK: @"$S15generic_structs23DynamicWithRequirementsVMn" = hidden constant <{ {{.*}} i32 }> <{
// -- flags: struct, unique, generic, reflectable
// CHECK-SAME: <i32 0x0004_00D1>
// CHECK-SAME: <i32 0x0001_00D1>
// -- name
// CHECK-SAME: [24 x i8]* [[DYNAMICWITHREQUIREMENTS_NAME]]
// -- field count
Expand Down
2 changes: 1 addition & 1 deletion test/IRGen/generic_types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// CHECK-LABEL: @"$S13generic_types1ACMI" = internal global [16 x i8*] zeroinitializer, align 8

// CHECK-LABEL: @"$S13generic_types1ACMn" = hidden constant
// CHECK-SAME: i32 -2147221296,
// CHECK-SAME: i32 -2147417904,
// CHECK-SAME: @"$S13generic_typesMXM"
// <name>
// CHECK-SAME: @"$S13generic_types1ACMa"
Expand Down
6 changes: 3 additions & 3 deletions test/IRGen/generic_vtable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class Concrete : Derived<Int> {

// CHECK-LABEL: @"$S14generic_vtable4BaseCMn" = {{(dllexport )?}}{{(protected )?}}constant
// -- flags: has vtable, reflectable, is class, is unique
// CHECK-SAME: <i32 0x8004_0050>,
// CHECK-SAME: <i32 0x8001_0050>,
// -- vtable offset
// CHECK-SAME: i32 10,
// -- vtable size
Expand All @@ -49,7 +49,7 @@ public class Concrete : Derived<Int> {

// CHECK-LABEL: @"$S14generic_vtable7DerivedCMn" = {{(dllexport )?}}{{(protected )?}}constant
// -- flags: has vtable, reflectable, is class, is unique, is generic
// CHECK-SAME: <i32 0x8004_00D0>,
// CHECK-SAME: <i32 0x8001_00D0>,
// -- vtable offset
// CHECK-SAME: i32 14,
// -- vtable size
Expand All @@ -73,7 +73,7 @@ public class Concrete : Derived<Int> {

// CHECK-LABEL: @"$S14generic_vtable8ConcreteCMn" = {{(dllexport )?}}{{(protected )?}}constant
// -- flags: has vtable, reflectable, is class, is unique
// CHECK-SAME: <i32 0x8004_0050>,
// CHECK-SAME: <i32 0x8001_0050>,
// -- vtable offset
// CHECK-SAME: i32 15,
// -- vtable size
Expand Down