Merge pull request #13618 from slavapestov/class-resilience-part-9
Class resilience part 9
diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h
index a5f9f2b..9a0f7ce 100644
--- a/include/swift/ABI/MetadataValues.h
+++ b/include/swift/ABI/MetadataValues.h
@@ -315,7 +315,8 @@
class GenericParameterDescriptorFlags {
typedef uint16_t int_type;
enum : int_type {
- HasVTable = 0x0004,
+ HasVTable = 0x0004,
+ HasResilientSuperclass = 0x0008,
};
int_type Data;
@@ -335,6 +336,23 @@
return Data & HasVTable;
}
+ constexpr GenericParameterDescriptorFlags withHasResilientSuperclass(bool b) const {
+ return GenericParameterDescriptorFlags(b ? (Data | HasResilientSuperclass)
+ : (Data & ~HasResilientSuperclass));
+ }
+
+ /// If this type is a class, does it have a resilient superclass?
+ /// If so, the generic parameter offset, field offset vector offset
+ /// and vtable start offsets are relative to the start of the class's
+ /// immediate members in the metadata, and not the start of the
+ /// metadata itself.
+ ///
+ /// Note that the immediate members begin at the same offset where the
+ /// superclass metadata ends.
+ bool hasResilientSuperclass() const {
+ return Data & HasResilientSuperclass;
+ }
+
int_type getIntValue() const {
return Data;
}
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index fcdde6b..d4bcf80 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -2192,6 +2192,8 @@
auto &layout = IGM.getMetadataLayout(cd);
if (layout.getVTableSize() > 0)
flags = flags.withHasVTable(true);
+ if (layout.hasResilientSuperclass())
+ flags = flags.withHasResilientSuperclass(true);
}
// Calculate the number of generic parameters at each nesting depth.
@@ -2427,13 +2429,19 @@
: super(IGM), Target(c)
{
auto &layout = IGM.getMetadataLayout(Target);
- FieldVectorOffset = layout.getStaticFieldOffsetVectorOffset();
- GenericParamsOffset = layout.getStaticGenericRequirementsOffset();
VTable = IGM.getSILModule().lookUpVTable(Target);
-
- VTableOffset = layout.getStaticVTableOffset();
VTableSize = layout.getVTableSize();
+
+ if (layout.hasResilientSuperclass()) {
+ FieldVectorOffset = layout.getRelativeFieldOffsetVectorOffset();
+ GenericParamsOffset = layout.getRelativeGenericRequirementsOffset();
+ VTableOffset = layout.getRelativeVTableOffset();
+ } else {
+ FieldVectorOffset = layout.getStaticFieldOffsetVectorOffset();
+ GenericParamsOffset = layout.getStaticGenericRequirementsOffset();
+ VTableOffset = layout.getStaticVTableOffset();
+ }
}
ClassDecl *getTarget() { return Target; }
diff --git a/lib/IRGen/MetadataLayout.cpp b/lib/IRGen/MetadataLayout.cpp
index 3c7954a..d1f77f6 100644
--- a/lib/IRGen/MetadataLayout.cpp
+++ b/lib/IRGen/MetadataLayout.cpp
@@ -147,14 +147,15 @@
IGF.IGM.getPointerAlignment());
// FIXME: Should this be an invariant load?
- auto *offsetBaseVal =
- IGF.Builder.CreateLoad(offsetBaseAddr, "base");
+ llvm::Value *offsetVal = IGF.Builder.CreateLoad(offsetBaseAddr, "base");
auto relativeOffset = offset.getRelativeOffset().getValue();
- auto *offsetVal =
- IGF.Builder.CreateAdd(offsetBaseVal,
- llvm::ConstantInt::get(IGF.IGM.SizeTy,
- relativeOffset));
+ if (relativeOffset != 0) {
+ offsetVal = IGF.Builder.CreateAdd(offsetVal,
+ llvm::ConstantInt::get(IGF.IGM.SizeTy,
+ relativeOffset));
+ }
+
return Offset(offsetVal);
}
@@ -237,12 +238,26 @@
using super = LayoutScanner;
ClassMetadataLayout &Layout;
+
Scanner(IRGenModule &IGM, ClassDecl *decl, ClassMetadataLayout &layout)
: super(IGM, decl), Layout(layout) {}
- void noteResilientSuperclass() {}
+ void noteResilientSuperclass() {
+ Layout.HasResilientSuperclass = true;
+ }
- void noteStartOfImmediateMembers(ClassDecl *theClass) {}
+ void noteStartOfImmediateMembers(ClassDecl *forClass) {
+ // If our superclass is resilient to us, or the class itself is resilient
+ // to us, we will access metadata members relative to a base offset.
+ if (forClass == Target) {
+ if (Layout.HasResilientSuperclass ||
+ (IGM.Context.LangOpts.EnableClassResilience &&
+ IGM.isResilient(forClass, ResilienceExpansion::Maximal))) {
+ assert(!DynamicOffsetBase);
+ DynamicOffsetBase = NextOffset;
+ }
+ }
+ }
void addClassSize() {
Layout.MetadataSize = getNextOffset();
diff --git a/lib/IRGen/MetadataLayout.h b/lib/IRGen/MetadataLayout.h
index a3ee008..0acad99 100644
--- a/lib/IRGen/MetadataLayout.h
+++ b/lib/IRGen/MetadataLayout.h
@@ -167,6 +167,8 @@
};
private:
+ bool HasResilientSuperclass = false;
+
StoredOffset MetadataSize;
StoredOffset InstanceSize;
@@ -210,6 +212,10 @@
return cast<ClassDecl>(Nominal);
}
+ bool hasResilientSuperclass() const {
+ return HasResilientSuperclass;
+ }
+
Size getMetadataSizeOffset() const;
Size getInstanceSizeOffset() const;
diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift
index d7f5fd9..41156a6 100644
--- a/test/IRGen/class_resilience.swift
+++ b/test/IRGen/class_resilience.swift
@@ -15,6 +15,10 @@
// CHECK: @_T016class_resilience14ResilientChildC5fields5Int32VvpWvd = {{(protected )?}}global [[INT]] {{8|16}}
+// CHECK: @_T016class_resilience14ResilientChildCMo = {{(protected )?}}global [[INT]] 0
+
+// CHECK: @_T016class_resilience21ResilientGenericChildCMo = {{(protected )?}}global [[INT]] 0
+
// CHECK: @_T016class_resilience26ClassWithResilientPropertyCMo = {{(protected )?}}constant [[INT]] {{52|80}}
// CHECK: @_T016class_resilience28ClassWithMyResilientPropertyC1rAA0eF6StructVvpWvd = {{(protected )?}}constant [[INT]] {{8|16}}
@@ -23,12 +27,34 @@
// CHECK: @_T016class_resilience30ClassWithIndirectResilientEnumC1s14resilient_enum10FunnyShapeOvpWvd = {{(protected )?}}constant [[INT]] {{8|16}}
// CHECK: @_T016class_resilience30ClassWithIndirectResilientEnumC5colors5Int32VvpWvd = {{(protected )?}}constant [[INT]] {{12|24}}
-// CHECK: @_T016class_resilience14ResilientChildCMo = {{(protected )?}}global [[INT]] 0
+// CHECK: [[RESILIENTCHILD_NAME:@.*]] = private constant [36 x i8] c"16class_resilience14ResilientChildC\00"
+// CHECK: [[RESILIENTCHILD_FIELDS:@.*]] = private constant [7 x i8] c"field\00\00"
+
+// CHECK: @_T016class_resilience14ResilientChildCMn = {{(protected )?}}constant <{{.*}}> <{
+// -- name:
+// CHECK-SAME: [36 x i8]* [[RESILIENTCHILD_NAME]]
+// -- num fields
+// CHECK-SAME: i32 1,
+// -- field offset vector offset
+// CHECK-SAME: i32 3,
+// -- field names,
+// CHECK-SAME: [7 x i8]* [[RESILIENTCHILD_FIELDS]]
+// -- kind 0 (class)
+// CHECK-SAME: i32 0,
+// -- generic parameter vector offset
+// CHECK-SAME: i32 0,
+// -- generic parameter count, primary count
+// CHECK-SAME: i32 0, i32 0,
+// -- nesting depth
+// CHECK-SAME: i16 1,
+// -- flags -- has vtable, has resilient superclass
+// CHECK-SAME: i16 12,
+// -- generic parameters at depth 0
+// CHECK-SAME: i32 0
+// CHECK-SAME: }>
// CHECK: @_T016class_resilience16FixedLayoutChildCMo = {{(protected )?}}global [[INT]] 0
-// CHECK: @_T016class_resilience21ResilientGenericChildCMo = {{(protected )?}}global [[INT]] 0
-
// CHECK: @_T016class_resilience17MyResilientParentCMo = {{(protected )?}}constant [[INT]] {{52|80}}
// CHECK: @_T016class_resilience16MyResilientChildCMo = {{(protected )?}}constant [[INT]] {{60|96}}
@@ -101,7 +127,7 @@
// offsets is not known at compile time
public class ResilientChild : ResilientOutsideParent {
- public let field: Int32 = 0
+ public var field: Int32 = 0
}
// Superclass is resilient, but the class is fixed-layout.
@@ -110,14 +136,14 @@
// global.
@_fixed_layout public class FixedLayoutChild : ResilientOutsideParent {
- public let field: Int32 = 0
+ public var field: Int32 = 0
}
// Superclass is resilient, so the number of fields and their
// offsets is not known at compile time
public class ResilientGenericChild<T> : ResilientGenericOutsideParent<T> {
- public let field: Int32 = 0
+ public var field: Int32 = 0
}
@@ -134,6 +160,12 @@
}
+extension ResilientGenericOutsideParent {
+ public func genericExtensionMethod() -> A.Type {
+ return A.self
+ }
+}
+
// ClassWithResilientProperty.color getter
// CHECK-LABEL: define{{( protected)?}} swiftcc i32 @_T016class_resilience26ClassWithResilientPropertyC5colors5Int32Vvg(%T16class_resilience26ClassWithResilientPropertyC* swiftself)
@@ -217,10 +249,35 @@
// CHECK-NEXT: call void @swift_endAccess
// CHECK: ret i32 [[FIELD_VALUE]]
+// ResilientChild.field getter dispatch thunk
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc i32 @_T016class_resilience14ResilientChildC5fields5Int32VvgTj(%T16class_resilience14ResilientChildC* swiftself)
+// CHECK: [[ISA_ADDR:%.*]] = getelementptr inbounds %T16class_resilience14ResilientChildC, %T16class_resilience14ResilientChildC* %0, i32 0, i32 0, i32 0
+// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
+// CHECK-NEXT: [[BASE:%.*]] = load [[INT]], [[INT]]* @_T016class_resilience14ResilientChildCMo
+// CHECK-NEXT: [[METADATA_BYTES:%.*]] = bitcast %swift.type* [[ISA]] to i8*
+// CHECK-NEXT: [[VTABLE_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[METADATA_BYTES]], [[INT]] [[BASE]]
+// CHECK-NEXT: [[VTABLE_OFFSET_ADDR:%.*]] = bitcast i8* [[VTABLE_OFFSET_TMP]] to i32 (%T16class_resilience14ResilientChildC*)**
+// CHECK-NEXT: [[METHOD:%.*]] = load i32 (%T16class_resilience14ResilientChildC*)*, i32 (%T16class_resilience14ResilientChildC*)** [[VTABLE_OFFSET_ADDR]]
+// CHECK-NEXT: [[RESULT:%.*]] = call swiftcc i32 [[METHOD]](%T16class_resilience14ResilientChildC* swiftself %0)
+// CHECK-NEXT: ret i32 [[RESULT]]
+
+// ResilientChild.field setter dispatch thunk
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc void @_T016class_resilience14ResilientChildC5fields5Int32VvsTj(i32, %T16class_resilience14ResilientChildC* swiftself)
+// CHECK: [[ISA_ADDR:%.*]] = getelementptr inbounds %T16class_resilience14ResilientChildC, %T16class_resilience14ResilientChildC* %1, i32 0, i32 0, i32 0
+// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
+// CHECK-NEXT: [[BASE:%.*]] = load [[INT]], [[INT]]* @_T016class_resilience14ResilientChildCMo
+// CHECK-NEXT: [[METADATA_OFFSET:%.*]] = add [[INT]] [[BASE]], {{4|8}}
+// CHECK-NEXT: [[METADATA_BYTES:%.*]] = bitcast %swift.type* [[ISA]] to i8*
+// CHECK-NEXT: [[VTABLE_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[METADATA_BYTES]], [[INT]] [[METADATA_OFFSET]]
+// CHECK-NEXT: [[VTABLE_OFFSET_ADDR:%.*]] = bitcast i8* [[VTABLE_OFFSET_TMP]] to void (i32, %T16class_resilience14ResilientChildC*)**
+// CHECK-NEXT: [[METHOD:%.*]] = load void (i32, %T16class_resilience14ResilientChildC*)*, void (i32, %T16class_resilience14ResilientChildC*)** [[VTABLE_OFFSET_ADDR]]
+// CHECK-NEXT: call swiftcc void [[METHOD]](i32 %0, %T16class_resilience14ResilientChildC* swiftself %1)
+// CHECK-NEXT: ret void
// ResilientGenericChild.field getter
-
// CHECK-LABEL: define{{( protected)?}} swiftcc i32 @_T016class_resilience21ResilientGenericChildC5fields5Int32Vvg(%T16class_resilience21ResilientGenericChildC* swiftself)
// FIXME: we could eliminate the unnecessary isa load by lazily emitting
@@ -230,8 +287,11 @@
// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds %T16class_resilience21ResilientGenericChildC, %T16class_resilience21ResilientGenericChildC* %0, i32 0, i32 0, i32 0
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ADDR]]
-// CHECK-NEXT: [[ISA_ADDR:%.*]] = bitcast %swift.type* [[ISA]] to [[INT]]*
-// CHECK-NEXT: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[ISA_ADDR]], [[INT]] {{11|14}}
+// CHECK-NEXT: [[BASE:%.*]] = load [[INT]], [[INT]]* @_T016class_resilience21ResilientGenericChildCMo
+// CHECK-NEXT: [[METADATA_OFFSET:%.*]] = add [[INT]] [[BASE]], {{16|32}}
+// CHECK-NEXT: [[ISA_ADDR:%.*]] = bitcast %swift.type* [[ISA]] to i8*
+// CHECK-NEXT: [[FIELD_OFFSET_TMP:%.*]] = getelementptr inbounds i8, i8* [[ISA_ADDR]], [[INT]] [[METADATA_OFFSET]]
+// CHECK-NEXT: [[FIELD_OFFSET_ADDR:%.*]] = bitcast i8* [[FIELD_OFFSET_TMP]] to [[INT]]*
// CHECK-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_ADDR:%.*]]
// CHECK-NEXT: [[OBJECT:%.*]] = bitcast %T16class_resilience21ResilientGenericChildC* %0 to i8*
// CHECK-NEXT: [[ADDR:%.*]] = getelementptr inbounds i8, i8* [[OBJECT]], [[INT]] [[FIELD_OFFSET]]
@@ -254,6 +314,19 @@
// CHECK: ret i32 [[RESULT]]
+// ResilientGenericOutsideParent.genericExtensionMethod()
+
+// CHECK-LABEL: define{{( protected)?}} swiftcc %swift.type* @_T015resilient_class29ResilientGenericOutsideParentC0B11_resilienceE22genericExtensionMethodxmyF(%T15resilient_class29ResilientGenericOutsideParentC* swiftself) #0 {
+// CHECK: [[ISA_ADDR:%.*]] = bitcast %T15resilient_class29ResilientGenericOutsideParentC* %0 to %swift.type**
+// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
+// CHECK-NEXT: [[BASE:%.*]] = load [[INT]], [[INT]]* @_T015resilient_class29ResilientGenericOutsideParentCMo
+// CHECK-NEXT: [[GENERIC_PARAM_OFFSET:%.*]] = add [[INT]] [[BASE]], 0
+// CHECK-NEXT: [[ISA_TMP:%.*]] = bitcast %swift.type* [[ISA]] to i8*
+// CHECK-NEXT: [[GENERIC_PARAM_TMP:%.*]] = getelementptr inbounds i8, i8* [[ISA_TMP]], [[INT]] [[GENERIC_PARAM_OFFSET]]
+// CHECK-NEXT: [[GENERIC_PARAM_ADDR:%.*]] = bitcast i8* [[GENERIC_PARAM_TMP]] to %swift.type**
+// CHECK-NEXT: [[GENERIC_PARAM:%.*]] = load %swift.type*, %swift.type** [[GENERIC_PARAM_ADDR]]
+// CHECK-NEXT: ret %swift.type* [[GENERIC_PARAM]]
+
// ClassWithResilientProperty metadata initialization function
@@ -306,7 +379,7 @@
// CHECK: store %swift.type* [[SUPER]], %swift.type** getelementptr inbounds ({{.*}})
// Relocate metadata if necessary...
-// CHECK: call %swift.type* @swift_relocateClassMetadata(%swift.type* {{.*}}, [[INT]] {{60|96}}, [[INT]] 1)
+// CHECK: call %swift.type* @swift_relocateClassMetadata(%swift.type* {{.*}}, [[INT]] {{60|96}}, [[INT]] 4)
// CHECK: ret void
@@ -327,7 +400,7 @@
// CHECK: store %swift.type* [[SUPER]], %swift.type** getelementptr inbounds ({{.*}})
// Relocate metadata if necessary...
-// CHECK: call %swift.type* @swift_relocateClassMetadata(%swift.type* {{.*}}, [[INT]] {{60|96}}, [[INT]] 1)
+// CHECK: call %swift.type* @swift_relocateClassMetadata(%swift.type* {{.*}}, [[INT]] {{60|96}}, [[INT]] 4)
// CHECK: ret void
@@ -345,5 +418,5 @@
// Initialize class metadata base offset...
// CHECK: store [[INT]] {{.*}}, [[INT]]* @_T016class_resilience21ResilientGenericChildCMo
-// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER_TMP]], [[INT]] 2)
+// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER_TMP]], [[INT]] 5)
// CHECK: ret %swift.type* [[METADATA]]