Skip to content

Commit 937f009

Browse files
authored
Merge pull request #18464 from slavapestov/remove-another-unnecessarily-resilient-access-pattern
Use known instance size and alignment across module boundaries
2 parents c329d72 + bee6b09 commit 937f009

File tree

4 files changed

+88
-100
lines changed

4 files changed

+88
-100
lines changed

lib/IRGen/GenClass.cpp

Lines changed: 41 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,22 @@ static SILType getSelfType(ClassDecl *base) {
133133
return SILType::getPrimitiveObjectType(loweredTy);
134134
}
135135

136+
/// If the superclass came from another module, we may have dropped
137+
/// stored properties due to the Swift language version availability of
138+
/// their types. In these cases we can't precisely lay out the ivars in
139+
/// the class object at compile time so we need to do runtime layout.
140+
static bool classHasIncompleteLayout(IRGenModule &IGM,
141+
ClassDecl *theClass) {
142+
if (theClass->getParentModule() == IGM.getSwiftModule())
143+
return false;
144+
145+
for (auto field : theClass->getStoredPropertiesAndMissingMemberPlaceholders())
146+
if (isa<MissingMemberDecl>(field))
147+
return true;
148+
149+
return false;
150+
}
151+
136152
namespace {
137153
class ClassLayoutBuilder : public StructLayoutBuilder {
138154
SmallVector<ElementLayout, 8> Elements;
@@ -229,6 +245,7 @@ namespace {
229245
fieldLayout.AllFieldAccesses = IGM.Context.AllocateCopy(AllFieldAccesses);
230246
fieldLayout.MetadataRequiresDynamicInitialization =
231247
ClassMetadataRequiresDynamicInitialization;
248+
fieldLayout.HasFixedSize = ClassHasFixedSize;
232249
return fieldLayout;
233250
}
234251

@@ -237,9 +254,6 @@ namespace {
237254
if (theClass->isGenericContext())
238255
ClassMetadataRequiresDynamicInitialization = true;
239256

240-
if (IGM.isResilient(theClass, ResilienceExpansion::Maximal))
241-
ClassMetadataRequiresDynamicInitialization = true;
242-
243257
if (theClass->hasSuperclass()) {
244258
SILType superclassType = classType.getSuperclass();
245259
auto superclass = superclassType.getClassOrBoundGenericClass();
@@ -251,6 +265,7 @@ namespace {
251265
// the class object at compile time so we need to do runtime layout.
252266
if (classHasIncompleteLayout(IGM, superclass)) {
253267
ClassMetadataRequiresDynamicInitialization = true;
268+
ClassHasFixedSize = false;
254269
}
255270

256271
if (superclass->hasClangNode()) {
@@ -282,9 +297,6 @@ namespace {
282297
}
283298
} else if (IGM.isResilient(superclass, ResilienceExpansion::Maximal)) {
284299
ClassMetadataRequiresDynamicInitialization = true;
285-
286-
// If the superclass is resilient to us, we cannot statically
287-
// know the layout of either its instances or its class objects.
288300
ClassHasFixedSize = false;
289301

290302
// Furthermore, if the superclass is a generic context, we have to
@@ -310,6 +322,11 @@ namespace {
310322
ClassHasFixedSize = false;
311323
}
312324

325+
if (IGM.isResilient(theClass, ResilienceExpansion::Maximal)) {
326+
ClassMetadataRequiresDynamicInitialization = true;
327+
ClassHasFixedSize = false;
328+
}
329+
313330
// Access strategies should be set by the abstract class layout,
314331
// not using the concrete type information we have.
315332
const ClassLayout *abstractLayout = nullptr;
@@ -657,7 +674,7 @@ Address irgen::emitTailProjection(IRGenFunction &IGF, llvm::Value *Base,
657674
} else {
658675
llvm::Value *metadata = emitHeapMetadataRefForHeapObject(IGF, Base,
659676
ClassType);
660-
Offset = emitClassFragileInstanceSizeAndAlignMask(IGF,
677+
Offset = emitClassResilientInstanceSizeAndAlignMask(IGF,
661678
ClassType.getClassOrBoundGenericClass(),
662679
metadata).first;
663680
}
@@ -789,17 +806,25 @@ llvm::Value *irgen::emitClassAllocation(IRGenFunction &IGF, SILType selfType,
789806
emitClassHeapMetadataRef(IGF, classType, MetadataValueType::TypeMetadata,
790807
MetadataState::Complete);
791808

792-
// FIXME: Long-term, we clearly need a specialized runtime entry point.
809+
const StructLayout &structLayout = classTI.getLayout(IGF.IGM, selfType);
810+
const ClassLayout &classLayout = classTI.getClassLayout(IGF.IGM, selfType);
811+
793812
llvm::Value *size, *alignMask;
794-
std::tie(size, alignMask)
795-
= emitClassFragileInstanceSizeAndAlignMask(IGF,
796-
selfType.getClassOrBoundGenericClass(),
797-
metadata);
813+
if (classLayout.HasFixedSize) {
814+
assert(structLayout.isFixedLayout());
798815

799-
const StructLayout &layout = classTI.getLayout(IGF.IGM, selfType);
800-
llvm::Type *destType = layout.getType()->getPointerTo();
816+
size = structLayout.emitSize(IGF.IGM);
817+
alignMask = structLayout.emitAlignMask(IGF.IGM);
818+
} else {
819+
std::tie(size, alignMask)
820+
= emitClassResilientInstanceSizeAndAlignMask(IGF,
821+
selfType.getClassOrBoundGenericClass(),
822+
metadata);
823+
}
824+
825+
llvm::Type *destType = structLayout.getType()->getPointerTo();
801826
llvm::Value *val = nullptr;
802-
if (llvm::Value *Promoted = stackPromote(IGF, layout, StackAllocSize,
827+
if (llvm::Value *Promoted = stackPromote(IGF, structLayout, StackAllocSize,
803828
TailArrays)) {
804829
val = IGF.Builder.CreateBitCast(Promoted, IGF.IGM.RefCountedPtrTy);
805830
val = IGF.emitInitStackObjectCall(metadata, val, "reference.new");
@@ -863,7 +888,7 @@ static void getInstanceSizeAndAlignMask(IRGenFunction &IGF,
863888
llvm::Value *metadata =
864889
emitHeapMetadataRefForHeapObject(IGF, selfValue, selfType);
865890
std::tie(size, alignMask)
866-
= emitClassFragileInstanceSizeAndAlignMask(IGF, selfClass, metadata);
891+
= emitClassResilientInstanceSizeAndAlignMask(IGF, selfClass, metadata);
867892
}
868893

869894
void irgen::emitClassDeallocation(IRGenFunction &IGF, SILType selfType,
@@ -2225,26 +2250,6 @@ ClassDecl *irgen::getRootClassForMetaclass(IRGenModule &IGM, ClassDecl *C) {
22252250
IGM.Context.Id_SwiftObject);
22262251
}
22272252

2228-
/// If the superclass came from another module, we may have dropped
2229-
/// stored properties due to the Swift language version availability of
2230-
/// their types. In these cases we can't precisely lay out the ivars in
2231-
/// the class object at compile time so we need to do runtime layout.
2232-
bool irgen::classHasIncompleteLayout(IRGenModule &IGM,
2233-
ClassDecl *theClass) {
2234-
do {
2235-
if (theClass->getParentModule() != IGM.getSwiftModule()) {
2236-
for (auto field :
2237-
theClass->getStoredPropertiesAndMissingMemberPlaceholders()){
2238-
if (isa<MissingMemberDecl>(field)) {
2239-
return true;
2240-
}
2241-
}
2242-
return false;
2243-
}
2244-
} while ((theClass = theClass->getSuperclassDecl()));
2245-
return false;
2246-
}
2247-
22482253
bool irgen::doesClassMetadataRequireDynamicInitialization(IRGenModule &IGM,
22492254
ClassDecl *theClass) {
22502255
// Classes imported from Objective-C never requires dynamic initialization.
@@ -2284,36 +2289,6 @@ bool irgen::hasKnownSwiftMetadata(IRGenModule &IGM, ClassDecl *theClass) {
22842289
return theClass->hasKnownSwiftImplementation();
22852290
}
22862291

2287-
/// Given a reference to class metadata of the given type,
2288-
/// load the fragile instance size and alignment of the class.
2289-
std::pair<llvm::Value *, llvm::Value *>
2290-
irgen::emitClassFragileInstanceSizeAndAlignMask(IRGenFunction &IGF,
2291-
ClassDecl *theClass,
2292-
llvm::Value *metadata) {
2293-
// FIXME: The below checks should capture this property already, but
2294-
// resilient class metadata layout is not fully implemented yet.
2295-
auto superClass = theClass;
2296-
do {
2297-
if (superClass->getParentModule() != IGF.IGM.getSwiftModule()) {
2298-
return emitClassResilientInstanceSizeAndAlignMask(IGF, theClass,
2299-
metadata);
2300-
}
2301-
} while ((superClass = superClass->getSuperclassDecl()));
2302-
2303-
// If the class has fragile fixed layout, return the constant size and
2304-
// alignment.
2305-
if (llvm::Constant *size
2306-
= tryEmitClassConstantFragileInstanceSize(IGF.IGM, theClass)) {
2307-
llvm::Constant *alignMask
2308-
= tryEmitClassConstantFragileInstanceAlignMask(IGF.IGM, theClass);
2309-
assert(alignMask && "static size without static align");
2310-
return {size, alignMask};
2311-
}
2312-
2313-
// Otherwise, load it from the metadata.
2314-
return emitClassResilientInstanceSizeAndAlignMask(IGF, theClass, metadata);
2315-
}
2316-
23172292
std::pair<llvm::Value *, llvm::Value *>
23182293
irgen::emitClassResilientInstanceSizeAndAlignMask(IRGenFunction &IGF,
23192294
ClassDecl *theClass,

lib/IRGen/GenClass.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -170,20 +170,6 @@ namespace irgen {
170170
/// the runtime?
171171
bool doesClassMetadataRequireDynamicInitialization(IRGenModule &IGM,
172172
ClassDecl *theClass);
173-
174-
/// If the superclass came from another module, we may have dropped
175-
/// stored properties due to the Swift language version availability of
176-
/// their types. In these cases we can't precisely lay out the ivars in
177-
/// the class object at compile time so we need to do runtime layout.
178-
bool classHasIncompleteLayout(IRGenModule &IGM,
179-
ClassDecl *theClass);
180-
181-
/// Load the fragile instance size and alignment mask from a reference to
182-
/// class type metadata of the given type.
183-
std::pair<llvm::Value *, llvm::Value *>
184-
emitClassFragileInstanceSizeAndAlignMask(IRGenFunction &IGF,
185-
ClassDecl *theClass,
186-
llvm::Value *metadata);
187173

188174
/// Load the instance size and alignment mask from a reference to
189175
/// class type metadata of the given type.

lib/IRGen/StructLayout.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,8 +430,14 @@ struct ClassLayout {
430430
ArrayRef<VarDecl*> InheritedStoredProperties;
431431
/// Lazily-initialized array of all field access methods.
432432
ArrayRef<FieldAccess> AllFieldAccesses;
433-
/// Does the class metadata require dynamic initialization.
433+
/// Does the class metadata require dynamic initialization?
434434
bool MetadataRequiresDynamicInitialization;
435+
/// Do instances of this class have a size and layout known at compile time?
436+
///
437+
/// Note: This is a stronger condition than the StructLayout of a class having
438+
/// a fixed layout. The latter is true even when the class requires sliding
439+
/// ivars by the Objective-C runtime.
440+
bool HasFixedSize;
435441

436442
unsigned getFieldIndex(VarDecl *field) const {
437443
// FIXME: This is algorithmically terrible.
Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -emit-module -o %t/UsingObjCStuff.swiftmodule -module-name UsingObjCStuff -I %t -I %S/Inputs/mixed_mode -swift-version 5 %S/Inputs/mixed_mode/UsingObjCStuff.swift
3-
// RUN: %target-swift-frontend -emit-ir -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 4 %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DWORD=i%target-ptrsize
4-
// RUN: %target-swift-frontend -emit-ir -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 5 %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DWORD=i%target-ptrsize
2+
// RUN: %target-swift-frontend -emit-module -o %t/UsingObjCStuff.swiftmodule -module-name UsingObjCStuff -I %t -I %S/Inputs/mixed_mode -swift-version 4 %S/Inputs/mixed_mode/UsingObjCStuff.swift
3+
// RUN: %target-swift-frontend -emit-ir -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 4 %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V5 --check-prefix=CHECK-V5-%target-ptrsize -DWORD=i%target-ptrsize
4+
// RUN: %target-swift-frontend -emit-ir -I %t -I %S/Inputs/mixed_mode -module-name main -swift-version 5 %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V5 --check-prefix=CHECK-V5-%target-ptrsize -DWORD=i%target-ptrsize
55

66
// REQUIRES: objc_interop
77

@@ -24,24 +24,45 @@ sil_vtable SubSubButtHolder {}
2424
// CHECK-LABEL: define {{.*}} @getHolder
2525
sil @getHolder: $@convention(thin) () -> @owned ButtHolder {
2626
entry:
27-
// We should load the dimensions of the class instance from metadata, not try
28-
// to hardcode constants.
29-
// CHECK: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$S14UsingObjCStuff10ButtHolderCMa"([[WORD]] 0)
30-
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
31-
// CHECK-64: [[SIZE32:%.*]] = load i32
32-
// CHECK-64: [[SIZE:%.*]] = zext i32 [[SIZE32]] to
33-
// CHECK-32: [[SIZE:%.*]] = load i32
34-
// CHECK: [[ALIGN16:%.*]] = load i16
35-
// CHECK: [[ALIGN:%.*]] = zext i16 [[ALIGN16]] to [[WORD]]
36-
// CHECK: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] [[SIZE]], [[WORD]] [[ALIGN]])
27+
28+
// In Swift 4 mode, we don't know the size or alignment of ButtHolder
29+
// instances, so we should load the dimensions of the class instance
30+
// from metadata.
31+
//
32+
// In Swift 5 mode, it's okay to hardcode constants.
33+
34+
// CHECK-V4: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$S14UsingObjCStuff10ButtHolderCMa"([[WORD]] 0)
35+
// CHECK-V4: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
36+
// CHECK-V4-64: [[SIZE32:%.*]] = load i32
37+
// CHECK-V4-64: [[SIZE:%.*]] = zext i32 [[SIZE32]] to
38+
// CHECK-V4-32: [[SIZE:%.*]] = load i32
39+
// CHECK-V4: [[ALIGN16:%.*]] = load i16
40+
// CHECK-V4: [[ALIGN:%.*]] = zext i16 [[ALIGN16]] to [[WORD]]
41+
// CHECK-V4: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] [[SIZE]], [[WORD]] [[ALIGN]])
42+
43+
// CHECK-V5: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$S14UsingObjCStuff10ButtHolderCMa"([[WORD]] 0)
44+
// CHECK-V5: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
45+
// CHECK-V5-32: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] 28, [[WORD]] 3)
46+
// CHECK-V5-64: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] 48, [[WORD]] 7)
47+
3748
%x = alloc_ref $ButtHolder
38-
// CHECK: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$S4main13SubButtHolderCMa"([[WORD]] 0)
39-
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
40-
// CHECK: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] %{{.*}}, [[WORD]] %{{.*}})
49+
// CHECK-V4: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$S4main13SubButtHolderCMa"([[WORD]] 0)
50+
// CHECK-V4: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
51+
// CHECK-V4: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] %{{.*}}, [[WORD]] %{{.*}})
52+
53+
// CHECK-V5: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$S4main13SubButtHolderCMa"([[WORD]] 0)
54+
// CHECK-V5: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
55+
// CHECK-V5-32: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] 40, [[WORD]] 7)
56+
// CHECK-V5-64: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] 56, [[WORD]] 7)
4157
%y = alloc_ref $SubButtHolder
42-
// CHECK: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$S4main03SubB10ButtHolderCMa"([[WORD]] 0)
43-
// CHECK: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
44-
// CHECK: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] %{{.*}}, [[WORD]] %{{.*}})
58+
// CHECK-V4: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$S4main03SubB10ButtHolderCMa"([[WORD]] 0)
59+
// CHECK-V4: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
60+
// CHECK-V4: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] %{{.*}}, [[WORD]] %{{.*}})
61+
62+
// CHECK-V5: [[TMP:%.*]] = call swiftcc %swift.metadata_response @"$S4main03SubB10ButtHolderCMa"([[WORD]] 0)
63+
// CHECK-V5: [[METADATA:%.*]] = extractvalue %swift.metadata_response [[TMP]], 0
64+
// CHECK-V5-32: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] 48, [[WORD]] 7)
65+
// CHECK-V5-64: call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[METADATA]], [[WORD]] 64, [[WORD]] 7)
4566
%z = alloc_ref $SubSubButtHolder
4667
return %x : $ButtHolder
4768
}

0 commit comments

Comments
 (0)