@@ -147,6 +147,90 @@ const ClassMetadata *TypeReference::getObjCClass(TypeReferenceKind kind) const {
147147}
148148#endif
149149
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+
150234// / Take the type reference inside a protocol conformance record and fetch the
151235// / canonical metadata pointer for the type it refers to.
152236// / Returns nil for universal or generic type references.
@@ -470,13 +554,10 @@ searchInConformanceCache(const Metadata *type,
470554 auto origType = type;
471555 auto snapshot = C.Cache .snapshot ();
472556
473- while ( type) {
557+ for ( auto type : iterateMaybeIncompleteSuperclasses (type) ) {
474558 if (auto *Value = snapshot.find (ConformanceCacheKey (type, protocol))) {
475559 return {type == origType, Value->getWitnessTable ()};
476560 }
477-
478- // If there is a superclass, look there.
479- type = _swift_class_getSuperclass (type);
480561 }
481562
482563 // We did not find a cache entry.
@@ -562,13 +643,10 @@ namespace {
562643 // / be a superclass of the given type. Returns null if this type does not
563644 // / match this conformance.
564645 const Metadata *getMatchingType (const Metadata *conformingType) const {
565- while ( conformingType) {
566- // Check for a match.
646+ for ( auto conformingType :
647+ iterateMaybeIncompleteSuperclasses (conformingType)) {
567648 if (matches (conformingType))
568649 return conformingType;
569-
570- // Look for a superclass.
571- conformingType = _swift_class_getSuperclass (conformingType);
572650 }
573651
574652 return nullptr ;
@@ -739,8 +817,7 @@ swift_conformsToProtocolImpl(const Metadata *const type,
739817 // Search the shared cache tables for a conformance for this type, and for
740818 // superclasses (if it's a class).
741819 if (C.sharedCacheOptimizationsActive ()) {
742- const Metadata *dyldSearchType = type;
743- do {
820+ for (auto dyldSearchType : iterateMaybeIncompleteSuperclasses (type)) {
744821 bool definitiveFailure;
745822 std::tie (dyldCachedWitnessTable, dyldCachedConformanceDescriptor,
746823 definitiveFailure) =
@@ -749,9 +826,9 @@ swift_conformsToProtocolImpl(const Metadata *const type,
749826 if (definitiveFailure)
750827 return nullptr ;
751828
752- dyldSearchType = _swift_class_getSuperclass (dyldSearchType);
753- } while (dyldSearchType && !dyldCachedWitnessTable &&
754- !dyldCachedConformanceDescriptor);
829+ if (dyldCachedWitnessTable || dyldCachedConformanceDescriptor)
830+ break ;
831+ }
755832
756833 validateSharedCacheResults (C, type, protocol, dyldCachedWitnessTable,
757834 dyldCachedConformanceDescriptor);
@@ -827,18 +904,18 @@ swift_conformsToProtocolImpl(const Metadata *const type,
827904
828905 // Find the most specific conformance that was scanned.
829906 const WitnessTable *foundWitness = nullptr ;
830- const Metadata *searchType = type ;
831- while (!foundWitness && searchType) {
907+ const Metadata *foundType = nullptr ;
908+ for ( auto searchType : iterateMaybeIncompleteSuperclasses (type) ) {
832909 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+ }
837914 }
838915
839916 // If it's for a superclass or if we didn't find anything, then add an
840917 // authoritative entry for this type.
841- if (searchType != type)
918+ if (foundType != type)
842919 C.cacheResult (type, protocol, foundWitness, snapshot.count ());
843920
844921 // A negative result can be overridden by a result from dyld.
@@ -864,67 +941,26 @@ swift::_searchConformancesByMangledTypeName(Demangle::NodePointer node) {
864941 return nullptr ;
865942}
866943
867- static MetadataState
868- tryGetCompleteMetadataNonblocking (const Metadata *metadata) {
869- return swift_checkMetadataState (
870- MetadataRequest (MetadataState::Complete, /* isNonBlocking*/ true ),
871- metadata)
872- .State ;
873- }
874-
875944template <typename HandleObjc>
876945bool isSwiftClassMetadataSubclass (const ClassMetadata *subclass,
877946 const ClassMetadata *superclass,
878947 HandleObjc handleObjc) {
879948 assert (subclass);
880949 assert (superclass);
881950
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)
925956 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+ }
928964}
929965
930966// Whether the provided `subclass` is metadata for a subclass* of the superclass
0 commit comments