@@ -656,7 +656,7 @@ static MetadataResponse emitNominalPrespecializedGenericMetadataRef(
656
656
DynamicMetadataRequest request,
657
657
SpecializedMetadataCanonicality canonicality) {
658
658
assert (isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
659
- IGF.IGM , *theDecl, theType, canonicality));
659
+ IGF.IGM , theType, canonicality));
660
660
// We are applying generic parameters to a generic type.
661
661
assert (theType->getAnyNominal () == theDecl);
662
662
@@ -763,16 +763,16 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
763
763
MetadataResponse response;
764
764
765
765
if (isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
766
- IGF.IGM , *theDecl, theType, CanonicalSpecializedMetadata)) {
766
+ IGF.IGM , theType, CanonicalSpecializedMetadata)) {
767
767
response = emitNominalPrespecializedGenericMetadataRef (
768
768
IGF, theDecl, theType, request, CanonicalSpecializedMetadata);
769
769
} else if (isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
770
- IGF.IGM , *theDecl, theType, NoncanonicalSpecializedMetadata)) {
770
+ IGF.IGM , theType, NoncanonicalSpecializedMetadata)) {
771
771
response = emitNominalPrespecializedGenericMetadataRef (
772
772
IGF, theDecl, theType, request, NoncanonicalSpecializedMetadata);
773
773
} else if (auto theClass = dyn_cast<ClassDecl>(theDecl)) {
774
774
if (isSpecializedNominalTypeMetadataStaticallyAddressable (
775
- IGF.IGM , *theClass, theType, CanonicalSpecializedMetadata,
775
+ IGF.IGM , theType, CanonicalSpecializedMetadata,
776
776
ForUseOnlyFromAccessor)) {
777
777
llvm::Function *accessor =
778
778
IGF.IGM
@@ -799,10 +799,13 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
799
799
}
800
800
801
801
bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable (
802
- IRGenModule &IGM, NominalTypeDecl &nominal, CanType type,
802
+ IRGenModule &IGM, CanType type,
803
803
SpecializedMetadataCanonicality canonicality,
804
804
SpecializedMetadataUsageIsOnlyFromAccessor onlyFromAccessor) {
805
- assert (nominal.isGenericContext ());
805
+ auto *nominal = type->getAnyNominal ();
806
+
807
+ assert (!isa<ProtocolDecl>(nominal));
808
+ assert (nominal->isGenericContext ());
806
809
807
810
if (!IGM.shouldPrespecializeGenericMetadata ()) {
808
811
return false ;
@@ -812,13 +815,16 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable(
812
815
return false ;
813
816
}
814
817
818
+ if (!IGM.getTypeInfoForUnlowered (type).isFixedSize (ResilienceExpansion::Maximal))
819
+ return false ;
820
+
815
821
switch (canonicality) {
816
822
case CanonicalSpecializedMetadata:
817
823
if (IGM.getSILModule ().isWholeModule ()) {
818
824
// Canonical prespecializations can only be emitted within the module
819
825
// where the generic type is itself defined, since it is the module where
820
826
// the metadata accessor is defined.
821
- if (IGM.getSwiftModule () != nominal. getModuleContext ()) {
827
+ if (IGM.getSwiftModule () != nominal-> getModuleContext ()) {
822
828
return false ;
823
829
}
824
830
} else {
@@ -827,7 +833,7 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable(
827
833
// containing the type's decl! The reason is that the generic metadata
828
834
// accessor is defined in the IRGenModule corresponding to the source file
829
835
// containing the type's decl.
830
- SourceFile *nominalFile = nominal. getDeclContext ()->getParentSourceFile ();
836
+ SourceFile *nominalFile = nominal-> getDeclContext ()->getParentSourceFile ();
831
837
if (auto *moduleFile = IGM.IRGen .getSourceFile (&IGM)) {
832
838
if (nominalFile != moduleFile) {
833
839
return false ;
@@ -838,17 +844,17 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable(
838
844
case NoncanonicalSpecializedMetadata:
839
845
// Non-canonical metadata prespecializations for a type cannot be formed
840
846
// within the module that defines that type.
841
- if (IGM.getSwiftModule () == nominal. getModuleContext ()) {
847
+ if (IGM.getSwiftModule () == nominal-> getModuleContext ()) {
842
848
return false ;
843
849
}
844
- if (nominal. isResilient (IGM.getSwiftModule (),
845
- ResilienceExpansion::Maximal)) {
850
+ if (nominal-> isResilient (IGM.getSwiftModule (),
851
+ ResilienceExpansion::Maximal)) {
846
852
return false ;
847
853
}
848
854
break ;
849
855
}
850
856
851
- if (auto *theClass = dyn_cast<ClassDecl>(& nominal)) {
857
+ if (auto *theClass = dyn_cast<ClassDecl>(nominal)) {
852
858
if (theClass->hasResilientMetadata (IGM.getSwiftModule (),
853
859
ResilienceExpansion::Maximal)) {
854
860
return false ;
@@ -871,77 +877,67 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable(
871
877
}
872
878
}
873
879
874
- auto *generic = type.getAnyGeneric ();
875
- assert (generic);
876
- auto *environment = generic->getGenericEnvironment ();
877
- assert (environment);
880
+ // Analyze the substitution map to determine if everything can be referenced
881
+ // statically.
878
882
auto substitutions =
879
- type->getContextSubstitutionMap (IGM.getSwiftModule (), &nominal);
880
-
881
- auto allArgumentsAreStaticallyAddressable =
882
- llvm::all_of (environment->getGenericParams (), [&](auto parameter) {
883
- auto signature = environment->getGenericSignature ();
884
- const auto protocols = signature->getRequiredProtocols (parameter);
885
- auto argument = ((Type *)parameter)->subst (substitutions);
886
- auto canonicalType = argument->getCanonicalType ();
887
- auto witnessTablesAreReferenceable = [&]() {
888
- return llvm::all_of (protocols, [&](ProtocolDecl *protocol) {
889
- auto conformance =
890
- signature->lookupConformance (canonicalType, protocol);
891
- if (!conformance.isConcrete ()) {
892
- return false ;
893
- }
894
- auto rootConformance =
895
- conformance.getConcrete ()->getRootConformance ();
896
- return !IGM.isDependentConformance (rootConformance) &&
897
- !IGM.isResilientConformance (rootConformance);
898
- });
899
- };
900
- // TODO: Once witness tables are statically specialized, check whether
901
- // the
902
- // ConformanceInfo returns nullptr from tryGetConstantTable.
903
- auto isGenericWithoutPrespecializedConformance = [&]() {
904
- auto genericArgument = argument->getAnyGeneric ();
905
- return genericArgument && genericArgument->isGenericContext () &&
906
- (protocols.size () > 0 );
907
- };
908
- auto metadataAccessIsTrivial = [&]() {
909
- if (onlyFromAccessor) {
910
- // If an accessor is being used, then the accessor will be able to
911
- // initialize the arguments, i.e. register classes with the ObjC
912
- // runtime.
913
- return irgen::
914
- isCanonicalInitializableTypeMetadataStaticallyAddressable (
915
- IGM, canonicalType);
916
- } else {
917
- return irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable (
918
- IGM, canonicalType);
919
- }
920
- };
921
- return !isGenericWithoutPrespecializedConformance () &&
922
- metadataAccessIsTrivial () && witnessTablesAreReferenceable ();
923
- });
924
- return allArgumentsAreStaticallyAddressable &&
925
- IGM.getTypeInfoForUnlowered (type).isFixedSize (
926
- ResilienceExpansion::Maximal);
883
+ type->getContextSubstitutionMap (IGM.getSwiftModule (), nominal);
884
+
885
+ // If we cannot statically reference type metadata for our replacement types,
886
+ // we cannot specialize.
887
+ for (auto replacementType : substitutions.getReplacementTypes ()) {
888
+ auto canonicalType = replacementType->getCanonicalType ();
889
+ if (onlyFromAccessor) {
890
+ // If an accessor is being used, then the accessor will be able to
891
+ // initialize the arguments, i.e. register classes with the ObjC
892
+ // runtime.
893
+ if (!irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable (
894
+ IGM, canonicalType)) {
895
+ return false ;
896
+ }
897
+ } else {
898
+ if (!irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable (
899
+ IGM, canonicalType)) {
900
+ return false ;
901
+ }
902
+ }
903
+ }
904
+
905
+ // If we have to instantiate resilient or dependent witness tables, we
906
+ // cannot prespecialize.
907
+ for (auto conformance : substitutions.getConformances ()) {
908
+ auto protocol = conformance.getRequirement ();
909
+ if (!Lowering::TypeConverter::protocolRequiresWitnessTable (protocol))
910
+ continue ;
911
+
912
+ if (!conformance.isConcrete ())
913
+ return false ;
914
+
915
+ auto rootConformance = conformance.getConcrete ()->getRootConformance ();
916
+ if (IGM.isDependentConformance (rootConformance) ||
917
+ IGM.isResilientConformance (rootConformance))
918
+ return false ;
919
+ }
920
+
921
+ return true ;
927
922
}
928
923
929
924
bool irgen::isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
930
- IRGenModule &IGM, NominalTypeDecl &nominal, CanType type,
925
+ IRGenModule &IGM, CanType type,
931
926
SpecializedMetadataCanonicality canonicality) {
932
927
if (isa<ClassType>(type) || isa<BoundGenericClassType>(type)) {
933
928
// TODO: On platforms without ObjC interop, we can do direct access to
934
929
// class metadata.
935
930
return false ;
936
931
}
932
+
937
933
// Prespecialized struct/enum metadata gets no dedicated accessor yet and so
938
934
// cannot do the work of registering the generic arguments which are classes
939
935
// with the ObjC runtime. Concretely, the following cannot be prespecialized
940
936
// yet:
941
937
// Struct<Klass<Int>>
942
938
// Enum<Klass<Int>>
943
939
return isSpecializedNominalTypeMetadataStaticallyAddressable (
944
- IGM, nominal, type, canonicality, NotForUseOnlyFromAccessor);
940
+ IGM, type, canonicality, NotForUseOnlyFromAccessor);
945
941
}
946
942
947
943
// / Is there a known address for canonical specialized metadata? The metadata
@@ -954,14 +950,17 @@ bool irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable(
954
950
return true ;
955
951
}
956
952
957
- NominalTypeDecl *nominal;
958
- if ((nominal = type->getAnyNominal ()) && nominal->isGenericContext ()) {
953
+ if (isa<ExistentialType>(type))
954
+ return false ;
955
+
956
+ auto *nominal = type->getAnyNominal ();
957
+ if (nominal && nominal->isGenericContext ()) {
959
958
// Prespecialized class metadata gets a dedicated accessor which can do
960
959
// the work of registering the class and its arguments with the ObjC
961
960
// runtime.
962
961
// Concretely, Clazz<Klass<Int>> can be prespecialized.
963
962
return isSpecializedNominalTypeMetadataStaticallyAddressable (
964
- IGM, *nominal, type, CanonicalSpecializedMetadata,
963
+ IGM, type, CanonicalSpecializedMetadata,
965
964
ForUseOnlyFromAccessor);
966
965
}
967
966
@@ -977,15 +976,12 @@ bool irgen::isNoncanonicalCompleteTypeMetadataStaticallyAddressable(
977
976
}
978
977
979
978
if (isa<BoundGenericStructType>(type) || isa<BoundGenericEnumType>(type)) {
980
- auto nominalType = cast<BoundGenericType>(type);
981
- auto *nominalDecl = nominalType->getDecl ();
982
-
983
979
// Imported type metadata always requires an accessor.
984
- if (isa<ClangModuleUnit>(nominalDecl ->getModuleScopeContext ()))
980
+ if (isa<ClangModuleUnit>(type-> getAnyNominal () ->getModuleScopeContext ()))
985
981
return false ;
986
982
987
983
return isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
988
- IGM, *nominalDecl, type, NoncanonicalSpecializedMetadata);
984
+ IGM, type, NoncanonicalSpecializedMetadata);
989
985
}
990
986
return false ;
991
987
}
@@ -1007,11 +1003,9 @@ bool irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable(
1007
1003
1008
1004
if (nominalDecl->isGenericContext ())
1009
1005
return isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
1010
- IGM, *nominalDecl, type, CanonicalSpecializedMetadata);
1006
+ IGM, type, CanonicalSpecializedMetadata);
1011
1007
1012
1008
auto expansion = ResilienceExpansion::Maximal;
1013
-
1014
- // Resiliently-sized metadata access always requires an accessor.
1015
1009
return IGM.getTypeInfoForUnlowered (type).isFixedSize (expansion);
1016
1010
}
1017
1011
@@ -1034,15 +1028,8 @@ bool irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable(
1034
1028
return true ;
1035
1029
1036
1030
if (isa<BoundGenericStructType>(type) || isa<BoundGenericEnumType>(type)) {
1037
- auto nominalType = cast<BoundGenericType>(type);
1038
- auto *nominalDecl = nominalType->getDecl ();
1039
-
1040
- // Imported type metadata always requires an accessor.
1041
- if (isa<ClangModuleUnit>(nominalDecl->getModuleScopeContext ()))
1042
- return false ;
1043
-
1044
1031
return isCompleteSpecializedNominalTypeMetadataStaticallyAddressable (
1045
- IGM, *nominalDecl, type, CanonicalSpecializedMetadata);
1032
+ IGM, type, CanonicalSpecializedMetadata);
1046
1033
}
1047
1034
1048
1035
return false ;
@@ -1066,7 +1053,7 @@ bool irgen::shouldCacheTypeMetadataAccess(IRGenModule &IGM, CanType type) {
1066
1053
return true ;
1067
1054
if (classDecl->isGenericContext () &&
1068
1055
isSpecializedNominalTypeMetadataStaticallyAddressable (
1069
- IGM, *classDecl, type, CanonicalSpecializedMetadata,
1056
+ IGM, type, CanonicalSpecializedMetadata,
1070
1057
ForUseOnlyFromAccessor))
1071
1058
return false ;
1072
1059
auto strategy = IGM.getClassMetadataStrategy (classDecl);
0 commit comments