Skip to content

Commit dbd1161

Browse files
committed
IRGen: Only mark field offset globals as constant if they won't be updated at runtime
Even if we have a constant value, we might be emitting a legacy layout that can be updated in place by newer runtimes. In this case, clients cannot assume the field offsets are constant, and the globals cannot be constant either. Part of <rdar://problem/17528739>.
1 parent b5aa1b3 commit dbd1161

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)