@@ -157,14 +157,20 @@ tryGetCompleteMetadataNonblocking(const Metadata *metadata) {
157
157
158
158
// / Get the superclass of metadata, which may be incomplete. When the metadata
159
159
// / is not sufficiently complete, then we fall back to demangling the superclass
160
- // / in the nominal type descriptor, which is slow but works. Return NULL if the
161
- // / metadata is not a class.
160
+ // / in the nominal type descriptor, which is slow but works. Return {NULL,
161
+ // / MetadataState::Complete} if the metadata is not a class, or has no
162
+ // / superclass.
162
163
// /
163
164
// / If the metadata's current state is known, it may be passed in as
164
165
// / knownMetadataState. This saves the cost of retrieving that info separately.
166
+ // /
167
+ // / When instantiateSuperclassMetadata is true, this function will instantiate
168
+ // / superclass metadata when necessary. When false, this will return {NULL,
169
+ // / MetadataState::Abstract} to indicate that there's an uninstantiated
170
+ // / superclass that was not returned.
165
171
static MetadataResponse getSuperclassForMaybeIncompleteMetadata (
166
- const Metadata *metadata,
167
- llvm::Optional<MetadataState> knownMetadataState ) {
172
+ const Metadata *metadata, llvm::Optional<MetadataState> knownMetadataState,
173
+ bool instantiateSuperclassMetadata ) {
168
174
const ClassMetadata *classMetadata = dyn_cast<ClassMetadata>(metadata);
169
175
if (!classMetadata)
170
176
return {_swift_class_getSuperclass (metadata), MetadataState::Complete};
@@ -192,36 +198,43 @@ static MetadataResponse getSuperclassForMaybeIncompleteMetadata(
192
198
// The subclass metadata is complete. Fetch and return the superclass.
193
199
auto *superMetadata = getMetadataForClass (classMetadata->Superclass );
194
200
return {superMetadata, MetadataState::Complete};
195
- }
196
- if (metadataState == MetadataState::NonTransitiveComplete) {
201
+ } else if (metadataState == MetadataState::NonTransitiveComplete) {
197
202
// The subclass metadata is complete, but, unlike above, not transitively.
198
203
// Its Superclass field is valid, so just read that field to get to the
199
204
// superclass to proceed to the next step.
200
205
auto *superMetadata = getMetadataForClass (classMetadata->Superclass );
201
206
auto superState = tryGetCompleteMetadataNonblocking (superMetadata);
202
207
return {superMetadata, superState};
203
- } else {
208
+ } else if (instantiateSuperclassMetadata) {
204
209
// The subclass metadata is either LayoutComplete or Abstract, so the
205
210
// Superclass field is not valid. To get to the superclass, make the
206
211
// expensive call to getSuperclassMetadata which demangles the superclass
207
212
// name from the nominal type descriptor to get the metadata for the
208
213
// superclass.
209
- MetadataRequest request (MetadataState::Complete ,
214
+ MetadataRequest request (MetadataState::Abstract ,
210
215
/* non-blocking*/ true );
211
216
return getSuperclassMetadata (request, classMetadata);
217
+ } else {
218
+ // The Superclass field is not valid and the caller did not request
219
+ // instantiation. Return a NULL superclass and Abstract to indicate that a
220
+ // superclass exists but is not yet instantiated.
221
+ return {nullptr , MetadataState::Abstract};
212
222
}
213
223
}
214
224
215
- class MaybeIncompleteSuperclassIterator {
225
+ struct MaybeIncompleteSuperclassIterator {
216
226
const Metadata *metadata;
217
227
llvm::Optional<MetadataState> state;
228
+ bool instantiateSuperclassMetadata;
218
229
219
- public:
220
- MaybeIncompleteSuperclassIterator (const Metadata *metadata)
221
- : metadata(metadata), state(llvm::None) {}
230
+ MaybeIncompleteSuperclassIterator (const Metadata *metadata,
231
+ bool instantiateSuperclassMetadata)
232
+ : metadata(metadata), state(llvm::None),
233
+ instantiateSuperclassMetadata (instantiateSuperclassMetadata) {}
222
234
223
235
MaybeIncompleteSuperclassIterator &operator ++() {
224
- auto response = getSuperclassForMaybeIncompleteMetadata (metadata, state);
236
+ auto response = getSuperclassForMaybeIncompleteMetadata (
237
+ metadata, state, instantiateSuperclassMetadata);
225
238
metadata = response.Value ;
226
239
state = response.State ;
227
240
return *this ;
@@ -238,10 +251,12 @@ class MaybeIncompleteSuperclassIterator {
238
251
// / superclasses in order. If the metadata is not a class, iteration will
239
252
// / provide that metadata and then stop.
240
253
iterator_range<MaybeIncompleteSuperclassIterator>
241
- iterateMaybeIncompleteSuperclasses (const Metadata *metadata) {
254
+ iterateMaybeIncompleteSuperclasses (const Metadata *metadata,
255
+ bool instantiateSuperclassMetadata) {
242
256
return iterator_range<MaybeIncompleteSuperclassIterator>(
243
- MaybeIncompleteSuperclassIterator (metadata),
244
- MaybeIncompleteSuperclassIterator (nullptr ));
257
+ MaybeIncompleteSuperclassIterator (metadata,
258
+ instantiateSuperclassMetadata),
259
+ MaybeIncompleteSuperclassIterator (nullptr , false ));
245
260
}
246
261
247
262
// / Take the type reference inside a protocol conformance record and fetch the
@@ -562,12 +577,14 @@ swift::swift_registerProtocolConformances(const ProtocolConformanceRecord *begin
562
577
// / A return value of `{ false, nullptr }` indicates nothing was cached.
563
578
static std::pair<bool , const WitnessTable *>
564
579
searchInConformanceCache (const Metadata *type,
565
- const ProtocolDescriptor *protocol) {
580
+ const ProtocolDescriptor *protocol,
581
+ bool instantiateSuperclassMetadata) {
566
582
auto &C = Conformances.get ();
567
583
auto origType = type;
568
584
auto snapshot = C.Cache .snapshot ();
569
585
570
- for (auto type : iterateMaybeIncompleteSuperclasses (type)) {
586
+ for (auto type : iterateMaybeIncompleteSuperclasses (
587
+ type, instantiateSuperclassMetadata)) {
571
588
if (auto *Value = snapshot.find (ConformanceCacheKey (type, protocol))) {
572
589
return {type == origType, Value->getWitnessTable ()};
573
590
}
@@ -655,9 +672,10 @@ namespace {
655
672
// / Retrieve the type that matches the conformance candidate, which may
656
673
// / be a superclass of the given type. Returns null if this type does not
657
674
// / match this conformance.
658
- const Metadata *getMatchingType (const Metadata *conformingType) const {
659
- for (auto conformingType :
660
- iterateMaybeIncompleteSuperclasses (conformingType)) {
675
+ const Metadata *getMatchingType (const Metadata *conformingType,
676
+ bool instantiateSuperclassMetadata) const {
677
+ for (auto conformingType : iterateMaybeIncompleteSuperclasses (
678
+ conformingType, instantiateSuperclassMetadata)) {
661
679
if (matches (conformingType))
662
680
return conformingType;
663
681
}
@@ -671,7 +689,8 @@ static void validateSharedCacheResults(
671
689
ConformanceState &C, const Metadata *type,
672
690
const ProtocolDescriptor *protocol,
673
691
const WitnessTable *dyldCachedWitnessTable,
674
- const ProtocolConformanceDescriptor *dyldCachedConformanceDescriptor) {
692
+ const ProtocolConformanceDescriptor *dyldCachedConformanceDescriptor,
693
+ bool instantiateSuperclassMetadata) {
675
694
#if USE_DYLD_SHARED_CACHE_CONFORMANCE_TABLES
676
695
if (!C.sharedCacheOptimizationsActive () || !C.validateSharedCacheResults )
677
696
return ;
@@ -684,7 +703,7 @@ static void validateSharedCacheResults(
684
703
continue ;
685
704
686
705
ConformanceCandidate candidate (descriptor);
687
- if (candidate.getMatchingType (type))
706
+ if (candidate.getMatchingType (type, instantiateSuperclassMetadata ))
688
707
conformances.push_back (&descriptor);
689
708
}
690
709
}
@@ -733,7 +752,8 @@ static void validateSharedCacheResults(
733
752
static std::tuple<const WitnessTable *, const ProtocolConformanceDescriptor *,
734
753
bool >
735
754
findSharedCacheConformance (ConformanceState &C, const Metadata *type,
736
- const ProtocolDescriptor *protocol) {
755
+ const ProtocolDescriptor *protocol,
756
+ bool instantiateSuperclassMetadata) {
737
757
#if USE_DYLD_SHARED_CACHE_CONFORMANCE_TABLES
738
758
const ContextDescriptor *description;
739
759
llvm::StringRef foreignTypeIdentity;
@@ -767,7 +787,8 @@ findSharedCacheConformance(ConformanceState &C, const Metadata *type,
767
787
dyldResult.value );
768
788
769
789
assert (conformanceDescriptor->getProtocol () == protocol);
770
- assert (ConformanceCandidate{*conformanceDescriptor}.getMatchingType (type));
790
+ assert (ConformanceCandidate{*conformanceDescriptor}.getMatchingType (
791
+ type, instantiateSuperclassMetadata));
771
792
772
793
if (conformanceDescriptor->getGenericWitnessTable ()) {
773
794
SHARED_CACHE_LOG (
@@ -818,9 +839,15 @@ findSharedCacheConformance(ConformanceState &C, const Metadata *type,
818
839
#endif
819
840
}
820
841
821
- static const WitnessTable *
822
- swift_conformsToProtocolImpl (const Metadata *const type,
823
- const ProtocolDescriptor *protocol) {
842
+ // / Check if a type conforms to a protocol, possibly instantiating superclasses
843
+ // / that have not yet been instantiated. The return value is a pair consisting
844
+ // / of the witness table for the conformance (or NULL if no conformance was
845
+ // / found), and a boolean indicating whether there are uninstantiated
846
+ // / superclasses that were not searched.
847
+ static std::pair<const WitnessTable *, bool >
848
+ swift_conformsToProtocolMaybeInstantiateSuperclasses (
849
+ const Metadata *const type, const ProtocolDescriptor *protocol,
850
+ bool instantiateSuperclassMetadata) {
824
851
auto &C = Conformances.get ();
825
852
826
853
const WitnessTable *dyldCachedWitnessTable = nullptr ;
@@ -830,51 +857,56 @@ swift_conformsToProtocolImpl(const Metadata *const type,
830
857
// Search the shared cache tables for a conformance for this type, and for
831
858
// superclasses (if it's a class).
832
859
if (C.sharedCacheOptimizationsActive ()) {
833
- for (auto dyldSearchType : iterateMaybeIncompleteSuperclasses (type)) {
860
+ for (auto dyldSearchType : iterateMaybeIncompleteSuperclasses (
861
+ type, instantiateSuperclassMetadata)) {
834
862
bool definitiveFailure;
835
863
std::tie (dyldCachedWitnessTable, dyldCachedConformanceDescriptor,
836
864
definitiveFailure) =
837
- findSharedCacheConformance (C, dyldSearchType, protocol);
865
+ findSharedCacheConformance (C, dyldSearchType, protocol,
866
+ instantiateSuperclassMetadata);
838
867
839
868
if (definitiveFailure)
840
- return nullptr ;
869
+ return { nullptr , false } ;
841
870
842
871
if (dyldCachedWitnessTable || dyldCachedConformanceDescriptor)
843
872
break ;
844
873
}
845
874
846
875
validateSharedCacheResults (C, type, protocol, dyldCachedWitnessTable,
847
- dyldCachedConformanceDescriptor);
876
+ dyldCachedConformanceDescriptor,
877
+ instantiateSuperclassMetadata);
848
878
// Return a cached result if we got a witness table. We can't do this if
849
879
// scanSectionsBackwards is set, since a scanned conformance can override a
850
880
// cached result in that case.
851
881
if (!C.scanSectionsBackwards )
852
882
if (dyldCachedWitnessTable)
853
- return dyldCachedWitnessTable;
883
+ return { dyldCachedWitnessTable, false } ;
854
884
}
855
885
856
886
// See if we have an authoritative cached conformance. The
857
887
// ConcurrentReadableHashMap data structure allows us to search the map
858
888
// concurrently without locking.
859
- auto found = searchInConformanceCache (type, protocol);
889
+ auto found =
890
+ searchInConformanceCache (type, protocol, instantiateSuperclassMetadata);
860
891
if (found.first ) {
861
892
// An authoritative negative result can be overridden by a result from dyld.
862
893
if (!found.second ) {
863
894
if (dyldCachedWitnessTable)
864
- return dyldCachedWitnessTable;
895
+ return { dyldCachedWitnessTable, false } ;
865
896
}
866
- return found.second ;
897
+ return { found.second , false } ;
867
898
}
868
899
869
900
if (dyldCachedConformanceDescriptor) {
870
901
ConformanceCandidate candidate (*dyldCachedConformanceDescriptor);
871
- auto *matchingType = candidate.getMatchingType (type);
902
+ auto *matchingType =
903
+ candidate.getMatchingType (type, instantiateSuperclassMetadata);
872
904
assert (matchingType);
873
905
auto witness = dyldCachedConformanceDescriptor->getWitnessTable (matchingType);
874
906
C.cacheResult (type, protocol, witness, /* always cache*/ 0 );
875
907
SHARED_CACHE_LOG (" Caching generic conformance to %s found in shared cache" ,
876
908
protocol->Name .get ());
877
- return witness;
909
+ return { witness, false } ;
878
910
}
879
911
880
912
// Scan conformance records.
@@ -890,7 +922,8 @@ swift_conformsToProtocolImpl(const Metadata *const type,
890
922
// The matching type is exact, so they can't go stale, and we should
891
923
// always cache them.
892
924
ConformanceCandidate candidate (descriptor);
893
- if (auto *matchingType = candidate.getMatchingType (type)) {
925
+ if (auto *matchingType =
926
+ candidate.getMatchingType (type, instantiateSuperclassMetadata)) {
894
927
auto witness = descriptor.getWitnessTable (matchingType);
895
928
C.cacheResult (matchingType, protocol, witness, /* always cache*/ 0 );
896
929
foundWitnesses.insert ({matchingType, witness});
@@ -918,7 +951,13 @@ swift_conformsToProtocolImpl(const Metadata *const type,
918
951
// Find the most specific conformance that was scanned.
919
952
const WitnessTable *foundWitness = nullptr ;
920
953
const Metadata *foundType = nullptr ;
921
- for (auto searchType : iterateMaybeIncompleteSuperclasses (type)) {
954
+
955
+ // Use MaybeIncompleteSuperclassIterator directly so we can examine its final
956
+ // state. Complete indicates that we finished normally, Abstract indicates
957
+ // that there's an uninstantiated superclass we didn't iterate over.
958
+ MaybeIncompleteSuperclassIterator superclassIterator{
959
+ type, instantiateSuperclassMetadata};
960
+ for (; auto searchType = superclassIterator.metadata ; ++superclassIterator) {
922
961
const WitnessTable *witness = foundWitnesses.lookup (searchType);
923
962
if (witness) {
924
963
if (!foundType) {
@@ -936,17 +975,49 @@ swift_conformsToProtocolImpl(const Metadata *const type,
936
975
}
937
976
}
938
977
978
+ // Do not cache negative results if there were uninstantiated superclasses we
979
+ // didn't search. They might have a conformance that will be found later.
980
+ bool hasUninstantiatedSuperclass =
981
+ superclassIterator.state == MetadataState::Abstract;
982
+
939
983
// If it's for a superclass or if we didn't find anything, then add an
940
984
// authoritative entry for this type.
941
985
if (foundType != type)
942
- C.cacheResult (type, protocol, foundWitness, snapshot.count ());
986
+ if (foundWitness || !hasUninstantiatedSuperclass)
987
+ C.cacheResult (type, protocol, foundWitness, snapshot.count ());
943
988
944
989
// A negative result can be overridden by a result from dyld.
945
- if (foundWitness) {
990
+ if (! foundWitness) {
946
991
if (dyldCachedWitnessTable)
947
- return dyldCachedWitnessTable;
992
+ return { dyldCachedWitnessTable, false } ;
948
993
}
949
- return foundWitness;
994
+ return {foundWitness, hasUninstantiatedSuperclass};
995
+ }
996
+
997
+ static const WitnessTable *
998
+ swift_conformsToProtocolImpl (const Metadata *const type,
999
+ const ProtocolDescriptor *protocol) {
1000
+ const WitnessTable *table;
1001
+ bool hasUninstantiatedSuperclass;
1002
+
1003
+ // First, try without instantiating any new superclasses. This avoids
1004
+ // an infinite loop for cases like `class Sub: Super<Sub>`. In cases like
1005
+ // that, the conformance must exist on the subclass (or at least somewhere
1006
+ // in the chain before we get to an uninstantiated superclass) so this search
1007
+ // will succeed without trying to instantiate Super while it's already being
1008
+ // instantiated.=
1009
+ std::tie (table, hasUninstantiatedSuperclass) =
1010
+ swift_conformsToProtocolMaybeInstantiateSuperclasses (
1011
+ type, protocol, false /* instantiateSuperclassMetadata*/ );
1012
+
1013
+ // If no conformance was found, and there is an uninstantiated superclass that
1014
+ // was not searched, then try the search again and instantiate all
1015
+ // superclasses.
1016
+ if (!table && hasUninstantiatedSuperclass)
1017
+ std::tie (table, hasUninstantiatedSuperclass) =
1018
+ swift_conformsToProtocolMaybeInstantiateSuperclasses (
1019
+ type, protocol, true /* instantiateSuperclassMetadata*/ );
1020
+ return table;
950
1021
}
951
1022
952
1023
const ContextDescriptor *
@@ -973,8 +1044,8 @@ bool isSwiftClassMetadataSubclass(const ClassMetadata *subclass,
973
1044
974
1045
llvm::Optional<MetadataState> subclassState = llvm::None;
975
1046
while (true ) {
976
- auto response =
977
- getSuperclassForMaybeIncompleteMetadata ( subclass, subclassState);
1047
+ auto response = getSuperclassForMaybeIncompleteMetadata (
1048
+ subclass, subclassState, true /* instantiateSuperclassMetadata */ );
978
1049
if (response.Value == superclass)
979
1050
return true ;
980
1051
if (!response.Value )
@@ -1177,7 +1248,8 @@ const Metadata *swift::findConformingSuperclass(
1177
1248
// Figure out which type we're looking for.
1178
1249
ConformanceCandidate candidate (*conformance);
1179
1250
1180
- const Metadata *conformingType = candidate.getMatchingType (type);
1251
+ const Metadata *conformingType =
1252
+ candidate.getMatchingType (type, true /* instantiateSuperclassMetadata*/ );
1181
1253
assert (conformingType);
1182
1254
return conformingType;
1183
1255
}
0 commit comments