@@ -147,6 +147,90 @@ const ClassMetadata *TypeReference::getObjCClass(TypeReferenceKind kind) const {
147
147
}
148
148
#endif
149
149
150
+ static MetadataState
151
+ tryGetCompleteMetadataNonblocking (const Metadata *metadata) {
152
+ return swift_checkMetadataState (
153
+ MetadataRequest (MetadataState::Complete, /* isNonBlocking*/ true ),
154
+ metadata)
155
+ .State ;
156
+ }
157
+
158
+ // / Get the superclass of metadata, which may be incomplete. When the metadata
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.
162
+ // /
163
+ // / If the metadata's current state is known, it may be passed in as
164
+ // / knownMetadataState. This saves the cost of retrieving that info separately.
165
+ static MetadataResponse getSuperclassForMaybeIncompleteMetadata (
166
+ const Metadata *metadata,
167
+ llvm::Optional<MetadataState> knownMetadataState) {
168
+ const ClassMetadata *classMetadata = dyn_cast<ClassMetadata>(metadata);
169
+ if (!classMetadata)
170
+ return {_swift_class_getSuperclass (metadata), MetadataState::Complete};
171
+
172
+ MetadataState metadataState;
173
+ if (knownMetadataState)
174
+ metadataState = *knownMetadataState;
175
+ else
176
+ metadataState = tryGetCompleteMetadataNonblocking (classMetadata);
177
+
178
+ if (metadataState == MetadataState::Complete) {
179
+ // The subclass metadata is complete. Fetch and return the superclass.
180
+ auto *superMetadata = getMetadataForClass (classMetadata->Superclass );
181
+ return {superMetadata, MetadataState::Complete};
182
+ }
183
+ if (metadataState == MetadataState::NonTransitiveComplete) {
184
+ // The subclass metadata is complete, but, unlike above, not transitively.
185
+ // Its Superclass field is valid, so just read that field to get to the
186
+ // superclass to proceed to the next step.
187
+ auto *superMetadata = getMetadataForClass (classMetadata->Superclass );
188
+ auto superState = tryGetCompleteMetadataNonblocking (superMetadata);
189
+ return {superMetadata, superState};
190
+ } else {
191
+ // The subclass metadata is either LayoutComplete or Abstract, so the
192
+ // Superclass field is not valid. To get to the superclass, make the
193
+ // expensive call to getSuperclassMetadata which demangles the superclass
194
+ // name from the nominal type descriptor to get the metadata for the
195
+ // superclass.
196
+ MetadataRequest request (MetadataState::Complete,
197
+ /* non-blocking*/ true );
198
+ return getSuperclassMetadata (request, classMetadata);
199
+ }
200
+ }
201
+
202
+ class MaybeIncompleteSuperclassIterator {
203
+ const Metadata *metadata;
204
+ llvm::Optional<MetadataState> state;
205
+
206
+ public:
207
+ MaybeIncompleteSuperclassIterator (const Metadata *metadata)
208
+ : metadata(metadata), state(llvm::None) {}
209
+
210
+ MaybeIncompleteSuperclassIterator &operator ++() {
211
+ auto response = getSuperclassForMaybeIncompleteMetadata (metadata, state);
212
+ metadata = response.Value ;
213
+ state = response.State ;
214
+ return *this ;
215
+ }
216
+
217
+ const Metadata *operator *() const { return metadata; }
218
+
219
+ bool operator !=(const MaybeIncompleteSuperclassIterator rhs) const {
220
+ return metadata != rhs.metadata ;
221
+ }
222
+ };
223
+
224
+ // / Return a range that will iterate over the given metadata and all its
225
+ // / superclasses in order. If the metadata is not a class, iteration will
226
+ // / provide that metadata and then stop.
227
+ iterator_range<MaybeIncompleteSuperclassIterator>
228
+ iterateMaybeIncompleteSuperclasses (const Metadata *metadata) {
229
+ return iterator_range<MaybeIncompleteSuperclassIterator>(
230
+ MaybeIncompleteSuperclassIterator (metadata),
231
+ MaybeIncompleteSuperclassIterator (nullptr ));
232
+ }
233
+
150
234
// / Take the type reference inside a protocol conformance record and fetch the
151
235
// / canonical metadata pointer for the type it refers to.
152
236
// / Returns nil for universal or generic type references.
@@ -470,13 +554,10 @@ searchInConformanceCache(const Metadata *type,
470
554
auto origType = type;
471
555
auto snapshot = C.Cache .snapshot ();
472
556
473
- while ( type) {
557
+ for ( auto type : iterateMaybeIncompleteSuperclasses (type) ) {
474
558
if (auto *Value = snapshot.find (ConformanceCacheKey (type, protocol))) {
475
559
return {type == origType, Value->getWitnessTable ()};
476
560
}
477
-
478
- // If there is a superclass, look there.
479
- type = _swift_class_getSuperclass (type);
480
561
}
481
562
482
563
// We did not find a cache entry.
@@ -562,13 +643,10 @@ namespace {
562
643
// / be a superclass of the given type. Returns null if this type does not
563
644
// / match this conformance.
564
645
const Metadata *getMatchingType (const Metadata *conformingType) const {
565
- while ( conformingType) {
566
- // Check for a match.
646
+ for ( auto conformingType :
647
+ iterateMaybeIncompleteSuperclasses (conformingType)) {
567
648
if (matches (conformingType))
568
649
return conformingType;
569
-
570
- // Look for a superclass.
571
- conformingType = _swift_class_getSuperclass (conformingType);
572
650
}
573
651
574
652
return nullptr ;
@@ -739,8 +817,7 @@ swift_conformsToProtocolImpl(const Metadata *const type,
739
817
// Search the shared cache tables for a conformance for this type, and for
740
818
// superclasses (if it's a class).
741
819
if (C.sharedCacheOptimizationsActive ()) {
742
- const Metadata *dyldSearchType = type;
743
- do {
820
+ for (auto dyldSearchType : iterateMaybeIncompleteSuperclasses (type)) {
744
821
bool definitiveFailure;
745
822
std::tie (dyldCachedWitnessTable, dyldCachedConformanceDescriptor,
746
823
definitiveFailure) =
@@ -749,9 +826,9 @@ swift_conformsToProtocolImpl(const Metadata *const type,
749
826
if (definitiveFailure)
750
827
return nullptr ;
751
828
752
- dyldSearchType = _swift_class_getSuperclass (dyldSearchType);
753
- } while (dyldSearchType && !dyldCachedWitnessTable &&
754
- !dyldCachedConformanceDescriptor);
829
+ if (dyldCachedWitnessTable || dyldCachedConformanceDescriptor)
830
+ break ;
831
+ }
755
832
756
833
validateSharedCacheResults (C, type, protocol, dyldCachedWitnessTable,
757
834
dyldCachedConformanceDescriptor);
@@ -827,18 +904,18 @@ swift_conformsToProtocolImpl(const Metadata *const type,
827
904
828
905
// Find the most specific conformance that was scanned.
829
906
const WitnessTable *foundWitness = nullptr ;
830
- const Metadata *searchType = type ;
831
- while (!foundWitness && searchType) {
907
+ const Metadata *foundType = nullptr ;
908
+ for ( auto searchType : iterateMaybeIncompleteSuperclasses (type) ) {
832
909
foundWitness = foundWitnesses.lookup (searchType);
833
-
834
- // If there's no entry here, move up to the superclass (if any).
835
- if (!foundWitness)
836
- searchType = _swift_class_getSuperclass (searchType);
910
+ if (foundWitness) {
911
+ foundType = searchType;
912
+ break ;
913
+ }
837
914
}
838
915
839
916
// If it's for a superclass or if we didn't find anything, then add an
840
917
// authoritative entry for this type.
841
- if (searchType != type)
918
+ if (foundType != type)
842
919
C.cacheResult (type, protocol, foundWitness, snapshot.count ());
843
920
844
921
// A negative result can be overridden by a result from dyld.
@@ -864,67 +941,26 @@ swift::_searchConformancesByMangledTypeName(Demangle::NodePointer node) {
864
941
return nullptr ;
865
942
}
866
943
867
- static MetadataState
868
- tryGetCompleteMetadataNonblocking (const Metadata *metadata) {
869
- return swift_checkMetadataState (
870
- MetadataRequest (MetadataState::Complete, /* isNonBlocking*/ true ),
871
- metadata)
872
- .State ;
873
- }
874
-
875
944
template <typename HandleObjc>
876
945
bool isSwiftClassMetadataSubclass (const ClassMetadata *subclass,
877
946
const ClassMetadata *superclass,
878
947
HandleObjc handleObjc) {
879
948
assert (subclass);
880
949
assert (superclass);
881
950
882
- MetadataState subclassState = tryGetCompleteMetadataNonblocking (subclass);
883
-
884
- do {
885
- if (subclassState == MetadataState::Complete) {
886
- // The subclass metadata is complete. That means not just that its
887
- // Superclass field is valid, but that the Superclass field of the
888
- // referenced class metadata is valid, and the Superclass field of the
889
- // class metadata referenced there, and so on transitively.
890
- //
891
- // Scan the superclass chains in the ClassMetadata looking for a match.
892
- while ((subclass = subclass->Superclass )) {
893
- if (subclass == superclass)
894
- return true ;
895
- }
896
- return false ;
897
- }
898
- if (subclassState == MetadataState::NonTransitiveComplete) {
899
- // The subclass metadata is complete, but, unlike above, not transitively.
900
- // Its Superclass field is valid, so just read that field to get to the
901
- // superclass to proceed to the next step.
902
- subclass = subclass->Superclass ;
903
- if (subclass->isPureObjC ()) {
904
- return handleObjc (subclass, superclass);
905
- }
906
- subclassState = tryGetCompleteMetadataNonblocking (subclass);
907
- } else {
908
- // The subclass metadata is either LayoutComplete or Abstract, so the
909
- // Superclass field is not valid. To get to the superclass, make the
910
- // expensive call to getSuperclassMetadata which demangles the superclass
911
- // name from the nominal type descriptor to get the metadata for the
912
- // superclass.
913
- MetadataRequest request (MetadataState::Complete,
914
- /* non-blocking*/ true );
915
- auto response = getSuperclassMetadata (request, subclass);
916
- auto newMetadata = response.Value ;
917
- if (auto newSubclass = dyn_cast<ClassMetadata>(newMetadata)) {
918
- subclass = newSubclass;
919
- subclassState = response.State ;
920
- } else {
921
- return handleObjc (newMetadata, superclass);
922
- }
923
- }
924
- if (subclass == superclass)
951
+ llvm::Optional<MetadataState> subclassState = llvm::None;
952
+ while (true ) {
953
+ auto response =
954
+ getSuperclassForMaybeIncompleteMetadata (subclass, subclassState);
955
+ if (response.Value == superclass)
925
956
return true ;
926
- } while (subclass);
927
- return false ;
957
+ if (!response.Value )
958
+ return false ;
959
+
960
+ subclass = dyn_cast<ClassMetadata>(response.Value );
961
+ if (!subclass || subclass->isPureObjC ())
962
+ return handleObjc (response.Value , superclass);
963
+ }
928
964
}
929
965
930
966
// Whether the provided `subclass` is metadata for a subclass* of the superclass
0 commit comments