Skip to content

Commit 0103cf6

Browse files
committed
IRGen: Use dynamic offsets in resilient class metadata
1 parent 829be3d commit 0103cf6

File tree

4 files changed

+119
-18
lines changed

4 files changed

+119
-18
lines changed

lib/IRGen/GenMeta.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,6 +2192,8 @@ namespace {
21922192
auto &layout = IGM.getMetadataLayout(cd);
21932193
if (layout.getVTableSize() > 0)
21942194
flags = flags.withHasVTable(true);
2195+
if (layout.hasResilientSuperclass())
2196+
flags = flags.withHasResilientSuperclass(true);
21952197
}
21962198

21972199
// Calculate the number of generic parameters at each nesting depth.
@@ -2427,13 +2429,19 @@ namespace {
24272429
: super(IGM), Target(c)
24282430
{
24292431
auto &layout = IGM.getMetadataLayout(Target);
2430-
FieldVectorOffset = layout.getStaticFieldOffsetVectorOffset();
2431-
GenericParamsOffset = layout.getStaticGenericRequirementsOffset();
24322432

24332433
VTable = IGM.getSILModule().lookUpVTable(Target);
2434-
2435-
VTableOffset = layout.getStaticVTableOffset();
24362434
VTableSize = layout.getVTableSize();
2435+
2436+
if (layout.hasResilientSuperclass()) {
2437+
FieldVectorOffset = layout.getRelativeFieldOffsetVectorOffset();
2438+
GenericParamsOffset = layout.getRelativeGenericRequirementsOffset();
2439+
VTableOffset = layout.getRelativeVTableOffset();
2440+
} else {
2441+
FieldVectorOffset = layout.getStaticFieldOffsetVectorOffset();
2442+
GenericParamsOffset = layout.getStaticGenericRequirementsOffset();
2443+
VTableOffset = layout.getStaticVTableOffset();
2444+
}
24372445
}
24382446

24392447
ClassDecl *getTarget() { return Target; }

lib/IRGen/MetadataLayout.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,26 @@ ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl)
238238
using super = LayoutScanner;
239239

240240
ClassMetadataLayout &Layout;
241+
241242
Scanner(IRGenModule &IGM, ClassDecl *decl, ClassMetadataLayout &layout)
242243
: super(IGM, decl), Layout(layout) {}
243244

244-
void noteResilientSuperclass() {}
245+
void noteResilientSuperclass() {
246+
Layout.HasResilientSuperclass = true;
247+
}
245248

246-
void noteStartOfImmediateMembers(ClassDecl *theClass) {}
249+
void noteStartOfImmediateMembers(ClassDecl *forClass) {
250+
// If our superclass is resilient to us, or the class itself is resilient
251+
// to us, we will access metadata members relative to a base offset.
252+
if (forClass == Target) {
253+
if (Layout.HasResilientSuperclass ||
254+
(IGM.Context.LangOpts.EnableClassResilience &&
255+
IGM.isResilient(forClass, ResilienceExpansion::Maximal))) {
256+
assert(!DynamicOffsetBase);
257+
DynamicOffsetBase = NextOffset;
258+
}
259+
}
260+
}
247261

