@@ -283,18 +283,6 @@ struct MaybeIncompleteSuperclassIterator {
283
283
}
284
284
};
285
285
286
- // / Return a range that will iterate over the given metadata and all its
287
- // / superclasses in order. If the metadata is not a class, iteration will
288
- // / provide that metadata and then stop.
289
- iterator_range<MaybeIncompleteSuperclassIterator>
290
- iterateMaybeIncompleteSuperclasses (const Metadata *metadata,
291
- bool instantiateSuperclassMetadata) {
292
- return iterator_range<MaybeIncompleteSuperclassIterator>(
293
- MaybeIncompleteSuperclassIterator (metadata,
294
- instantiateSuperclassMetadata),
295
- MaybeIncompleteSuperclassIterator (nullptr , false ));
296
- }
297
-
298
286
// / Take the type reference inside a protocol conformance record and fetch the
299
287
// / canonical metadata pointer for the type it refers to.
300
288
// / Returns nil for universal or generic type references.
@@ -635,8 +623,9 @@ searchInConformanceCache(const Metadata *type,
635
623
auto origType = type;
636
624
auto snapshot = C.Cache .snapshot ();
637
625
638
- for (auto type : iterateMaybeIncompleteSuperclasses (
639
- type, instantiateSuperclassMetadata)) {
626
+ MaybeIncompleteSuperclassIterator superclassIterator{
627
+ type, instantiateSuperclassMetadata};
628
+ for (; auto type = superclassIterator.metadata ; ++superclassIterator) {
640
629
if (auto *Value = snapshot.find (ConformanceCacheKey (type, protocol))) {
641
630
return {type == origType, Value->getWitnessTable ()};
642
631
}
@@ -723,16 +712,20 @@ namespace {
723
712
724
713
// / Retrieve the type that matches the conformance candidate, which may
725
714
// / be a superclass of the given type. Returns null if this type does not
726
- // / match this conformance.
727
- const Metadata *getMatchingType (const Metadata *conformingType,
728
- bool instantiateSuperclassMetadata) const {
729
- for (auto conformingType : iterateMaybeIncompleteSuperclasses (
730
- conformingType, instantiateSuperclassMetadata)) {
715
+ // / match this conformance, along with the final metadata state of the
716
+ // / superclass iterator.
717
+ std::pair<const Metadata *, llvm::Optional<MetadataState>>
718
+ getMatchingType (const Metadata *conformingType,
719
+ bool instantiateSuperclassMetadata) const {
720
+ MaybeIncompleteSuperclassIterator superclassIterator{
721
+ conformingType, instantiateSuperclassMetadata};
722
+ for (; auto conformingType = superclassIterator.metadata ;
723
+ ++superclassIterator) {
731
724
if (matches (conformingType))
732
- return conformingType;
725
+ return { conformingType, llvm::None} ;
733
726
}
734
727
735
- return nullptr ;
728
+ return { nullptr , superclassIterator. state } ;
736
729
}
737
730
};
738
731
}
@@ -755,7 +748,8 @@ static void validateDyldResults(
755
748
continue ;
756
749
757
750
ConformanceCandidate candidate (descriptor);
758
- if (candidate.getMatchingType (type, instantiateSuperclassMetadata))
751
+ if (std::get<const Metadata *>(
752
+ candidate.getMatchingType (type, instantiateSuperclassMetadata)))
759
753
conformances.push_back (&descriptor);
760
754
}
761
755
}
@@ -915,8 +909,9 @@ findConformanceWithDyld(ConformanceState &C, const Metadata *type,
915
909
dyldResult.value );
916
910
917
911
assert (conformanceDescriptor->getProtocol () == protocol);
918
- assert (ConformanceCandidate{*conformanceDescriptor}.getMatchingType (
919
- type, instantiateSuperclassMetadata));
912
+ assert (std::get<const Metadata *>(
913
+ ConformanceCandidate{*conformanceDescriptor}.getMatchingType (
914
+ type, instantiateSuperclassMetadata)));
920
915
921
916
if (conformanceDescriptor->getGenericWitnessTable ()) {
922
917
DYLD_CONFORMANCES_LOG (
@@ -980,11 +975,29 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
980
975
const ProtocolConformanceDescriptor *dyldCachedConformanceDescriptor =
981
976
nullptr ;
982
977
978
+ // Track whether we have uninstantiated superclasses. Each time we iterate
979
+ // over our superclasses, we check the final state to see if there are more
980
+ // superclasses we haven't instantiated by calling noteFinalMetadataState.
981
+ // If we ever see Abstract, that means there are more superclasses we can't
982
+ // check yet, and we might get a false negative. We have to do this after each
983
+ // iteration (really, just the first iteration, but it's hard to keep track of
984
+ // which iteration is the first time), because another thread might
985
+ // instantiate the superclass while we're in the middle of searching. If we
986
+ // only look at the state after the last iteration, we might have hit a false
987
+ // negative before that no longer shows up.
988
+ bool hasUninstantiatedSuperclass = false ;
989
+ auto noteFinalMetadataState = [&](llvm::Optional<MetadataState> state) {
990
+ hasUninstantiatedSuperclass =
991
+ hasUninstantiatedSuperclass || state == MetadataState::Abstract;
992
+ };
993
+
983
994
// Search the shared cache tables for a conformance for this type, and for
984
995
// superclasses (if it's a class).
985
996
if (C.dyldOptimizationsActive ()) {
986
- for (auto dyldSearchType : iterateMaybeIncompleteSuperclasses (
987
- type, instantiateSuperclassMetadata)) {
997
+ MaybeIncompleteSuperclassIterator superclassIterator{
998
+ type, instantiateSuperclassMetadata};
999
+ for (; auto dyldSearchType = superclassIterator.metadata ;
1000
+ ++superclassIterator) {
988
1001
bool definitiveFailure;
989
1002
std::tie (dyldCachedWitnessTable, dyldCachedConformanceDescriptor,
990
1003
definitiveFailure) =
@@ -997,6 +1010,7 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
997
1010
if (dyldCachedWitnessTable || dyldCachedConformanceDescriptor)
998
1011
break ;
999
1012
}
1013
+ noteFinalMetadataState (superclassIterator.state );
1000
1014
1001
1015
validateDyldResults (C, type, protocol, dyldCachedWitnessTable,
1002
1016
dyldCachedConformanceDescriptor,
@@ -1025,8 +1039,8 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
1025
1039
1026
1040
if (dyldCachedConformanceDescriptor) {
1027
1041
ConformanceCandidate candidate (*dyldCachedConformanceDescriptor);
1028
- auto *matchingType =
1029
- candidate.getMatchingType (type, instantiateSuperclassMetadata);
1042
+ auto *matchingType = std::get< const Metadata *>(
1043
+ candidate.getMatchingType (type, instantiateSuperclassMetadata)) ;
1030
1044
assert (matchingType);
1031
1045
auto witness = dyldCachedConformanceDescriptor->getWitnessTable (matchingType);
1032
1046
C.cacheResult (type, protocol, witness, /* always cache*/ 0 );
@@ -1048,8 +1062,12 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
1048
1062
// The matching type is exact, so they can't go stale, and we should
1049
1063
// always cache them.
1050
1064
ConformanceCandidate candidate (descriptor);
1051
- if (auto *matchingType =
1052
- candidate.getMatchingType (type, instantiateSuperclassMetadata)) {
1065
+ const Metadata *matchingType;
1066
+ llvm::Optional<MetadataState> finalState;
1067
+ std::tie (matchingType, finalState) =
1068
+ candidate.getMatchingType (type, instantiateSuperclassMetadata);
1069
+ noteFinalMetadataState (finalState);
1070
+ if (matchingType) {
1053
1071
auto witness = descriptor.getWitnessTable (matchingType);
1054
1072
C.cacheResult (matchingType, protocol, witness, /* always cache*/ 0 );
1055
1073
foundWitnesses.insert ({matchingType, witness});
@@ -1078,9 +1096,6 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
1078
1096
const WitnessTable *foundWitness = nullptr ;
1079
1097
const Metadata *foundType = nullptr ;
1080
1098
1081
- // Use MaybeIncompleteSuperclassIterator directly so we can examine its final
1082
- // state. Complete indicates that we finished normally, Abstract indicates
1083
- // that there's an uninstantiated superclass we didn't iterate over.
1084
1099
MaybeIncompleteSuperclassIterator superclassIterator{
1085
1100
type, instantiateSuperclassMetadata};
1086
1101
for (; auto searchType = superclassIterator.metadata ; ++superclassIterator) {
@@ -1102,15 +1117,13 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
1102
1117
}
1103
1118
}
1104
1119
}
1105
-
1106
- // Do not cache negative results if there were uninstantiated superclasses we
1107
- // didn't search. They might have a conformance that will be found later.
1108
- bool hasUninstantiatedSuperclass =
1109
- superclassIterator.state == MetadataState::Abstract;
1120
+ noteFinalMetadataState (superclassIterator.state );
1110
1121
1111
1122
// If it's for a superclass or if we didn't find anything, then add an
1112
1123
// authoritative entry for this type.
1113
1124
if (foundType != type)
1125
+ // Do not cache negative results if there were uninstantiated superclasses
1126
+ // we didn't search. They might have a conformance that will be found later.
1114
1127
if (foundWitness || !hasUninstantiatedSuperclass)
1115
1128
C.cacheResult (type, protocol, foundWitness, snapshot.count ());
1116
1129
@@ -1378,8 +1391,8 @@ const Metadata *swift::findConformingSuperclass(
1378
1391
// Figure out which type we're looking for.
1379
1392
ConformanceCandidate candidate (*conformance);
1380
1393
1381
- const Metadata *conformingType =
1382
- candidate.getMatchingType (type, true /* instantiateSuperclassMetadata*/ );
1394
+ const Metadata *conformingType = std::get< const Metadata *>(
1395
+ candidate.getMatchingType (type, true /* instantiateSuperclassMetadata*/ )) ;
1383
1396
assert (conformingType);
1384
1397
return conformingType;
1385
1398
}
0 commit comments