Skip to content

Commit 98b65f2

Browse files
authored
Merge pull request swiftlang#20206 from slavapestov/fix-field-offset-global-update
IRGen: Only mark field offset globals as constant if they won't be updated at runtime
2 parents dbc2e21 + dbd1161 commit 98b65f2

File tree

4 files changed

+35
-21
lines changed

4 files changed

+35
-21
lines changed

lib/IRGen/GenClass.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -993,17 +993,17 @@ void IRGenModule::emitClassDecl(ClassDecl *D) {
993993
SILType selfType = getSelfType(D);
994994
auto &classTI = getTypeInfo(selfType).as<ClassTypeInfo>();
995995

996-
// FIXME: For now, always use the fragile layout when emitting metadata.
996+
// Use the fragile layout when emitting metadata.
997997
auto &fragileLayout =
998998
classTI.getClassLayout(*this, selfType, /*forBackwardDeployment=*/true);
999999

1000-
// ... but still compute the resilient layout for better test coverage.
1000+
// The resilient layout tells us what parts of the metadata can be
1001+
// updated at runtime by the Objective-C metadata update callback.
10011002
auto &resilientLayout =
10021003
classTI.getClassLayout(*this, selfType, /*forBackwardDeployment=*/false);
1003-
(void) resilientLayout;
10041004

10051005
// Emit the class metadata.
1006-
emitClassMetadata(*this, D, fragileLayout);
1006+
emitClassMetadata(*this, D, fragileLayout, resilientLayout);
10071007

10081008
IRGen.addClassForEagerInitialization(D);
10091009

lib/IRGen/GenMeta.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,9 +2293,10 @@ getAddrOfDestructorFunction(IRGenModule &IGM, ClassDecl *classDecl) {
22932293

22942294
static void emitFieldOffsetGlobals(IRGenModule &IGM,
22952295
ClassDecl *classDecl,
2296-
const ClassLayout &classLayout) {
2296+
const ClassLayout &fragileLayout,
2297+
const ClassLayout &resilientLayout) {
22972298
for (auto prop : classDecl->getStoredProperties()) {
2298-
auto fieldInfo = classLayout.getFieldAccessAndElement(prop);
2299+
auto fieldInfo = fragileLayout.getFieldAccessAndElement(prop);
22992300
auto access = fieldInfo.first;
23002301
auto element = fieldInfo.second;
23012302

@@ -2323,8 +2324,19 @@ static void emitFieldOffsetGlobals(IRGenModule &IGM,
23232324
auto offsetVar = cast<llvm::GlobalVariable>(offsetAddr.getAddress());
23242325
offsetVar->setInitializer(fieldOffsetOrZero);
23252326

2326-
// If we know the offset won't change, make it a constant.
2327-
offsetVar->setConstant(access == FieldAccess::ConstantDirect);
2327+
// If the offset is constant in the resilient layout, it will not change
2328+
// at runtime, and the global can be true const.
2329+
//
2330+
// If it is constant in the fragile layout only, newer Objective-C
2331+
// runtimes will still update them in place, so make sure to check the
2332+
// correct layout.
2333+
auto resilientInfo = resilientLayout.getFieldAccessAndElement(prop);
2334+
if (resilientInfo.first == FieldAccess::ConstantDirect) {
2335+
// If it is constant in the resilient layout, it should be constant in
2336+
// the fragile layout also.
2337+
assert(access == FieldAccess::ConstantDirect);
2338+
offsetVar->setConstant(true);
2339+
}
23282340

23292341
break;
23302342
}
@@ -3015,11 +3027,12 @@ static void emitObjCClassSymbol(IRGenModule &IGM,
30153027

30163028
/// Emit the type metadata or metadata template for a class.
30173029
void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
3018-
const ClassLayout &fieldLayout) {
3030+
const ClassLayout &fragileLayout,
3031+
const ClassLayout &resilientLayout) {
30193032
assert(!classDecl->isForeign());
30203033
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl);
30213034

3022-
emitFieldOffsetGlobals(IGM, classDecl, fieldLayout);
3035+
emitFieldOffsetGlobals(IGM, classDecl, fragileLayout, resilientLayout);
30233036

30243037
// Set up a dummy global to stand in for the metadata object while we produce
30253038
// relative references.
@@ -3034,28 +3047,28 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
30343047
bool canBeConstant;
30353048
if (classDecl->isGenericContext()) {
30363049
GenericClassMetadataBuilder builder(IGM, classDecl, init,
3037-
fieldLayout);
3050+
fragileLayout);
30383051
builder.layout();
30393052
canBeConstant = true;
30403053

30413054
builder.createMetadataAccessFunction();
30423055
} else if (doesClassMetadataRequireRelocation(IGM, classDecl)) {
30433056
ResilientClassMetadataBuilder builder(IGM, classDecl, init,
3044-
fieldLayout);
3057+
fragileLayout);
30453058
builder.layout();
30463059
canBeConstant = true;
30473060

30483061
builder.createMetadataAccessFunction();
30493062
} else if (doesClassMetadataRequireInitialization(IGM, classDecl)) {
30503063
SingletonClassMetadataBuilder builder(IGM, classDecl, init,
3051-
fieldLayout);
3064+
fragileLayout);
30523065
builder.layout();
30533066
canBeConstant = builder.canBeConstant();
30543067

30553068
builder.createMetadataAccessFunction();
30563069
} else {
30573070
FixedClassMetadataBuilder builder(IGM, classDecl, init,
3058-
fieldLayout);
3071+
fragileLayout);
30593072
builder.layout();
30603073
canBeConstant = builder.canBeConstant();
30613074

lib/IRGen/GenMeta.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ namespace irgen {
5252

5353
/// Emit the metadata associated with the given class declaration.
5454
void emitClassMetadata(IRGenModule &IGM, ClassDecl *theClass,
55-
const ClassLayout &fieldLayout);
55+
const ClassLayout &fragileLayout,
56+
const ClassLayout &resilientLayout);
5657

5758
/// Emit the constant initializer of the type metadata candidate for
5859
/// the given foreign class declaration.

test/IRGen/completely_fragile_class_layout.sil

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ sil_vtable SubclassOfClassWithResilientField {}
3737

3838
// Field offsets are statically known:
3939
// CHECK-DAG: @"$s31completely_fragile_class_layout23ClassWithResilientFieldC5firstSivpWvd" = hidden constant i64 16, align 8
40-
// CHECK-DAG: @"$s31completely_fragile_class_layout23ClassWithResilientFieldC6second16resilient_struct4SizeVvpWvd" = hidden constant i64 24, align 8
41-
// CHECK-DAG: @"$s31completely_fragile_class_layout23ClassWithResilientFieldC5thirdSivpWvd" = hidden constant i64 40, align 8
40+
// CHECK-DAG: @"$s31completely_fragile_class_layout23ClassWithResilientFieldC6second16resilient_struct4SizeVvpWvd" = hidden global i64 24, align 8
41+
// CHECK-DAG: @"$s31completely_fragile_class_layout23ClassWithResilientFieldC5thirdSivpWvd" = hidden global i64 40, align 8
4242

4343

4444
// RO-data for ClassWithResilientField:
@@ -91,8 +91,8 @@ public class ClassWithResilientEnum {
9191
sil_vtable ClassWithResilientEnum {}
9292

9393
// Field offsets are statically known:
94-
// CHECK-LABEL: @"$s31completely_fragile_class_layout22ClassWithResilientEnumC5firstAA0hfG7PayloadOvpWvd" = hidden constant i64 16, align 8
95-
// CHECK-LABEL: @"$s31completely_fragile_class_layout22ClassWithResilientEnumC6seconds4Int8VvpWvd" = hidden constant i64 25, align 8
94+
// CHECK-LABEL: @"$s31completely_fragile_class_layout22ClassWithResilientEnumC5firstAA0hfG7PayloadOvpWvd" = hidden global i64 16, align 8
95+
// CHECK-LABEL: @"$s31completely_fragile_class_layout22ClassWithResilientEnumC6seconds4Int8VvpWvd" = hidden global i64 25, align 8
9696

9797

9898
// Make sure extra inhabitants work when reading a legacy layout -- the
@@ -105,8 +105,8 @@ public class ClassWithResilientRef {
105105
sil_vtable ClassWithResilientRef {}
106106

107107
// Field offsets are statically known:
108-
// CHECK-LABEL: @"$s31completely_fragile_class_layout21ClassWithResilientRefC5first16resilient_struct0gH0VSgvpWvd" = hidden constant i64 16, align 8
109-
// CHECK-LABEL: @"$s31completely_fragile_class_layout21ClassWithResilientRefC6secondSivpWvd" = hidden constant i64 24, align 8
108+
// CHECK-LABEL: @"$s31completely_fragile_class_layout21ClassWithResilientRefC5first16resilient_struct0gH0VSgvpWvd" = hidden global i64 16, align 8
109+
// CHECK-LABEL: @"$s31completely_fragile_class_layout21ClassWithResilientRefC6secondSivpWvd" = hidden global i64 24, align 8
110110

111111

112112
// When allocating a class with resiliently-sized fields, we must still load

0 commit comments

Comments
 (0)