Skip to content

Commit 5ad306a

Browse files
authored
Merge pull request swiftlang#22634 from slavapestov/update-callback-new-runtime
Always use update callback for classes when the deployment target is sufficiently new
2 parents 7186092 + 6ac9170 commit 5ad306a

17 files changed

+839
-272
lines changed

include/swift/IRGen/Linking.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ class LinkEntity {
158158
SwiftMetaclassStub,
159159

160160
/// A callback used by newer Objective-C runtimes to initialize class
161-
/// metadata for classes where doesClassMetadataRequireUpdate() is true
162-
/// but doesClassMetadataRequireInitialization() is false.
161+
/// metadata for classes where getClassMetadataStrategy() is equal to
162+
/// ClassMetadataStrategy::Update or ::FixedOrUpdate.
163163
ObjCMetadataUpdateFunction,
164164

165165
/// A class metadata base offset global variable. This stores the offset

lib/IRGen/ClassLayout.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,15 @@ using namespace swift;
2525
using namespace irgen;
2626

2727
ClassLayout::ClassLayout(const StructLayoutBuilder &builder,
28-
bool isFixedSize,
29-
bool metadataRequiresInitialization,
30-
bool metadataRequiresRelocation,
28+
ClassMetadataOptions options,
3129
llvm::Type *classTy,
3230
ArrayRef<VarDecl *> allStoredProps,
3331
ArrayRef<FieldAccess> allFieldAccesses,
3432
ArrayRef<ElementLayout> allElements)
3533
: MinimumAlign(builder.getAlignment()),
3634
MinimumSize(builder.getSize()),
3735
IsFixedLayout(builder.isFixedLayout()),
38-
IsFixedSize(isFixedSize),
39-
MetadataRequiresInitialization(metadataRequiresInitialization),
40-
MetadataRequiresRelocation(metadataRequiresRelocation),
36+
Options(options),
4137
Ty(classTy),
4238
AllStoredProperties(allStoredProps),
4339
AllFieldAccesses(allFieldAccesses),

lib/IRGen/ClassLayout.h

Lines changed: 99 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,65 @@ enum class FieldAccess : uint8_t {
3939
ConstantIndirect
4040
};
4141

42+
/// A set of flags describing properties of a class's metadata layout.
43+
/// The presence or absence of these flags determines how much static
44+
/// knowledge the compiler has of the layout of this class and its
45+
/// metadata, which in turn will determine the strategy used to emit
46+
/// and initialize class metadata.
47+
enum class ClassMetadataFlags {
48+
/// Does the class or any of its superclasses have stored properties that
49+
/// where dropped due to the Swift language version availability of
50+
/// their types?
51+
ClassHasMissingMembers = (1 << 0),
52+
53+
/// Does the class or any of its fragile superclasses have stored
54+
/// properties of unknown size, which do *not* depend on generic
55+
/// parameters?
56+
///
57+
/// This is different from the class itself being resilient or
58+
/// having resilient ancestry, because we still have a fixed layout
59+
/// for the class metadata in this case.
60+
///
61+
/// In fact, for a class with resilient ancestry, this can still be
62+
/// false if all of the fields known to us are fixed size.
63+
ClassHasResilientMembers = (1 << 1),
64+
65+
/// Is this class or any of its superclasses generic?
66+
ClassHasGenericAncestry = (1 << 2),
67+
68+
/// Is this class itself generic via the Swift generic system, ie. not a
69+
/// lightweight Objective-C generic class?
70+
ClassIsGeneric = (1 << 3),
71+
72+
/// Does the class layout depend on the size or alignment of its
73+
/// generic parameters?
74+
///
75+
/// This can be the case if the class has generic resilient ancestry
76+
/// that depends on the class's generic parameters, of it it has
77+
/// fields of generic type that are not fixed size.
78+
ClassHasGenericLayout = (1 << 4),
79+
80+
/// Is this class or any of its superclasses resilient from the viewpoint
81+
/// of the current module? This means that their metadata can change size,
82+
/// hence field offsets, generic arguments and virtual methods must be
83+
/// accessed relative to a metadata base global variable.
84+
///
85+
/// Note that a @_fixed_layout class in a resilient module still has
86+
/// resilient metadata, so any subclasses will have this flag set;
87+
/// to check for resilient stored property layout, check for
88+
/// ClassHasResilientMembers.
89+
ClassHasResilientAncestry = (1 << 5),
90+
91+
/// Are any of this class's superclasses defined in Objective-C?
92+
/// This means that field offsets must be loaded from field offset globals
93+
/// or the field offset vector in the metadata, and the Objective-C runtime
94+
/// will slide offsets based on the actual superclass size, which is not
95+
/// known at compile time.
96+
ClassHasObjCAncestry = (1 << 6)
97+
};
98+
99+
using ClassMetadataOptions = OptionSet<ClassMetadataFlags>;
100+
42101
class ClassLayout {
43102
/// The statically-known minimum bound on the alignment.
44103
Alignment MinimumAlign;
@@ -50,18 +109,7 @@ class ClassLayout {
50109
/// alignment are exact.
51110
bool IsFixedLayout;
52111

53-
/// Do instances of this class have a size and layout known at compile time?
54-
///
55-
/// Note: This is a stronger condition than having a fixed layout. The latter
56-
/// is true even when the class requires sliding ivars by the Objective-C
57-
/// runtime.
58-
bool IsFixedSize;
59-
60-
/// Does the class metadata require initialization?
61-
bool MetadataRequiresInitialization;
62-
63-
/// Does the class metadata require relocation?
64-
bool MetadataRequiresRelocation;
112+
ClassMetadataOptions Options;
65113

66114
/// The LLVM type for instances of this class.
67115
llvm::Type *Ty;
@@ -79,9 +127,7 @@ class ClassLayout {
79127

80128
public:
81129
ClassLayout(const StructLayoutBuilder &builder,
82-
bool isFixedSize,
83-
bool metadataRequiresInitialization,
84-
bool metadataRequiresRelocation,
130+
ClassMetadataOptions options,
85131
llvm::Type *classTy,
86132
ArrayRef<VarDecl *> allStoredProps,
87133
ArrayRef<FieldAccess> allFieldAccesses,
@@ -96,14 +142,49 @@ class ClassLayout {
96142

97143
bool isFixedLayout() const { return IsFixedLayout; }
98144

99-
bool isFixedSize() const { return IsFixedSize; }
145+
/// Returns true if the stored property layout of instances of this class
146+
/// is known at compile time.
147+
///
148+
/// Note that ClassHasResilientAncestry or ClassHasGenericAncestry might
149+
/// still be true; the former means the class has resilient metadata, so
150+
/// it might still be @_fixed_layout; the latter means we have a generic
151+
/// superclass, but it doesn't mean the layout actually depends on any
152+
/// generic parameters.
153+
bool isFixedSize() const {
154+
return !(Options.contains(ClassMetadataFlags::ClassHasMissingMembers) ||
155+
Options.contains(ClassMetadataFlags::ClassHasResilientMembers) ||
156+
Options.contains(ClassMetadataFlags::ClassHasGenericLayout) ||
157+
Options.contains(ClassMetadataFlags::ClassHasObjCAncestry));
158+
}
100159

160+
/// Returns true iff everything about the class metadata layout is statically
161+
/// known except field offsets and the instance size and alignment.
162+
///
163+
/// Will assert if the class metadata is "more" dynamic; you must check
164+
/// doesMetadataRequireRelocation() and doesMetadataRequireInitialization()
165+
/// first.
166+
bool doesMetadataRequireUpdate() const {
167+
assert(!doesMetadataRequireInitialization());
168+
return (Options.contains(ClassMetadataFlags::ClassHasResilientMembers) ||
169+
Options.contains(ClassMetadataFlags::ClassHasMissingMembers));
170+
}
171+
172+
/// Returns true iff everything about the class metadata layout is statically
173+
/// known except the superclass field must be instantiated at runtime because
174+
/// it is a generic class type.
175+
///
176+
/// Will assert if the class metadata is "more" dynamic; you must check
177+
/// doesMetadataRequireRelocation() first.
101178
bool doesMetadataRequireInitialization() const {
102-
return MetadataRequiresInitialization;
179+
assert(!doesMetadataRequireRelocation());
180+
return Options.contains(ClassMetadataFlags::ClassHasGenericAncestry);
103181
}
104182

183+
/// Returns true if the class metadata must be built at runtime because its
184+
/// size is not known at compile time. This is the most general case.
105185
bool doesMetadataRequireRelocation() const {
106-
return MetadataRequiresRelocation;
186+
return (Options.contains(ClassMetadataFlags::ClassHasResilientAncestry) ||
187+
Options.contains(ClassMetadataFlags::ClassIsGeneric));
107188
}
108189

109190
std::pair<FieldAccess, ElementLayout>

0 commit comments

Comments
 (0)