Skip to content

Commit 7ac3338

Browse files
authored
Merge pull request #30058 from jckarter/dont-cache-fixed-class-metadata
IRGen: Don't cache accesses to fixed class metadata.
2 parents b7aaad7 + 808d33d commit 7ac3338

File tree

6 files changed

+79
-34
lines changed

6 files changed

+79
-34
lines changed

lib/IRGen/MetadataRequest.cpp

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,19 @@ static MetadataResponse emitNominalPrespecializedGenericMetadataRef(
607607
return MetadataResponse::forComplete(metadata);
608608
}
609609

610+
static llvm::Value *
611+
emitIdempotentClassMetadataInitialization(IRGenFunction &IGF,
612+
llvm::Value *metadata) {
613+
if (IGF.IGM.ObjCInterop) {
614+
metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy);
615+
metadata = IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(),
616+
metadata);
617+
metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.TypeMetadataPtrTy);
618+
}
619+
620+
return metadata;
621+
}
622+
610623
/// Returns a metadata reference for a nominal type.
611624
///
612625
/// This is only valid in a couple of special cases:
@@ -615,6 +628,10 @@ static MetadataResponse emitNominalPrespecializedGenericMetadataRef(
615628
/// 2) The nominal type is a value type with a fixed size from this
616629
/// resilience domain, in which case we can reference the constant
617630
/// metadata directly.
631+
/// 3) The nominal type is a class with known Swift metadata and
632+
/// a fixed layout from this resilience domain, in which case we only
633+
/// need perform idempotent class initialization to realize it
634+
/// in the ObjC runtime.
618635
///
619636
/// In any other case, a metadata accessor should be called instead.
620637
static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
@@ -625,11 +642,21 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
625642

626643
if (!theDecl->isGenericContext()) {
627644
assert(!IGF.IGM.isResilient(theDecl, ResilienceExpansion::Maximal));
628-
// TODO: If Obj-C interop is off, we can relax this to allow referencing
629-
// class metadata too.
630-
assert(isa<StructDecl>(theDecl) || isa<EnumDecl>(theDecl));
631-
auto metadata = IGF.IGM.getAddrOfTypeMetadata(theType);
632-
return MetadataResponse::forComplete(metadata);
645+
if (auto response = IGF.tryGetLocalTypeMetadata(theType, request)) {
646+
return response;
647+
}
648+
649+
llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(theType);
650+
651+
// We need to realize classes with the ObjC runtime.
652+
if (auto c = dyn_cast<ClassDecl>(theDecl)) {
653+
654+
assert(hasKnownSwiftMetadata(IGF.IGM, c));
655+
metadata = emitIdempotentClassMetadataInitialization(IGF, metadata);
656+
}
657+
auto response = MetadataResponse::forComplete(metadata);
658+
IGF.setScopedLocalTypeMetadata(theType, response);
659+
return response;
633660
}
634661

635662
// We are applying generic parameters to a generic type.
@@ -796,13 +823,45 @@ bool irgen::shouldCacheTypeMetadataAccess(IRGenModule &IGM, CanType type) {
796823
if (type->hasDynamicSelfType())
797824
return false;
798825

799-
// Statically addressable metadata does not need a cache.
826+
// Nongeneric, nonresilient classes with known Swift metadata need to be
827+
// realized with the Objective-C runtime, but that only requires a single
828+
// runtime call that already has a fast path exit for already-realized
829+
// classes, so we don't need to put up another layer of caching in front.
830+
//
831+
// TODO: On platforms without ObjC interop, we can do direct access to
832+
// Swift metadata without a runtime call at all.
833+
if (auto clas = dyn_cast<ClassType>(type)) {
834+
if (!hasKnownSwiftMetadata(IGM, clas))
835+
return true;
836+
auto strategy = IGM.getClassMetadataStrategy(clas->getDecl());
837+
return strategy != ClassMetadataStrategy::Fixed;
838+
}
839+
840+
// Trivially accessible metadata does not need a cache.
800841
if (isCompleteTypeMetadataStaticallyAddressable(IGM, type))
801842
return false;
802843

803844
return true;
804845
}
805846

847+
/// Should requests for the given type's metadata go through an accessor?
848+
static bool shouldTypeMetadataAccessUseAccessor(IRGenModule &IGM, CanType type){
849+
// Anything that requires caching should go through an accessor to outline
850+
// the cache check.
851+
if (shouldCacheTypeMetadataAccess(IGM, type))
852+
return true;
853+
854+
// Fixed-metadata classes don't require caching, but we still want to go
855+
// through the accessor to outline the ObjC realization.
856+
// TODO: On non-Apple platforms, fixed classes should not need any
857+
// initialization so should be directly addressable.
858+
if (isa<ClassType>(type)) {
859+
return true;
860+
}
861+
862+
return false;
863+
}
864+
806865
/// Return the standard access strategy for getting a non-dependent
807866
/// type metadata object.
808867
MetadataAccessStrategy irgen::getTypeMetadataAccessStrategy(CanType type) {
@@ -1958,19 +2017,6 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction(
19582017
return MetadataResponse::handle(IGF, DynamicMetadataRequest(request), result);
19592018
}
19602019

1961-
static llvm::Value *
1962-
emitIdempotentClassMetadataInitialization(IRGenFunction &IGF,
1963-
llvm::Value *metadata) {
1964-
if (IGF.IGM.ObjCInterop) {
1965-
metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy);
1966-
metadata = IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(),
1967-
metadata);
1968-
metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.TypeMetadataPtrTy);
1969-
}
1970-
1971-
return metadata;
1972-
}
1973-
19742020
/// Emit the body of a metadata accessor function for the given type.
19752021
///
19762022
/// This function is appropriate for ordinary situations where the
@@ -2012,16 +2058,15 @@ emitDirectTypeMetadataAccessFunctionBody(IRGenFunction &IGF,
20122058
// metadata using this function.
20132059
assert(!requiresForeignTypeMetadata(typeDecl));
20142060

2015-
// Classes that might not have Swift metadata use a different
2016-
// access pattern.
20172061
if (auto classDecl = dyn_cast<ClassDecl>(typeDecl)) {
2018-
if (!hasKnownSwiftMetadata(IGF.IGM, classDecl)) {
2019-
return MetadataResponse::forComplete(emitObjCMetadataRef(IGF, classDecl));
2020-
}
2021-
2022-
llvm::Constant *metadata = IGF.IGM.getAddrOfTypeMetadata(type);
2023-
return MetadataResponse::forComplete(
2024-
emitIdempotentClassMetadataInitialization(IGF, metadata));
2062+
// For known-Swift metadata, we can perform a direct reference with
2063+
// potentially idempotent initialization.
2064+
if (hasKnownSwiftMetadata(IGF.IGM, classDecl))
2065+
return emitDirectTypeMetadataRef(IGF, type, request);
2066+
2067+
// Classes that might not have Swift metadata use a different
2068+
// access pattern.
2069+
return MetadataResponse::forComplete(emitObjCMetadataRef(IGF, classDecl));
20252070
}
20262071

20272072
// We should not be doing more serious work along this path.
@@ -2554,7 +2599,7 @@ IRGenFunction::emitTypeMetadataRef(CanType type,
25542599
}
25552600

25562601
if (type->hasArchetype() ||
2557-
!shouldCacheTypeMetadataAccess(IGM, type)) {
2602+
!shouldTypeMetadataAccessUseAccessor(IGM, type)) {
25582603
return emitDirectTypeMetadataRef(*this, type, request);
25592604
}
25602605

test/IRGen/casts.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ nay:
276276
// CHECK: [[V2:%.*]] = icmp ne %T5casts1AC* [[V1]], null
277277
// CHECK: br i1 [[V2]], label %[[LBL:.*]], label
278278
// CHECK: [[LBL]]:
279-
// CHECK: [[V4:%.*]] = bitcast %T5casts1AC* [[V1]] to %swift.type**
279+
// CHECK: [[V4:%.*]] = getelementptr inbounds %T5casts1AC, %T5casts1AC* [[V1]]
280280
// CHECK: load %swift.type*, %swift.type** [[V4]]
281281
sil @checked_downcast_optional_class_to_ex : $@convention(thin) (@guaranteed Optional<A>) -> @owned Optional<CP> {
282282
bb0(%0 : $Optional<A>):

test/IRGen/objc_super.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import gizmo
99

1010
// CHECK: [[CLASS:%objc_class]] = type
11-
// CHECK: [[TYPE:%swift.type]] = type
1211
// CHECK: [[HOOZIT:%T10objc_super6HoozitC]] = type
12+
// CHECK: [[TYPE:%swift.type]] = type
1313
// CHECK: [[PARTIAL_APPLY_CLASS:%T10objc_super12PartialApplyC]] = type
1414
// CHECK: [[SUPER:%objc_super]] = type
1515
// CHECK: [[OBJC:%objc_object]] = type

test/IRGen/protocol_resilience.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ bb0(%0 : $*ConformingStruct):
277277
// concrete Self type.
278278

279279
// CHECK-NEXT: [[SELF:%.*]] = bitcast %T19protocol_resilience16ConformingStructV* %0 to %swift.opaque*
280-
// CHECK-NEXT: call swiftcc void @defaultC(%swift.opaque* noalias nocapture swiftself [[SELF]], %swift.type* bitcast ({{i32|i64}}* {{.*}}) to %swift.type*), i8** %SelfWitnessTable)
280+
// CHECK-NEXT: call swiftcc void @defaultC(%swift.opaque* noalias nocapture swiftself [[SELF]], %swift.type* %Self, i8** %SelfWitnessTable)
281281
%fn1 = function_ref @defaultC : $@convention(witness_method: ResilientProtocol) <Self where Self : ResilientProtocol> (@in_guaranteed Self) -> ()
282282
%ignore1 = apply %fn1<ConformingStruct>(%0) : $@convention(witness_method: ResilientProtocol) <Self where Self : ResilientProtocol> (@in_guaranteed Self) -> ()
283283

test/IRGen/unowned.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
// REQUIRES: CPU=x86_64
44

5-
// CHECK: [[TYPE:%swift.type]] = type
65
// CHECK: [[C:%T7unowned1CC]] = type <{ [[REF:%swift.refcounted]] }>
6+
// CHECK: [[TYPE:%swift.type]] = type
77
// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
88
// CHECK: [[A:%T7unowned1AV]] = type <{ %swift.unowned }>
99

test/ModuleInterface/private-stored-member-type-layout.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
// These two appear out-of-order between run lines
1818

19-
// CHECK-DAG: [[MYCLASS:%T20PrivateStoredMembers7MyClassC]] = type opaque
19+
// CHECK-DAG: [[MYCLASS:%T20PrivateStoredMembers7MyClassC]] = type
2020
// CHECK-DAG: [[MYSTRUCT:%T20PrivateStoredMembers8MyStructV]] = type <{ %Ts5Int64V, %TSb, [7 x i8], %Ts5Int64V, %TSb, [7 x i8], %Ts5Int64V, %TSb, [7 x i8], %Ts5Int64V, %TSb, [7 x i8], %Ts5Int64V }>
2121

2222
// CHECK-MAIN-DAG: [[MYCLASS:%T4main7MyClassC]] = type <{ %swift.refcounted, %Ts5Int64V, %TSb, [7 x i8], %Ts5Int64V, %TSb, [7 x i8], %Ts5Int64V, %TSb, [7 x i8], %Ts5Int64V, %TSb, [7 x i8], %Ts5Int64V }>

0 commit comments

Comments
 (0)