248262
void addClassSize() {
249263
Layout.MetadataSize = getNextOffset();

lib/IRGen/MetadataLayout.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ class ClassMetadataLayout : public NominalMetadataLayout {
167167
};
168168

169169
private:
170+
bool HasResilientSuperclass = false;
171+
170172
StoredOffset MetadataSize;
171173

172174
StoredOffset InstanceSize;
@@ -210,6 +212,10 @@ class ClassMetadataLayout : public NominalMetadataLayout {
210212
return cast<ClassDecl>(Nominal);
211213
}
212214

215+
bool hasResilientSuperclass() const {
216+
return HasResilientSuperclass;
217+
}
218+
213219
Size getMetadataSizeOffset() const;
214220

215221
Size getInstanceSizeOffset() const;

test/IRGen/class_resilience.swift

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
// CHECK: @_T016class_resilience14ResilientChildC5fields5Int32VvpWvd = {{(protected )?}}global [[INT]] {{8|16}}
1717

18+
// CHECK: @_T016class_resilience14ResilientChildCMo = {{(protected )?}}global [[INT]] 0
19+
20+
// CHECK: @_T016class_resilience21ResilientGenericChildCMo = {{(protected )?}}global [[INT]] 0
21+
1822
// CHECK: @_T016class_resilience26ClassWithResilientPropertyCMo = {{(protected )?}}constant [[INT]] {{52|80}}
1923

2024
// CHECK: @_T016class_resilience28ClassWithMyResilientPropertyC1rAA0eF6StructVvpWvd = {{(protected )?}}constant [[INT]] {{8|16}}
@@ -23,12 +27,34 @@
2327
// CHECK: @_T016class_resilience30ClassWithIndirectResilientEnumC1s14resilient_enum10FunnyShapeOvpWvd = {{(protected )?}}constant [[INT]] {{8|16}}
2428
// CHECK: @_T016class_resilience30ClassWithIndirectResilientEnumC5colors5Int32VvpWvd = {{(protected )?}}constant [[INT]] {{12|24}}
2529

26-
// CHECK: @_T016class_resilience14ResilientChildCMo = {{(protected )?}}global [[INT]] 0
30+
// CHECK: [[RESILIENTCHILD_NAME:@.*]] = private constant [36 x i8] c"16class_resilience14ResilientChildC\00"
31+
// CHECK: [[RESILIENTCHILD_FIELDS:@.*]] = private constant [7 x i8] c"field\00\00"
32+
33+
// CHECK: @_T016class_resilience14ResilientChildCMn = {{(protected )?}}constant <{{.*}}> <{
34+
// -- name:
35+
// CHECK-SAME: [36 x i8]* [[RESILIENTCHILD_NAME]]
36+
// -- num fields
37+
// CHECK-SAME: i32 1,
38+
// -- field offset vector offset
39+
// CHECK-SAME: i32 3,
40+
// -- field names,
41+
// CHECK-SAME: [7 x i8]* [[RESILIENTCHILD_FIELDS]]
42+
// -- kind 0 (class)
43+
// CHECK-SAME: i32 0,
44+
// -- generic parameter vector offset
45+
// CHECK-SAME: i32 0,
46+
// -- generic parameter count, primary count
47+
// CHECK-SAME: i32 0, i32 0,
48+
// -- nesting depth
49+
// CHECK-SAME: i16 1,
50+
// -- flags -- has vtable, has resilient superclass
51+
// CHECK-SAME: i16 12,
52+
// -- generic parameters at depth 0
53+
// CHECK-SAME: i32 0
54+
// CHECK-SAME: }>
2755

2856
// CHECK: @_T016class_resilience16FixedLayoutChildCMo = {{(protected )?}}global [[INT]] 0
2957

30-
// CHECK: @_T016class_resilience21ResilientGenericChildCMo = {{(protected )?}}global [[INT]] 0
31-
3258
// CHECK: @_T016class_resilience17MyResilientParentCMo = {{(protected )?}}constant [[INT]] {{52|80}}
3359

3460
// CHECK: @_T016class_resilience16MyResilientChildCMo = {{(protected )?}}constant [[INT]] {{60|96}}
@@ -101,7 +127,7 @@ public class ClassWithIndirectResilientEnum {
101127
// offsets is not known at compile time
102128

103129
public class ResilientChild : ResilientOutsideParent {
104-
public let field: Int32 = 0
130+
public var field: Int32 = 0
105131
}
106132

107133
// Superclass is resilient, but the class is fixed-layout.
@@ -110,14 +136,14 @@ public class ResilientChild : ResilientOutsideParent {
110136
// global.
111137

112138
@_fixed_layout public class FixedLayoutChild : ResilientOutsideParent {
113-
public let field: Int32 = 0
139+
public var field: Int32 = 0
114140
}
115141

116142
// Superclass is resilient, so the number of fields and their
117143
// offsets is not known at compile time
118144

119145
public class ResilientGenericChild<T> : ResilientGenericOutsideParent<T> {
120-
public let field: Int32 = 0
146+
public var field: Int32 = 0
121147
}
122148

123149

@@ -134,6 +160,12 @@ public class MyResilientChild : MyResilientParent {
134160
}
135161

136162

163+
extension ResilientGenericOutsideParent {
164+
public func genericExtensionMethod() -> A.Type {
165+
return A.self
166+
}
167+
}
168+
137169
// ClassWithResilientProperty.color getter
138170

139171
// CHECK-LABEL: define{{( protected)?}} swiftcc i32 @_T016class_resilience26ClassWithResilientPropertyC5colors5Int32Vvg(%T16class_resilience26ClassWithResilientPropertyC* swiftself)
@@ -217,10 +249,35 @@ public class MyResilientChild : MyResilientParent {
217249
// CHECK-NEXT: call void @swift_endAccess
218250
// CHECK: ret i32 [[FIELD_VALUE]]
219251

252+
// ResilientChild.field getter dispatch thunk
253+
254+
// CHECK-LABEL: define{{( protected)?}} swiftcc i32 @_T016class_resilience14ResilientChildC5fields5Int32VvgTj(%T16class_resilience14ResilientChildC* swiftself)
255+
// CHECK: [[ISA_ADDR:%.*]] = getelementptr inbounds %T16class_resilience14ResilientChildC, %T16class_resilience14ResilientChildC* %0, i32 0, i32 0, i32 0
256+
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
257+
// CHECK-NEXT: [[BASE:%.*]] = load [[INT]], [[INT]]* @_T016class_resilience14ResilientChildCMo
258+
// CHECK-NEXT: [[METADATA_BYTES:%.*]] = bitcast %swift.type* [[ISA]] to i8*
259+
// CHECK-NEXT: [[VTABLE_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[METADATA_BYTES]], [[INT]] [[BASE]]
260+
// CHECK-NEXT: [[VTABLE_OFFSET_ADDR:%.*]] = bitcast i8* [[VTABLE_OFFSET_TMP]] to i32 (%T16class_resilience14ResilientChildC*)**
261+
// CHECK-NEXT: [[METHOD:%.*]] = load i32 (%T16class_resilience14ResilientChildC*)*, i32 (%T16class_resilience14ResilientChildC*)** [[VTABLE_OFFSET_ADDR]]
262+
// CHECK-NEXT: [[RESULT:%.*]] = call swiftcc i32 [[METHOD]](%T16class_resilience14ResilientChildC* swiftself %0)
263+
// CHECK-NEXT: ret i32 [[RESULT]]
264+
265+
// ResilientChild.field setter dispatch thunk
266+
267+
// CHECK-LABEL: define{{( protected)?}} swiftcc void @_T016class_resilience14ResilientChildC5fields5Int32VvsTj(i32, %T16class_resilience14ResilientChildC* swiftself)
268+
// CHECK: [[ISA_ADDR:%.*]] = getelementptr inbounds %T16class_resilience14ResilientChildC, %T16class_resilience14ResilientChildC* %1, i32 0, i32 0, i32 0
269+
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
270+
// CHECK-NEXT: [[BASE:%.*]] = load [[INT]], [[INT]]* @_T016class_resilience14ResilientChildCMo
271+
// CHECK-NEXT: [[METADATA_OFFSET:%.*]] = add [[INT]] [[BASE]], {{4|8}}
272+
// CHECK-NEXT: [[METADATA_BYTES:%.*]] = bitcast %swift.type* [[ISA]] to i8*
273+
// CHECK-NEXT: [[VTABLE_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[METADATA_BYTES]], [[INT]] [[METADATA_OFFSET]]
274+
// CHECK-NEXT: [[VTABLE_OFFSET_ADDR:%.*]] = bitcast i8* [[VTABLE_OFFSET_TMP]] to void (i32, %T16class_resilience14ResilientChildC*)**
275+
// CHECK-NEXT: [[METHOD:%.*]] = load void (i32, %T16class_resilience14ResilientChildC*)*, void (i32, %T16class_resilience14ResilientChildC*)** [[VTABLE_OFFSET_ADDR]]
276+
// CHECK-NEXT: call swiftcc void [[METHOD]](i32 %0, %T16class_resilience14ResilientChildC* swiftself %1)
277+
// CHECK-NEXT: ret void
220278

221279
// ResilientGenericChild.field getter
222280

223-
224281
// CHECK-LABEL: define{{( protected)?}} swiftcc i32 @_T016class_resilience21ResilientGenericChildC5fields5Int32Vvg(%T16class_resilience21ResilientGenericChildC* swiftself)
225282

226283
// FIXME: we could eliminate the unnecessary isa load by lazily emitting
@@ -230,8 +287,11 @@ public class MyResilientChild : MyResilientParent {
230287

231288
// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds %T16class_resilience21ResilientGenericChildC, %T16class_resilience21ResilientGenericChildC* %0, i32 0, i32 0, i32 0
232289
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ADDR]]
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}}
290+
// CHECK-NEXT: [[BASE:%.*]] = load [[INT]], [[INT]]* @_T016class_resilience21ResilientGenericChildCMo
291+
// CHECK-NEXT: [[METADATA_OFFSET:%.*]] = add [[INT]] [[BASE]], {{16|32}}
292+
// CHECK-NEXT: [[ISA_ADDR:%.*]] = bitcast %swift.type* [[ISA]] to i8*
293+
// CHECK-NEXT: [[FIELD_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[ISA_ADDR]], [[INT]] [[METADATA_OFFSET]]
294+
// CHECK-NEXT: [[FIELD_OFFSET_ADDR:%.*]] = bitcast i8* [[FIELD_OFFSET_TMP]] to [[INT]]*
235295
// CHECK-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_ADDR:%.*]]
236296
// CHECK-NEXT: [[OBJECT:%.*]] = bitcast %T16class_resilience21ResilientGenericChildC* %0 to i8*
237297
// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds i8, i8* [[OBJECT]], [[INT]] [[FIELD_OFFSET]]
@@ -254,6 +314,19 @@ public class MyResilientChild : MyResilientParent {
254314
// CHECK: ret i32 [[RESULT]]
255315

256316

317+
// ResilientGenericOutsideParent.genericExtensionMethod()
318+
319+
// CHECK-LABEL: define{{( protected)?}} swiftcc %swift.type* @_T015resilient_class29ResilientGenericOutsideParentC0B11_resilienceE22genericExtensionMethodxmyF(%T15resilient_class29ResilientGenericOutsideParentC* swiftself) #0 {
320+
// CHECK: [[ISA_ADDR:%.*]] = bitcast %T15resilient_class29ResilientGenericOutsideParentC* %0 to %swift.type**
321+
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
322+
// CHECK-NEXT: [[BASE:%.*]] = load [[INT]], [[INT]]* @_T015resilient_class29ResilientGenericOutsideParentCMo
323+
// CHECK-NEXT: [[GENERIC_PARAM_OFFSET:%.*]] = add [[INT]] [[BASE]], 0
324+
// CHECK-NEXT: [[ISA_TMP:%.*]] = bitcast %swift.type* [[ISA]] to i8*
325+
// CHECK-NEXT: [[GENERIC_PARAM_TMP:%.*]] = getelementptr inbounds i8, i8* [[ISA_TMP]], [[INT]] [[GENERIC_PARAM_OFFSET]]
326+
// CHECK-NEXT: [[GENERIC_PARAM_ADDR:%.*]] = bitcast i8* [[GENERIC_PARAM_TMP]] to %swift.type**
327+
// CHECK-NEXT: [[GENERIC_PARAM:%.*]] = load %swift.type*, %swift.type** [[GENERIC_PARAM_ADDR]]
328+
// CHECK-NEXT: ret %swift.type* [[GENERIC_PARAM]]
329+
257330
// ClassWithResilientProperty metadata initialization function
258331

259332

@@ -306,7 +379,7 @@ public class MyResilientChild : MyResilientParent {
306379
// CHECK: store %swift.type* [[SUPER]], %swift.type** getelementptr inbounds ({{.*}})
307380

308381
// Relocate metadata if necessary...
309-
// CHECK: call %swift.type* @swift_relocateClassMetadata(%swift.type* {{.*}}, [[INT]] {{60|96}}, [[INT]] 1)
382+
// CHECK: call %swift.type* @swift_relocateClassMetadata(%swift.type* {{.*}}, [[INT]] {{60|96}}, [[INT]] 4)
310383

311384
// CHECK: ret void
312385

@@ -327,7 +400,7 @@ public class MyResilientChild : MyResilientParent {
327400
// CHECK: store %swift.type* [[SUPER]], %swift.type** getelementptr inbounds ({{.*}})
328401

329402
// Relocate metadata if necessary...
330-
// CHECK: call %swift.type* @swift_relocateClassMetadata(%swift.type* {{.*}}, [[INT]] {{60|96}}, [[INT]] 1)
403+
// CHECK: call %swift.type* @swift_relocateClassMetadata(%swift.type* {{.*}}, [[INT]] {{60|96}}, [[INT]] 4)
331404

332405
// CHECK: ret void
333406

@@ -345,5 +418,5 @@ public class MyResilientChild : MyResilientParent {
345418
// Initialize class metadata base offset...
346419
// CHECK: store [[INT]] {{.*}}, [[INT]]* @_T016class_resilience21ResilientGenericChildCMo
347420

348-
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER_TMP]], [[INT]] 2)
421+
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER_TMP]], [[INT]] 5)
349422
// CHECK: ret %swift.type* [[METADATA]]

0 commit comments

Comments
 (0)