@@ -607,6 +607,19 @@ static MetadataResponse emitNominalPrespecializedGenericMetadataRef(
607
607
return MetadataResponse::forComplete (metadata);
608
608
}
609
609
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
+
610
623
// / Returns a metadata reference for a nominal type.
611
624
// /
612
625
// / This is only valid in a couple of special cases:
@@ -615,6 +628,10 @@ static MetadataResponse emitNominalPrespecializedGenericMetadataRef(
615
628
// / 2) The nominal type is a value type with a fixed size from this
616
629
// / resilience domain, in which case we can reference the constant
617
630
// / 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.
618
635
// /
619
636
// / In any other case, a metadata accessor should be called instead.
620
637
static MetadataResponse emitNominalMetadataRef (IRGenFunction &IGF,
@@ -625,11 +642,21 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
625
642
626
643
if (!theDecl->isGenericContext ()) {
627
644
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;
633
660
}
634
661
635
662
// We are applying generic parameters to a generic type.
@@ -796,13 +823,45 @@ bool irgen::shouldCacheTypeMetadataAccess(IRGenModule &IGM, CanType type) {
796
823
if (type->hasDynamicSelfType ())
797
824
return false ;
798
825
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.
800
841
if (isCompleteTypeMetadataStaticallyAddressable (IGM, type))
801
842
return false ;
802
843
803
844
return true ;
804
845
}
805
846
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
+
806
865
// / Return the standard access strategy for getting a non-dependent
807
866
// / type metadata object.
808
867
MetadataAccessStrategy irgen::getTypeMetadataAccessStrategy (CanType type) {
@@ -1958,19 +2017,6 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction(
1958
2017
return MetadataResponse::handle (IGF, DynamicMetadataRequest (request), result);
1959
2018
}
1960
2019
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
-
1974
2020
// / Emit the body of a metadata accessor function for the given type.
1975
2021
// /
1976
2022
// / This function is appropriate for ordinary situations where the
@@ -2012,16 +2058,15 @@ emitDirectTypeMetadataAccessFunctionBody(IRGenFunction &IGF,
2012
2058
// metadata using this function.
2013
2059
assert (!requiresForeignTypeMetadata (typeDecl));
2014
2060
2015
- // Classes that might not have Swift metadata use a different
2016
- // access pattern.
2017
2061
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));
2025
2070
}
2026
2071
2027
2072
// We should not be doing more serious work along this path.
@@ -2554,7 +2599,7 @@ IRGenFunction::emitTypeMetadataRef(CanType type,
2554
2599
}
2555
2600
2556
2601
if (type->hasArchetype () ||
2557
- !shouldCacheTypeMetadataAccess (IGM, type)) {
2602
+ !shouldTypeMetadataAccessUseAccessor (IGM, type)) {
2558
2603
return emitDirectTypeMetadataRef (*this , type, request);
2559
2604
}
2560
2605
0 commit comments