Skip to content

Commit d6bbf81

Browse files
authored
Merge pull request #13612 from slavapestov/class-resilience-part-8
Class resilience part 8
2 parents 810bc89 + 2df1b0a commit d6bbf81

File tree

9 files changed

+112
-88
lines changed

9 files changed

+112
-88
lines changed

lib/IRGen/GenClass.cpp

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,6 @@ namespace {
170170
// - or has a field with resilient layout.
171171
bool ClassMetadataRequiresDynamicInitialization = false;
172172

173-
// Does the superclass have a fixed number of stored properties?
174-
// If not, and the class has generally-dependent layout, we have to
175-
// access stored properties through an indirect offset into the field
176-
// offset vector.
177-
bool ClassHasFixedFieldCount = true;
178-
179173
// Does the class have a fixed size up until the current point?
180174
// If not, we have to access stored properties either ivar offset globals,
181175
// or through the field offset vector, based on whether the layout has
@@ -304,9 +298,7 @@ namespace {
304298
//
305299
// FIXME: We need to implement indirect field/vtable entry access
306300
// before we can enable this
307-
if (IGM.Context.LangOpts.EnableClassResilience) {
308-
ClassHasFixedFieldCount = false;
309-
} else {
301+
if (!IGM.Context.LangOpts.EnableClassResilience) {
310302
addFieldsForClass(superclass, superclassType);
311303
NumInherited = Elements.size();
312304
}
@@ -405,16 +397,7 @@ namespace {
405397

406398
// If layout depends on generic parameters, we have to load the
407399
// offset from the class metadata.
408-
409-
// If the layout of the class metadata is statically known, then
410-
// there should be a fixed offset to the right offset.
411-
if (ClassHasFixedFieldCount) {
412-
return FieldAccess::ConstantIndirect;
413-
}
414-
415-
// Otherwise, the offset of the offset is stored in a global variable
416-
// that will be set up by the runtime.
417-
return FieldAccess::NonConstantIndirect;
400+
return FieldAccess::ConstantIndirect;
418401
}
419402
};
420403
} // end anonymous namespace

lib/IRGen/GenMeta.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2825,8 +2825,7 @@ namespace {
28252825

28262826
// Execute the fill ops. Cast the parameters to word pointers because the
28272827
// fill indexes are word-indexed.
2828-
Address metadataWords(IGF.Builder.CreateBitCast(metadataValue, IGM.Int8PtrPtrTy),
2829-
IGM.getPointerAlignment());
2828+
auto *metadataWords = IGF.Builder.CreateBitCast(metadataValue, IGM.Int8PtrPtrTy);
28302829

28312830
auto genericReqtOffset = IGM.getMetadataLayout(Target)
28322831
.getGenericRequirementsOffset(IGF);
@@ -2839,13 +2838,15 @@ namespace {
28392838
value = IGF.emitTypeMetadataRef(fillOp.Type);
28402839
}
28412840

2842-
auto dest = createPointerSizedGEP(IGF, metadataWords,
2843-
genericReqtOffset.getStatic());
2844-
genericReqtOffset = genericReqtOffset.offsetBy(
2845-
IGF, IGM.getPointerSize());
2841+
auto dest = IGF.emitAddressAtOffset(metadataWords, genericReqtOffset,
2842+
IGM.Int8PtrTy,
2843+
IGM.getPointerAlignment());
28462844

28472845
value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy);
28482846
IGF.Builder.CreateStore(value, dest);
2847+
2848+
genericReqtOffset = genericReqtOffset.offsetBy(
2849+
IGF, IGM.getPointerSize());
28492850
}
28502851

28512852
// A dependent VWT means that we have dependent metadata.

