Skip to content

Class resilience part 9 #13618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,8 @@ enum class ProtocolDispatchStrategy: uint8_t {
class GenericParameterDescriptorFlags {
typedef uint16_t int_type;
enum : int_type {
HasVTable = 0x0004,
HasVTable = 0x0004,
HasResilientSuperclass = 0x0008,
};
int_type Data;

Expand All @@ -335,6 +336,23 @@ class GenericParameterDescriptorFlags {
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;
}
Expand Down
16 changes: 12 additions & 4 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2192,6 +2192,8 @@ namespace {
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.
Expand Down Expand Up @@ -2427,13 +2429,19 @@ namespace {
: 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; }
Expand Down
31 changes: 23 additions & 8 deletions lib/IRGen/MetadataLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,15 @@ Offset NominalMetadataLayout::emitOffset(IRGenFunction &IGF,
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);
}

Expand Down Expand Up @@ -237,12 +238,26 @@ ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl)
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();
Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/MetadataLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ class ClassMetadataLayout : public NominalMetadataLayout {
};

private:
bool HasResilientSuperclass = false;

StoredOffset MetadataSize;

StoredOffset InstanceSize;
Expand Down Expand Up @@ -210,6 +212,10 @@ class ClassMetadataLayout : public NominalMetadataLayout {
return cast<ClassDecl>(Nominal);
}

bool hasResilientSuperclass() const {
return HasResilientSuperclass;
}

Size getMetadataSizeOffset() const;

Size getInstanceSizeOffset() const;
Expand Down
97 changes: 85 additions & 12 deletions test/IRGen/class_resilience.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand All @@ -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}}
Expand Down Expand Up @@ -101,7 +127,7 @@ public class ClassWithIndirectResilientEnum {
// 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.
Expand All @@ -110,14 +136,14 @@ public class ResilientChild : ResilientOutsideParent {
// 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
}


Expand All @@ -134,6 +160,12 @@ public class MyResilientChild : MyResilientParent {
}


extension ResilientGenericOutsideParent {
public func genericExtensionMethod() -> A.Type {
return A.self
}
}

// ClassWithResilientProperty.color getter

// CHECK-LABEL: define{{( protected)?}} swiftcc i32 @_T016class_resilience26ClassWithResilientPropertyC5colors5Int32Vvg(%T16class_resilience26ClassWithResilientPropertyC* swiftself)
Expand Down Expand Up @@ -217,10 +249,35 @@ public class MyResilientChild : MyResilientParent {
// 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
Expand All @@ -230,8 +287,11 @@ public class MyResilientChild : MyResilientParent {

// 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]]
Expand All @@ -254,6 +314,19 @@ public class MyResilientChild : MyResilientParent {
// 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


Expand Down Expand Up @@ -306,7 +379,7 @@ public class MyResilientChild : MyResilientParent {
// 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

Expand All @@ -327,7 +400,7 @@ public class MyResilientChild : MyResilientParent {
// 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

Expand All @@ -345,5 +418,5 @@ public class MyResilientChild : MyResilientParent {
// 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]]