@@ -53,7 +53,25 @@ _dyld_find_foreign_type_protocol_conformance(const void *protocol,
5353
5454LLVM_ATTRIBUTE_WEAK
5555uint32_t _dyld_swift_optimizations_version (void );
56- #endif
56+
57+ #if DYLD_FIND_PROTOCOL_ON_DISK_CONFORMANCE_DEFINED
58+ // Redeclare these functions as weak as well.
59+ LLVM_ATTRIBUTE_WEAK bool _dyld_has_preoptimized_swift_protocol_conformances (
60+ const struct mach_header *mh);
61+
62+ LLVM_ATTRIBUTE_WEAK struct _dyld_protocol_conformance_result
63+ _dyld_find_protocol_conformance_on_disk (const void *protocolDescriptor,
64+ const void *metadataType,
65+ const void *typeDescriptor,
66+ uint32_t flags);
67+
68+ LLVM_ATTRIBUTE_WEAK struct _dyld_protocol_conformance_result
69+ _dyld_find_foreign_type_protocol_conformance_on_disk (
70+ const void *protocol, const char *foreignTypeIdentityStart,
71+ size_t foreignTypeIdentityLength, uint32_t flags);
72+ #endif // DYLD_FIND_PROTOCOL_ON_DISK_CONFORMANCE_DEFINED
73+
74+ #endif // __has_include(<mach-o/dyld_priv.h>)
5775
5876// Set this to 1 to enable logging of calls to the dyld shared cache conformance
5977// table
@@ -411,19 +429,20 @@ struct ConformanceState {
411429 uintptr_t dyldSharedCacheStart;
412430 uintptr_t dyldSharedCacheEnd;
413431 bool hasOverriddenImage;
414- bool validateSharedCacheResults ;
432+ bool validateDyldResults ;
415433
416- // Only populated when validateSharedCacheResults is enabled.
417- ConcurrentReadableArray<ConformanceSection> SharedCacheSections ;
434+ // Only populated when validateDyldResults is enabled.
435+ ConcurrentReadableArray<ConformanceSection> DyldOptimizedSections ;
418436
419437 bool inSharedCache (const void *ptr) {
420438 auto uintPtr = reinterpret_cast <uintptr_t >(ptr);
421439 return dyldSharedCacheStart <= uintPtr && uintPtr < dyldSharedCacheEnd;
422440 }
423441
424- bool sharedCacheOptimizationsActive () { return dyldSharedCacheStart != 0 ; }
442+ bool dyldOptimizationsActive () { return dyldSharedCacheStart != 0 ; }
425443#else
426- bool sharedCacheOptimizationsActive () { return false ; }
444+ bool dyldOptimizationsActive () { return false ; }
445+
427446#endif
428447
429448 ConformanceState () {
@@ -441,7 +460,7 @@ struct ConformanceState {
441460 (uintptr_t )_dyld_get_shared_cache_range (&length);
442461 dyldSharedCacheEnd =
443462 dyldSharedCacheStart ? dyldSharedCacheStart + length : 0 ;
444- validateSharedCacheResults = runtime::environment::
463+ validateDyldResults = runtime::environment::
445464 SWIFT_DEBUG_VALIDATE_SHARED_CACHE_PROTOCOL_CONFORMANCES ();
446465 SHARED_CACHE_LOG (" Shared cache range is %#lx-%#lx" ,
447466 dyldSharedCacheStart, dyldSharedCacheEnd);
@@ -557,10 +576,21 @@ void swift::addImageProtocolConformanceBlockCallbackUnsafe(
557576 if (C.inSharedCache (conformances)) {
558577 SHARED_CACHE_LOG (" Skipping conformances section %p in the shared cache" ,
559578 conformances);
560- if (C.validateSharedCacheResults )
561- C.SharedCacheSections .push_back (
579+ if (C.validateDyldResults )
580+ C.DyldOptimizedSections .push_back (
581+ ConformanceSection{conformances, conformancesSize});
582+ return ;
583+ #if DYLD_FIND_PROTOCOL_ON_DISK_CONFORMANCE_DEFINED
584+ } else if (_dyld_has_preoptimized_swift_protocol_conformances (
585+ reinterpret_cast <const mach_header *>(baseAddress))) {
586+ // dyld may optimize images outside the shared cache. Skip those too.
587+ SHARED_CACHE_LOG (" Skipping conformances section %p optimized by dyld" ,
588+ conformances);
589+ if (C.validateDyldResults )
590+ C.DyldOptimizedSections .push_back (
562591 ConformanceSection{conformances, conformancesSize});
563592 return ;
593+ #endif
564594 } else {
565595 SHARED_CACHE_LOG (
566596 " Adding conformances section %p outside the shared cache" ,
@@ -705,18 +735,18 @@ namespace {
705735 };
706736}
707737
708- static void validateSharedCacheResults (
738+ static void validateDyldResults (
709739 ConformanceState &C, const Metadata *type,
710740 const ProtocolDescriptor *protocol,
711741 const WitnessTable *dyldCachedWitnessTable,
712742 const ProtocolConformanceDescriptor *dyldCachedConformanceDescriptor,
713743 bool instantiateSuperclassMetadata) {
714744#if USE_DYLD_SHARED_CACHE_CONFORMANCE_TABLES
715- if (!C.sharedCacheOptimizationsActive () || !C.validateSharedCacheResults )
745+ if (!C.dyldOptimizationsActive () || !C.validateDyldResults )
716746 return ;
717747
718748 llvm::SmallVector<const ProtocolConformanceDescriptor *, 8 > conformances;
719- for (auto §ion : C.SharedCacheSections .snapshot ()) {
749+ for (auto §ion : C.DyldOptimizedSections .snapshot ()) {
720750 for (const auto &record : section) {
721751 auto &descriptor = *record.get ();
722752 if (descriptor.getProtocol () != protocol)
@@ -765,15 +795,61 @@ static void validateSharedCacheResults(
765795#endif
766796}
767797
768- // / Query the shared cache for a protocol conformance, if supported. The return
798+ #if USE_DYLD_SHARED_CACHE_CONFORMANCE_TABLES
799+ static _dyld_protocol_conformance_result getDyldSharedCacheConformance (
800+ ConformanceState &C, const ProtocolDescriptor *protocol,
801+ const ClassMetadata *objcClassMetadata,
802+ const ContextDescriptor *description, llvm::StringRef foreignTypeIdentity) {
803+ if (!foreignTypeIdentity.empty ()) {
804+ SHARED_CACHE_LOG (
805+ " _dyld_find_foreign_type_protocol_conformance(%p, %.*s, %zu)" , protocol,
806+ (int )foreignTypeIdentity.size (), foreignTypeIdentity.data (),
807+ foreignTypeIdentity.size ());
808+ return _dyld_find_foreign_type_protocol_conformance (
809+ protocol, foreignTypeIdentity.data (), foreignTypeIdentity.size ());
810+ } else {
811+ SHARED_CACHE_LOG (" _dyld_find_protocol_conformance(%p, %p, %p)" , protocol,
812+ objcClassMetadata, description);
813+ return _dyld_find_protocol_conformance (protocol, objcClassMetadata,
814+ description);
815+ }
816+ }
817+
818+ static _dyld_protocol_conformance_result getDyldOnDiskConformance (
819+ ConformanceState &C, const ProtocolDescriptor *protocol,
820+ const ClassMetadata *objcClassMetadata,
821+ const ContextDescriptor *description, llvm::StringRef foreignTypeIdentity) {
822+ #if DYLD_FIND_PROTOCOL_ON_DISK_CONFORMANCE_DEFINED
823+ if (&_dyld_find_foreign_type_protocol_conformance_on_disk &&
824+ &_dyld_find_protocol_conformance_on_disk) {
825+ if (!foreignTypeIdentity.empty ()) {
826+ SHARED_CACHE_LOG (" _dyld_find_foreign_type_protocol_conformance_on_disk(%"
827+ " p, %.*s, %zu, 0)" ,
828+ protocol, (int )foreignTypeIdentity.size (),
829+ foreignTypeIdentity.data (), foreignTypeIdentity.size ());
830+ return _dyld_find_foreign_type_protocol_conformance_on_disk (
831+ protocol, foreignTypeIdentity.data (), foreignTypeIdentity.size (), 0 );
832+ } else {
833+ SHARED_CACHE_LOG (" _dyld_find_protocol_conformance_on_disk(%p, %p, %p, 0)" ,
834+ protocol, objcClassMetadata, description);
835+ return _dyld_find_protocol_conformance_on_disk (
836+ protocol, objcClassMetadata, description, 0 );
837+ }
838+ }
839+ #endif
840+ return {_dyld_protocol_conformance_result_kind_not_found, nullptr };
841+ }
842+ #endif
843+
844+ // / Query dyld for a protocol conformance, if supported. The return
769845// / value is a tuple consisting of the found witness table (if any), the found
770846// / conformance descriptor (if any), and a bool that's true if a failure is
771847// / definitive.
772848static std::tuple<const WitnessTable *, const ProtocolConformanceDescriptor *,
773849 bool >
774- findSharedCacheConformance (ConformanceState &C, const Metadata *type,
775- const ProtocolDescriptor *protocol,
776- bool instantiateSuperclassMetadata) {
850+ findConformanceWithDyld (ConformanceState &C, const Metadata *type,
851+ const ProtocolDescriptor *protocol,
852+ bool instantiateSuperclassMetadata) {
777853#if USE_DYLD_SHARED_CACHE_CONFORMANCE_TABLES
778854 const ContextDescriptor *description;
779855 llvm::StringRef foreignTypeIdentity;
@@ -787,6 +863,21 @@ findSharedCacheConformance(ConformanceState &C, const Metadata *type,
787863 typeName.data , protocol->Name .get ());
788864#endif
789865 _dyld_protocol_conformance_result dyldResult;
866+ if (C.scanSectionsBackwards ) {
867+ // Search "on disk" first, then shared cache.
868+ dyldResult = getDyldOnDiskConformance (C, protocol, objcClassMetadata,
869+ description, foreignTypeIdentity);
870+ if (dyldResult.kind == _dyld_protocol_conformance_result_kind_not_found)
871+ dyldResult = getDyldSharedCacheConformance (
872+ C, protocol, objcClassMetadata, description, foreignTypeIdentity);
873+ } else {
874+ // In normal operation, search the shared cache first.
875+ dyldResult = getDyldSharedCacheConformance (
876+ C, protocol, objcClassMetadata, description, foreignTypeIdentity);
877+ if (dyldResult.kind == _dyld_protocol_conformance_result_kind_not_found)
878+ dyldResult = getDyldOnDiskConformance (C, protocol, objcClassMetadata,
879+ description, foreignTypeIdentity);
880+ }
790881 if (!foreignTypeIdentity.empty ()) {
791882 SHARED_CACHE_LOG (
792883 " _dyld_find_foreign_type_protocol_conformance(%p, %.*s, %zu)" , protocol,
@@ -876,14 +967,14 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
876967
877968 // Search the shared cache tables for a conformance for this type, and for
878969 // superclasses (if it's a class).
879- if (C.sharedCacheOptimizationsActive ()) {
970+ if (C.dyldOptimizationsActive ()) {
880971 for (auto dyldSearchType : iterateMaybeIncompleteSuperclasses (
881972 type, instantiateSuperclassMetadata)) {
882973 bool definitiveFailure;
883974 std::tie (dyldCachedWitnessTable, dyldCachedConformanceDescriptor,
884975 definitiveFailure) =
885- findSharedCacheConformance (C, dyldSearchType, protocol,
886- instantiateSuperclassMetadata);
976+ findConformanceWithDyld (C, dyldSearchType, protocol,
977+ instantiateSuperclassMetadata);
887978
888979 if (definitiveFailure)
889980 return {nullptr , false };
@@ -892,9 +983,9 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
892983 break ;
893984 }
894985
895- validateSharedCacheResults (C, type, protocol, dyldCachedWitnessTable,
896- dyldCachedConformanceDescriptor,
897- instantiateSuperclassMetadata);
986+ validateDyldResults (C, type, protocol, dyldCachedWitnessTable,
987+ dyldCachedConformanceDescriptor,
988+ instantiateSuperclassMetadata);
898989 // Return a cached result if we got a witness table. We can't do this if
899990 // scanSectionsBackwards is set, since a scanned conformance can override a
900991 // cached result in that case.
0 commit comments