Skip to content

Commit 800821f

Browse files
committed
IRGen: Layout of root classes containing resiliently-sized fields
Now that all the machinery is in place, the ClassMetadataBuilder can (more accurately) query the ClassLayout instead of trying to re-derive whether the field offset vector is dependent, etc. Apart from performing dynamic layout for resiliently-sized fields in concrete classes, this also lets us *skip* dynamic layout if we have a generic class without any dependent fields. I haven't tested subclassing with resilient field layout yet, but getting that working is the next step and should not be too much work. Also, swift_initClassMetadata_UniversalStrategy() only stores the computed field offsets in the field offset globals when the Objective-C runtime is available, because it gets the offset pointers from the Objective-C class rodata. On Linux, we will need to emit code to copy from the field offset vector into field offset globals in IRGen. This is pretty easy, but I'll do it in a follow-up patch so for now the new execution test is XFAIL'd on Linux.
1 parent 64cd87d commit 800821f

9 files changed

+338
-86
lines changed

lib/IRGen/ClassMetadataLayout.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,11 @@ template <class Impl> class ClassMetadataLayout : public MetadataLayout<Impl> {
8484
// consistent metadata layout between generic superclasses and concrete
8585
// subclasses.
8686
if (Type superclass = theClass->getSuperclass()) {
87+
ClassDecl *superclassDecl = superclass->getClassOrBoundGenericClass();
8788
// Skip superclass fields if superclass is resilient.
8889
// FIXME: Needs runtime support to ensure the field offset vector is
8990
// populated correctly.
90-
if (!IGM.isResilient(superclass->getClassOrBoundGenericClass(),
91-
ResilienceScope::Component)) {
91+
if (!IGM.isResilient(superclassDecl, ResilienceScope::Component)) {
9292
addClassMembers(superclass->getClassOrBoundGenericClass());
9393
}
9494
}

lib/IRGen/GenClass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ namespace {
254254
// If the superclass is in a generic context, conservatively
255255
// assume the layout depends on generic parameters, since we
256256
// can't look at stored properties.
257-
if (superclass->isGenericContext())
257+
if (superclassType.hasArchetype())
258258
ClassHasConcreteLayout = false;
259259
} else {
260260
// Otherwise, we have total knowledge of the class and its

lib/IRGen/GenMeta.cpp

Lines changed: 32 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -188,32 +188,19 @@ static bool hasMetadataPattern(IRGenModule &IGM, NominalTypeDecl *theDecl) {
188188
// Protocols must be special-cased in a few places.
189189
assert(!isa<ProtocolDecl>(theDecl));
190190

191-
// Classes imported from Objective-C never have a metadata pattern.
192-
if (theDecl->hasClangNode())
193-
return false;
194-
195-
// A generic class, struct, or enum is always initialized at runtime.
191+
// For classes, we already computed this when we did the layout.
192+
// FIXME: Try not to call this for classes of other modules, by referencing
193+
// the metadata accessor instead.
194+
if (auto *theClass = dyn_cast<ClassDecl>(theDecl))
195+
return getClassHasMetadataPattern(IGM, theClass);
196+
197+
// Ok, we have a value type. If it is generic, it is always initialized
198+
// at runtime.
196199
if (theDecl->isGenericContext())
197200
return true;
198201

199-
// A class with generic ancestry is always initialized at runtime.
200-
// TODO: This should be cached in the ClassDecl since it is checked for in
201-
// several places.
202-
if (auto *theClass = dyn_cast<ClassDecl>(theDecl)) {
203-
Type superclassTy = theClass->getSuperclass();
204-
while (superclassTy) {
205-
if (superclassTy->getClassOrBoundGenericClass()->isGenericContext())
206-
return true;
207-
superclassTy = superclassTy->getSuperclass(nullptr);
208-
}
209-
210-
// TODO: check if class fields are resilient. Fixed-size check for value
211-
// types isn't meaningful here.
212-
return false;
213-
}
214-
215-
// If we have fields of resilient type, the metadata still has to be
216-
// initialized at runtime.
202+
// If the type is not fixed-size, its size depends on resilient types,
203+
// and the metadata is initialized at runtime.
217204
if (!IGM.getTypeInfoForUnlowered(theDecl->getDeclaredType()).isFixedSize())
218205
return true;
219206

@@ -2864,6 +2851,7 @@ namespace {
28642851
}
28652852

28662853
bool HasRuntimeParent = false;
2854+
28672855
public:
28682856
/// The 'metadata flags' field in a class is actually a pointer to
28692857
/// the metaclass object for the class.
@@ -3140,7 +3128,15 @@ namespace {
31403128
ClassMetadataBuilder(IRGenModule &IGM, ClassDecl *theClass,
31413129
const StructLayout &layout,
31423130
const ClassLayout &fieldLayout)
3143-
: ClassMetadataBuilderBase(IGM, theClass, layout, fieldLayout) {}
3131+
: ClassMetadataBuilderBase(IGM, theClass, layout, fieldLayout) {
3132+
3133+
assert(layout.isFixedLayout() &&
3134+
"non-fixed layout classes require a template");
3135+
// FIXME: Distinguish Objective-C sliding from resilient layout
3136+
assert((fieldLayout.MetadataAccess == FieldAccess::ConstantDirect ||
3137+
fieldLayout.MetadataAccess == FieldAccess::NonConstantDirect) &&
3138+
"resilient superclasses require a template");
3139+
}
31443140

31453141
llvm::Constant *getInit() {
31463142
return getInitWithSuggestedType(NumHeapMetadataFields,
@@ -3202,11 +3198,6 @@ namespace {
32023198
{
32033199
typedef GenericMetadataBuilderBase super;
32043200

3205-
bool HasDependentFieldOffsetVector = false;
3206-
3207-
bool InheritFieldOffsetVectors = false;
3208-
bool InheritGenericParameters = false;
3209-
32103201
Size MetaclassPtrOffset = Size::invalid();
32113202
Size ClassRODataPtrOffset = Size::invalid();
32123203
Size MetaclassRODataPtrOffset = Size::invalid();
@@ -3305,26 +3296,9 @@ namespace {
33053296

33063297
void noteStartOfFieldOffsets(ClassDecl *whichClass) {
33073298
HasDependentMetadata = true;
3308-
3309-
if (whichClass == Target) {
3310-
// If the metadata contains a field offset vector for the class itself,
3311-
// then we need to initialize it at runtime.
3312-
HasDependentFieldOffsetVector = true;
3313-
return;
3314-
}
3315-
3316-
// If we have a field offset vector for an ancestor class, we will copy
3317-
// it from our superclass metadata at instantiation time.
3318-
InheritFieldOffsetVectors = true;
33193299
}
33203300

3321-
void noteEndOfFieldOffsets(ClassDecl *whichClass) {
3322-
if (whichClass == Target)
3323-
return;
3324-
3325-
assert(InheritFieldOffsetVectors
3326-
&& "no start of ancestor field offsets?!");
3327-
}
3301+
void noteEndOfFieldOffsets(ClassDecl *whichClass) {}
33283302

33293303
// Suppress GenericMetadataBuilderBase's default behavior of introducing
33303304
// fill ops for generic arguments unless they belong directly to the target
@@ -3338,7 +3312,6 @@ namespace {
33383312
// Lay out the field, but don't fill it in, we will copy it from
33393313
// the superclass.
33403314
HasDependentMetadata = true;
3341-
InheritGenericParameters = true;
33423315
ClassMetadataBuilderBase::addGenericArgument(type, forClass);
33433316
}
33443317
}
@@ -3353,7 +3326,6 @@ namespace {
33533326
// Lay out the field, but don't provide the fill op, which we'll get
33543327
// from the superclass.
33553328
HasDependentMetadata = true;
3356-
InheritGenericParameters = true;
33573329
ClassMetadataBuilderBase::addGenericWitnessTable(type, protocol,
33583330
forClass);
33593331
}
@@ -3446,15 +3418,13 @@ namespace {
34463418
IGF.Builder.CreateStore(rodata, rodataPtrSlot);
34473419
}
34483420

3449-
// If the field layout is dependent, ask the runtime to populate the
3450-
// offset vector.
3421+
// If we have fields that are not fixed-size, ask the runtime to
3422+
// populate the offset vector.
34513423
//
3452-
// FIXME: the right check here is if the class layout is dependent or
3453-
// resilient. Also if only the superclass is resilient, we can get away
3424+
// FIXME: if only the superclass is resilient, we can get away
34543425
// with sliding field offsets instead of doing the entire layout all
34553426
// over again.
3456-
if (Target->isGenericContext() &&
3457-
HasDependentFieldOffsetVector) {
3427+
if (!Layout.isFixedLayout()) {
34583428
llvm::Value *fieldVector
34593429
= emitAddressOfFieldOffsetVectorInClassMetadata(IGF,
34603430
Target, metadata)
@@ -3505,18 +3475,19 @@ namespace {
35053475
{metadata, numFields,
35063476
firstField.getAddress(), fieldVector});
35073477

3508-
} else if (InheritFieldOffsetVectors || InheritGenericParameters) {
3478+
} else {
35093479
// If we have any ancestor generic parameters or field offset vectors,
35103480
// copy them from the superclass metadata.
35113481
auto initFn = IGF.IGM.getInitializeSuperclassFn();
3482+
3483+
bool copyFieldOffsetVectors = false;
3484+
if (FieldLayout.MetadataAccess != FieldAccess::ConstantDirect)
3485+
copyFieldOffsetVectors = true;
3486+
35123487
IGF.Builder.CreateCall(initFn,
35133488
{metadata,
35143489
llvm::ConstantInt::get(IGF.IGM.Int1Ty,
3515-
InheritFieldOffsetVectors)});
3516-
} else if (IGF.IGM.ObjCInterop) {
3517-
// Register the class with the ObjC runtime.
3518-
llvm::Value *instantiateObjC = IGF.IGM.getInstantiateObjCClassFn();
3519-
IGF.Builder.CreateCall(instantiateObjC, metadata);
3490+
copyFieldOffsetVectors)});
35203491
}
35213492
}
35223493

0 commit comments

Comments
 (0)