@@ -163,54 +163,7 @@ namespace {
163
163
// ancestry, or has a superclass that is itself resilient.
164
164
bool CompletelyFragileLayout;
165
165
166
- // The below flags indicate various things about the metadata of the
167
- // class that might require dynamic initialization or resilient
168
- // access patterns:
169
-
170
- // Does the class or any of its superclasses have stored properties that
171
- // where dropped due to the Swift language version availability of
172
- // their types?
173
- bool ClassHasMissingMembers = false ;
174
-
175
- // Does the class or any of its fragile superclasses have stored
176
- // properties of unknown size, which do *not* depend on generic
177
- // parameters?
178
- //
179
- // This is different from the class itself being resilient or
180
- // having resilient ancestry, because we still have a fixed layout
181
- // for the class metadata in this case.
182
- //
183
- // In fact, for a class with resilient ancestry, this can still be
184
- // false if all of the fields known to us are fixed size.
185
- bool ClassHasResilientMembers = false ;
186
-
187
- // Is this class or any of its superclasses generic?
188
- bool ClassHasGenericAncestry = false ;
189
-
190
- // Is this class itself generic via the Swift generic system, ie. not a
191
- // lightweight Objective-C generic class?
192
- bool ClassIsGeneric = false ;
193
-
194
- // Does the class layout depend on the size or alignment of its
195
- // generic parameters?
196
- //
197
- // This can be the case if the class has generic resilient ancestry
198
- // that depends on the class's generic parameters, of it it has
199
- // fields of generic type that are not fixed size.
200
- bool ClassHasGenericLayout = false ;
201
-
202
- // Is this class or any of its superclasses resilient from the viewpoint
203
- // of the current module? This means that their metadata can change size,
204
- // hence field offsets, generic arguments and virtual methods must be
205
- // accessed relative to a metadata base global variable.
206
- bool ClassHasResilientAncestry = false ;
207
-
208
- // Are any of this class's superclasses defined in Objective-C?
209
- // This means that field offsets must be loaded from field offset globals
210
- // or the field offset vector in the metadata, and the Objective-C runtime
211
- // will slide offsets based on the actual superclass size, which is not
212
- // known at compile time.
213
- bool ClassHasObjCAncestry = false ;
166
+ ClassMetadataOptions Options;
214
167
215
168
public:
216
169
ClassLayoutBuilder (IRGenModule &IGM, SILType classType,
@@ -243,7 +196,7 @@ namespace {
243
196
assert (theClass);
244
197
245
198
if (theClass->isGenericContext () && !theClass->hasClangNode ())
246
- ClassIsGeneric = true ;
199
+ Options |= ClassMetadataFlags::ClassIsGeneric ;
247
200
248
201
addFieldsForClass (theClass, classType, /* superclass=*/ false );
249
202
@@ -261,42 +214,15 @@ namespace {
261
214
return Elements;
262
215
}
263
216
264
- // / Do instances of the class have a completely known, static layout?
265
- bool isFixedSize () const {
266
- return !(ClassHasMissingMembers ||
267
- ClassHasResilientMembers ||
268
- ClassHasGenericLayout ||
269
- ClassHasObjCAncestry);
270
- }
271
-
272
- bool doesMetadataRequireInitialization () const {
273
- return (ClassHasMissingMembers ||
274
- ClassHasResilientMembers ||
275
- ClassHasResilientAncestry ||
276
- ClassHasGenericAncestry ||
277
- IGM.getOptions ().LazyInitializeClassMetadata );
278
- }
279
-
280
- bool doesMetadataRequireRelocation () const {
281
- return (ClassHasResilientAncestry ||
282
- ClassIsGeneric);
283
- }
284
-
285
217
ClassLayout getClassLayout (llvm::Type *classTy) const {
286
218
assert (!TailTypes);
287
219
288
220
auto allStoredProps = IGM.Context .AllocateCopy (AllStoredProperties);
289
221
auto allFieldAccesses = IGM.Context .AllocateCopy (AllFieldAccesses);
290
222
auto allElements = IGM.Context .AllocateCopy (Elements);
291
223
292
- return ClassLayout (*this ,
293
- isFixedSize (),
294
- doesMetadataRequireInitialization (),
295
- doesMetadataRequireRelocation (),
296
- classTy,
297
- allStoredProps,
298
- allFieldAccesses,
299
- allElements);
224
+ return ClassLayout (*this , Options, classTy,
225
+ allStoredProps, allFieldAccesses, allElements);
300
226
}
301
227
302
228
private:
@@ -320,7 +246,7 @@ namespace {
320
246
void addFieldsForClass (ClassDecl *theClass, SILType classType,
321
247
bool superclass) {
322
248
if (theClass->hasClangNode ()) {
323
- ClassHasObjCAncestry = true ;
249
+ Options |= ClassMetadataFlags::ClassHasObjCAncestry ;
324
250
return ;
325
251
}
326
252
@@ -330,18 +256,18 @@ namespace {
330
256
assert (superclassType && superclassDecl);
331
257
332
258
if (IGM.hasResilientMetadata (superclassDecl, ResilienceExpansion::Maximal))
333
- ClassHasResilientAncestry = true ;
259
+ Options |= ClassMetadataFlags::ClassHasResilientAncestry ;
334
260
335
261
// If the superclass has resilient storage, don't walk its fields.
336
262
if (IGM.isResilient (superclassDecl, ResilienceExpansion::Maximal)) {
337
- ClassHasResilientMembers = true ;
263
+ Options |= ClassMetadataFlags::ClassHasResilientMembers ;
338
264
339
265
// If the superclass is generic, we have to assume that its layout
340
266
// depends on its generic parameters. But this only propagates down to
341
267
// subclasses whose superclass type depends on the subclass's generic
342
268
// context.
343
269
if (superclassType.hasArchetype ())
344
- ClassHasGenericLayout = true ;
270
+ Options |= ClassMetadataFlags::ClassHasGenericLayout ;
345
271
} else {
346
272
// Otherwise, we are allowed to have total knowledge of the superclass
347
273
// fields, so walk them to compute the layout.
@@ -350,16 +276,16 @@ namespace {
350
276
}
351
277
352
278
if (theClass->isGenericContext ())
353
- ClassHasGenericAncestry = true ;
279
+ Options |= ClassMetadataFlags::ClassHasGenericAncestry ;
354
280
355
281
if (classHasIncompleteLayout (IGM, theClass))
356
- ClassHasMissingMembers = true ;
282
+ Options |= ClassMetadataFlags::ClassHasMissingMembers ;
357
283
358
284
if (IGM.hasResilientMetadata (theClass, ResilienceExpansion::Maximal))
359
- ClassHasResilientAncestry = true ;
285
+ Options |= ClassMetadataFlags::ClassHasResilientAncestry ;
360
286
361
287
if (IGM.isResilient (theClass, ResilienceExpansion::Maximal)) {
362
- ClassHasResilientMembers = true ;
288
+ Options |= ClassMetadataFlags::ClassHasResilientMembers ;
363
289
return ;
364
290
}
365
291
@@ -382,9 +308,9 @@ namespace {
382
308
383
309
if (!eltType->isFixedSize ()) {
384
310
if (type.hasArchetype ())
385
- ClassHasGenericLayout = true ;
311
+ Options |= ClassMetadataFlags::ClassHasGenericLayout ;
386
312
else
387
- ClassHasResilientMembers = true ;
313
+ Options |= ClassMetadataFlags::ClassHasResilientMembers ;
388
314
}
389
315
390
316
auto element = ElementLayout::getIncomplete (*eltType);
@@ -445,7 +371,8 @@ namespace {
445
371
// var y : AKlass = AKlass()
446
372
// var t : T?
447
373
// }
448
- if (ClassHasGenericLayout && ClassHasObjCAncestry) {
374
+ if (Options.contains (ClassMetadataFlags::ClassHasGenericLayout) &&
375
+ Options.contains (ClassMetadataFlags::ClassHasObjCAncestry)) {
449
376
for (auto &access : AllFieldAccesses) {
450
377
if (access == FieldAccess::NonConstantDirect)
451
378
access = FieldAccess::ConstantIndirect;
@@ -455,23 +382,26 @@ namespace {
455
382
}
456
383
457
384
FieldAccess getFieldAccess () {
458
- // If the layout so far has a fixed size, the field offset is known
459
- // statically.
460
- if (isFixedSize ())
461
- return FieldAccess::ConstantDirect;
462
-
463
385
// If layout so far depends on generic parameters, we have to load the
464
386
// offset from the field offset vector in class metadata.
465
- if (ClassHasGenericLayout)
387
+ if (Options. contains (ClassMetadataFlags:: ClassHasGenericLayout) )
466
388
return FieldAccess::ConstantIndirect;
467
389
468
390
// If layout so far doesn't depend on any generic parameters, but it's
469
- // nonetheless not statically known (because either a superclass
470
- // or a member type was resilient), then we can rely on the existence
391
+ // nonetheless not statically known (because either the stored property
392
+ // layout of a superclass is resilient, or one of our own members is a
393
+ // resilient value type), then we can rely on the existence
471
394
// of a global field offset variable which will be initialized by
472
395
// either the Objective-C or Swift runtime, depending on the
473
396
// class's heritage.
474
- return FieldAccess::NonConstantDirect;
397
+ if (Options.contains (ClassMetadataFlags::ClassHasMissingMembers) ||
398
+ Options.contains (ClassMetadataFlags::ClassHasResilientMembers) ||
399
+ Options.contains (ClassMetadataFlags::ClassHasObjCAncestry))
400
+ return FieldAccess::NonConstantDirect;
401
+
402
+ // If the layout so far has a fixed size, the field offset is known
403
+ // statically.
404
+ return FieldAccess::ConstantDirect;
475
405
}
476
406
};
477
407
} // end anonymous namespace
@@ -2316,6 +2246,10 @@ IRGenModule::getClassMetadataStrategy(const ClassDecl *theClass) {
2316
2246
if (fragileLayout.doesMetadataRequireInitialization ())
2317
2247
return ClassMetadataStrategy::Singleton;
2318
2248
2249
+ // If the legacy type info was sufficient to produce a fixed fragile layout,
2250
+ // but our resilient layout requires initialization, we can use the fixed
2251
+ // layout on older Objective-C runtimes, and emit an update callback for
2252
+ // newer Objective-C runtimes.
2319
2253
if (resilientLayout.doesMetadataRequireInitialization ())
2320
2254
return ClassMetadataStrategy::FixedOrUpdate;
2321
2255
0 commit comments