lib/IRGen/MetadataLayout.cpp

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class LayoutScanner : public Base<Impl> {
4444
Optional<Size> AddressPoint;
4545

4646
protected:
47+
Optional<Size> DynamicOffsetBase;
48+
4749
template <class... As>
4850
LayoutScanner(As &&... args) : Base<Impl>(std::forward<As>(args)...) {}
4951

@@ -52,7 +54,13 @@ class LayoutScanner : public Base<Impl> {
5254

5355
void noteAddressPoint() { AddressPoint = this->NextOffset; }
5456
StoredOffset getNextOffset() const {
55-
return StoredOffset(this->NextOffset - AddressPoint.getValue());
57+
if (DynamicOffsetBase) {
58+
return StoredOffset(this->NextOffset - *DynamicOffsetBase,
59+
StoredOffset::Dynamic);
60+
}
61+
62+
return StoredOffset(this->NextOffset - *AddressPoint,
63+
StoredOffset::Static);
5664
}
5765

5866
Size getAddressPoint() const {
@@ -126,18 +134,38 @@ void MetadataLayout::destroy() const {
126134

127135
/******************************* NOMINAL TYPES ********************************/
128136

137+
Offset NominalMetadataLayout::emitOffset(IRGenFunction &IGF,
138+
StoredOffset offset) const {
139+
assert(offset.isValid());
140+
141+
if (offset.isStatic())
142+
return Offset(offset.getStaticOffset());
143+
144+
Address offsetBaseAddr(
145+
IGF.IGM.getAddrOfClassMetadataBaseOffset(cast<ClassDecl>(getDecl()),
146+
NotForDefinition),
147+
IGF.IGM.getPointerAlignment());
148+
149+
// FIXME: Should this be an invariant load?
150+
auto *offsetBaseVal =
151+
IGF.Builder.CreateLoad(offsetBaseAddr, "base");
152+
153+
auto relativeOffset = offset.getRelativeOffset().getValue();
154+
auto *offsetVal =
155+
IGF.Builder.CreateAdd(offsetBaseVal,
156+
llvm::ConstantInt::get(IGF.IGM.SizeTy,
157+
relativeOffset));
158+
return Offset(offsetVal);
159+
}
160+
129161
Size
130162
NominalMetadataLayout::getStaticGenericRequirementsOffset() const {
131-
assert(GenericRequirements.isValid());
132-
assert(GenericRequirements.isStatic() && "resilient metadata layout unsupported!");
133163
return GenericRequirements.getStaticOffset();
134164
}
135165

136166
Offset
137167
NominalMetadataLayout::getGenericRequirementsOffset(IRGenFunction &IGF) const {
138-
assert(GenericRequirements.isValid());
139-
assert(GenericRequirements.isStatic() && "resilient metadata layout unsupported!");
140-
return Offset(GenericRequirements.getStaticOffset());
168+
return emitOffset(IGF, GenericRequirements);
141169
}
142170

143171
static llvm::Value *emitLoadOfGenericRequirement(IRGenFunction &IGF,
@@ -315,11 +343,7 @@ Size ClassMetadataLayout::getInstanceAlignMaskOffset() const {
315343
ClassMetadataLayout::MethodInfo
316344
ClassMetadataLayout::getMethodInfo(IRGenFunction &IGF, SILDeclRef method) const{
317345
auto &stored = getStoredMethodInfo(method);
318-
319-
assert(stored.TheOffset.isStatic() &&
320-
"resilient class metadata layout unsupported!");
321-
auto offset = Offset(stored.TheOffset.getStaticOffset());
322-
346+
auto offset = emitOffset(IGF, stored.TheOffset);
323347
return MethodInfo(offset);
324348
}
325349

@@ -331,45 +355,50 @@ Size ClassMetadataLayout::getStaticMethodOffset(SILDeclRef method) const{
331355
return stored.TheOffset.getStaticOffset();
332356
}
333357

334-
Size
335-
ClassMetadataLayout::getStaticVTableOffset() const {
336-
// TODO: if class is resilient, return the offset relative to the start
337-
// of immediate class metadata
338-
assert(VTableOffset.isStatic());
339-
return VTableOffset.getStaticOffset();
340-
}
341-
342358
Offset
343359
ClassMetadataLayout::getVTableOffset(IRGenFunction &IGF) const {
344-
// TODO: implement resilient metadata layout
345-
assert(VTableOffset.isStatic());
346-
return Offset(VTableOffset.getStaticOffset());
360+
return emitOffset(IGF, VTableOffset);
347361
}
348362

349363
Offset ClassMetadataLayout::getFieldOffset(IRGenFunction &IGF,
350364
VarDecl *field) const {
351-
// TODO: implement resilient metadata layout
352-
return Offset(getStaticFieldOffset(field));
365+
return emitOffset(IGF, getStoredFieldOffset(field));
353366
}
367+
354368
Size ClassMetadataLayout::getStaticFieldOffset(VarDecl *field) const {
355369
auto &stored = getStoredFieldOffset(field);
356370
assert(stored.isStatic() && "resilient class metadata layout unsupported!");
357371
return stored.getStaticOffset();
358372
}
359373

374+
Size
375+
ClassMetadataLayout::getRelativeGenericRequirementsOffset() const {
376+
return GenericRequirements.getRelativeOffset();
377+
}
378+
360379
Size
361380
ClassMetadataLayout::getStaticFieldOffsetVectorOffset() const {
362-
// TODO: if class is resilient, return the offset relative to the start
363-
// of immediate class metadata
364-
assert(FieldOffsetVector.isStatic());
365381
return FieldOffsetVector.getStaticOffset();
366382
}
367383

384+
Size
385+
ClassMetadataLayout::getRelativeFieldOffsetVectorOffset() const {
386+
return FieldOffsetVector.getRelativeOffset();
387+
}
388+
389+
Size
390+
ClassMetadataLayout::getStaticVTableOffset() const {
391+
return VTableOffset.getStaticOffset();
392+
}
393+
394+
Size
395+
ClassMetadataLayout::getRelativeVTableOffset() const {
396+
return VTableOffset.getRelativeOffset();
397+
}
398+
368399
Offset
369400
ClassMetadataLayout::getFieldOffsetVectorOffset(IRGenFunction &IGF) const {
370-
// TODO: implement resilient metadata layout
371-
assert(FieldOffsetVector.isStatic());
372-
return Offset(FieldOffsetVector.getStaticOffset());
401+
return emitOffset(IGF, FieldOffsetVector);
373402
}
374403

375404
Size irgen::getClassFieldOffsetOffset(IRGenModule &IGM, ClassDecl *theClass,
@@ -390,8 +419,8 @@ llvm::Value *irgen::emitClassFieldOffset(IRGenFunction &IGF,
390419

391420
Address irgen::emitAddressOfClassFieldOffset(IRGenFunction &IGF,
392421
llvm::Value *metadata,
393-
ClassDecl *theClass,
394-
VarDecl *field) {
422+
ClassDecl *theClass,
423+
VarDecl *field) {
395424
auto offset = IGF.IGM.getMetadataLayout(theClass).getFieldOffset(IGF, field);
396425
auto slot = IGF.emitAddressAtOffset(metadata, offset, IGF.IGM.SizeTy,
397426
IGF.IGM.getPointerAlignment());

lib/IRGen/MetadataLayout.h

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,19 @@ class MetadataLayout {
5454
};
5555

5656
class StoredOffset {
57-
enum State {
57+
public:
58+
enum Kind {
5859
/// The high bits are an integer displacement.
5960
Static = 0,
6061

61-
/// The high bits are an llvm::Constant* for the displacement,
62-
/// which may be null if it hasn't been computed yet.
62+
/// The high bits are an integer displacement relative to a offset stored
63+
/// in a class metadata base offset global variable. This is used to
64+
/// access members of class metadata where the superclass is resilient to
65+
/// us, and therefore has an unknown size.
6366
Dynamic,
6467
};
68+
69+
private:
6570
enum : uint64_t {
6671
KindBits = 1,
6772
KindMask = (1 << KindBits) - 1,
@@ -71,29 +76,33 @@ class MetadataLayout {
7176
mutable uintptr_t Data;
7277
public:
7378
StoredOffset() : Data(0) {}
74-
explicit StoredOffset(llvm::Constant *offset)
75-
: Data(reinterpret_cast<uintptr_t>(offset) | Dynamic) {}
76-
explicit StoredOffset(Size offset)
77-
: Data((static_cast<uint64_t>(offset.getValue()) << KindBits) | Static) {
78-
assert(!offset.isZero() && "cannot store a zero offset");
79-
assert(getStaticOffset() == offset && "overflow");
79+
explicit StoredOffset(Size offset, Kind kind)
80+
: Data((static_cast<uint64_t>(offset.getValue()) << KindBits) | kind) {
81+
assert(kind == Kind::Dynamic || !offset.isZero() &&
82+
"cannot store a zero static offset");
83+
if (kind == Kind::Static)
84+
assert(getStaticOffset() == offset && "overflow");
85+
if (kind == Kind::Dynamic)
86+
assert(getRelativeOffset() == offset && "overflow");
8087
}
8188

8289
bool isValid() const { return Data != 0; }
8390
bool isStatic() const { return isValid() && (Data & KindMask) == Static; }
8491
bool isDynamic() const { return (Data & KindMask) == Dynamic; }
92+
93+
/// If this is a metadata offset into a resilient class, returns the offset
94+
/// relative to the size of the superclass metadata.
95+
Size getRelativeOffset() const {
96+
assert(isDynamic());
97+
return Size(static_cast<int64_t>(Data) >> KindBits);
98+
}
99+
100+
/// Returns the offset relative to start of metadata. Only used for
101+
/// metadata fields whose offset is completely known at compile time.
85102
Size getStaticOffset() const {
86103
assert(isStatic());
87104
return Size(static_cast<int64_t>(Data) >> KindBits);
88105
}
89-
llvm::Constant *getDynamicOffsetVariable() const {
90-
assert(isDynamic());
91-
return reinterpret_cast<llvm::Constant*>(Data & PayloadMask);
92-
}
93-
void setDynamicOffsetVariable(llvm::Constant *pointer) const {
94-
assert(isDynamic());
95-
Data = reinterpret_cast<uintptr_t>(pointer) | Dynamic;
96-
}
97106
};
98107

99108
private:
@@ -125,6 +134,8 @@ class NominalMetadataLayout : public MetadataLayout {
125134
NominalMetadataLayout(Kind kind, NominalTypeDecl *nominal)
126135
: MetadataLayout(kind), Nominal(nominal) {}
127136

137+
Offset emitOffset(IRGenFunction &IGF, StoredOffset offset) const;
138+
128139
public:
129140
NominalTypeDecl *getDecl() const {
130141
return Nominal;
@@ -205,9 +216,6 @@ class ClassMetadataLayout : public NominalMetadataLayout {
205216

206217
Size getInstanceAlignMaskOffset() const;
207218

208-
/// Should only be used when emitting the nominal type descriptor.
209-
Size getStaticVTableOffset() const;
210-
211219
/// Returns the start of the vtable in the class metadata.
212220
Offset getVTableOffset(IRGenFunction &IGF) const;
213221

@@ -235,7 +243,13 @@ class ClassMetadataLayout : public NominalMetadataLayout {
235243
Size getStaticFieldOffset(VarDecl *field) const;
236244

237245
/// Should only be used when emitting the nominal type descriptor.
246+
Size getRelativeGenericRequirementsOffset() const;
247+
238248
Size getStaticFieldOffsetVectorOffset() const;
249+
Size getRelativeFieldOffsetVectorOffset() const;
250+
251+
Size getStaticVTableOffset() const;
252+
Size getRelativeVTableOffset() const;
239253

240254
Offset getFieldOffsetVectorOffset(IRGenFunction &IGF) const;
241255

test/IRGen/class_resilience.swift

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
// CHECK: @_T016class_resilience33ClassWithResilientlySizedPropertyC5colors5Int32VvpWvd = {{(protected )?}}global [[INT]] 0
1515

1616
// CHECK: @_T016class_resilience14ResilientChildC5fields5Int32VvpWvd = {{(protected )?}}global [[INT]] {{8|16}}
17-
// CHECK: @_T016class_resilience21ResilientGenericChildC5fields5Int32VvpWvi = {{(protected )?}}global [[INT]] {{56|88}}
1817

1918
// CHECK: @_T016class_resilience26ClassWithResilientPropertyCMo = {{(protected )?}}constant [[INT]] {{52|80}}
2019

@@ -231,10 +230,8 @@ public class MyResilientChild : MyResilientParent {
231230

232231
// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds %T16class_resilience21ResilientGenericChildC, %T16class_resilience21ResilientGenericChildC* %0, i32 0, i32 0, i32 0
233232
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ADDR]]
234-
// CHECK-NEXT: [[INDIRECT_OFFSET:%.*]] = load [[INT]], [[INT]]* @_T016class_resilience21ResilientGenericChildC5fields5Int32VvpWvi
235-
// CHECK-NEXT: [[ISA_ADDR:%.*]] = bitcast %swift.type* [[ISA]] to i8*
236-
// CHECK-NEXT: [[FIELD_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[ISA_ADDR]], [[INT]] [[INDIRECT_OFFSET]]
237-
// CHECK-NEXT: [[FIELD_OFFSET_ADDR:%.*]] = bitcast i8* [[FIELD_OFFSET_TMP]] to [[INT]]*
233+
// CHECK-NEXT: [[ISA_ADDR:%.*]] = bitcast %swift.type* [[ISA]] to [[INT]]*
234+
// CHECK-NEXT: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[ISA_ADDR]], [[INT]] {{11|14}}
238235
// CHECK-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_ADDR:%.*]]
239236
// CHECK-NEXT: [[OBJECT:%.*]] = bitcast %T16class_resilience21ResilientGenericChildC* %0 to i8*
240237
// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds i8, i8* [[OBJECT]], [[INT]] [[FIELD_OFFSET]]

test/IRGen/enum.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2693,7 +2693,7 @@ entry(%x : $*MyOptional):
26932693
// CHECK: [[T:%T]] = load %swift.type*, %swift.type** [[T0]],
26942694
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1)
26952695
// CHECK: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
2696-
// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 2
2696+
// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], [[WORD]] 2
26972697
// CHECK: [[T0:%.*]] = bitcast %swift.type* [[T]] to i8*
26982698
// CHECK: store i8* [[T0]], i8** [[T1]]
26992699
// CHECK: [[T_VWTS:%.*]] = bitcast %swift.type* [[T]] to i8***

test/IRGen/generic_classes.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,10 +324,10 @@ entry(%c : $RootGeneric<Int32>):
324324
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[T0]], i64 6)
325325
// CHECK: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
326326
// Put the generic arguments in their correct positions.
327-
// CHECK: [[A_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i32 18
327+
// CHECK: [[A_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i64 18
328328
// CHECK: [[T0:%.*]] = bitcast %swift.type* %A to i8*
329329
// CHECK: store i8* [[T0]], i8** [[A_ADDR]], align 8
330-
// CHECK: [[B_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i32 19
330+
// CHECK: [[B_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i64 19
331331
// CHECK: [[T0:%.*]] = bitcast %swift.type* %B to i8*
332332
// CHECK: store i8* [[T0]], i8** [[B_ADDR]], align 8
333333
// Set up the isa.

test/IRGen/generic_structs.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ entry(%0 : $*ComplexDynamic<A, B>, %1 : $*Byteful, %2 : $*A, %3 : $*B, %4 : $*Ch
214214
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1)
215215
// CHECK: [[SELF_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
216216
// Fill type argument.
217-
// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 3
217+
// CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i64 3
218218
// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8*
219219
// CHECK: store i8* [[T0]], i8** [[T1]], align 8
220220
// Lay out fields.

0 commit comments

Comments
 (0)