Runtime: Refactor conformance cache initialization to include installation of the dyld callbacks.

This more cleanly groups together the initialization steps needed to warm up the conformance cache, so redundant work doesn't need to be done by other interested parties (such as the type-by-name lookup @lhoward's working on).
This commit is contained in:
Joe Groff
2015-12-31 16:55:25 -08:00
parent e210532690
commit d0be84e1f3

View File

@@ -2397,6 +2397,8 @@ namespace {
// Conformance Cache. // Conformance Cache.
static void _initializeCallbacksToInspectDylib();
struct ConformanceState { struct ConformanceState {
ConcurrentMap<size_t, ConformanceCacheEntry> Cache; ConcurrentMap<size_t, ConformanceCacheEntry> Cache;
std::vector<ConformanceSection> SectionsToScan; std::vector<ConformanceSection> SectionsToScan;
@@ -2405,24 +2407,18 @@ struct ConformanceState {
ConformanceState() { ConformanceState() {
SectionsToScan.reserve(16); SectionsToScan.reserve(16);
pthread_mutex_init(&SectionsToScanLock, nullptr); pthread_mutex_init(&SectionsToScanLock, nullptr);
_initializeCallbacksToInspectDylib();
} }
}; };
static Lazy<ConformanceState> Conformances; static Lazy<ConformanceState> Conformances;
// This variable is used to signal when a cache was generated and static void
// it is correct to avoid a new scan. _registerProtocolConformances(ConformanceState &C,
static unsigned ConformanceCacheGeneration = 0; const ProtocolConformanceRecord *begin,
const ProtocolConformanceRecord *end) {
void
swift::swift_registerProtocolConformances(const ProtocolConformanceRecord *begin,
const ProtocolConformanceRecord *end){
auto &C = Conformances.get();
pthread_mutex_lock(&C.SectionsToScanLock); pthread_mutex_lock(&C.SectionsToScanLock);
C.SectionsToScan.push_back(ConformanceSection{begin, end}); C.SectionsToScan.push_back(ConformanceSection{begin, end});
pthread_mutex_unlock(&C.SectionsToScanLock); pthread_mutex_unlock(&C.SectionsToScanLock);
} }
@@ -2437,7 +2433,10 @@ static void _addImageProtocolConformancesBlock(const uint8_t *conformances,
auto recordsEnd auto recordsEnd
= reinterpret_cast<const ProtocolConformanceRecord*> = reinterpret_cast<const ProtocolConformanceRecord*>
(conformances + conformancesSize); (conformances + conformancesSize);
swift_registerProtocolConformances(recordsBegin, recordsEnd);
// Conformance cache should always be sufficiently initialized by this point.
_registerProtocolConformances(Conformances.unsafeGetAlreadyInitialized(),
recordsBegin, recordsEnd);
} }
#if defined(__APPLE__) && defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
@@ -2490,26 +2489,32 @@ static int _addImageProtocolConformances(struct dl_phdr_info *info,
} }
#endif #endif
static void installCallbacksToInspectDylib() { static void _initializeCallbacksToInspectDylib() {
static OnceToken_t token; #if defined(__APPLE__) && defined(__MACH__)
auto callback = [](void*) { // Install our dyld callback.
#if defined(__APPLE__) && defined(__MACH__)
// Install our dyld callback if we haven't already.
// Dyld will invoke this on our behalf for all images that have already // Dyld will invoke this on our behalf for all images that have already
// been loaded. // been loaded.
_dyld_register_func_for_add_image(_addImageProtocolConformances); _dyld_register_func_for_add_image(_addImageProtocolConformances);
#elif defined(__ELF__) #elif defined(__ELF__)
// Search the loaded dls. Unlike the above, this only searches the already // Search the loaded dls. Unlike the above, this only searches the already
// loaded ones. // loaded ones.
// FIXME: Find a way to have this continue to happen after. // FIXME: Find a way to have this continue to happen after.
// rdar://problem/19045112 // rdar://problem/19045112
dl_iterate_phdr(_addImageProtocolConformances, nullptr); dl_iterate_phdr(_addImageProtocolConformances, nullptr);
#else #else
# error No known mechanism to inspect dynamic libraries on this platform. # error No known mechanism to inspect dynamic libraries on this platform.
#endif #endif
}; }
SWIFT_ONCE_F(token, callback, nullptr); // This variable is used to signal when a cache was generated and
// it is correct to avoid a new scan.
static unsigned ConformanceCacheGeneration = 0;
void
swift::swift_registerProtocolConformances(const ProtocolConformanceRecord *begin,
const ProtocolConformanceRecord *end){
auto &C = Conformances.get();
_registerProtocolConformances(C, begin, end);
} }
static size_t hashTypeProtocolPair(const void *type, static size_t hashTypeProtocolPair(const void *type,
@@ -2630,7 +2635,6 @@ swift::swift_conformsToProtocol(const Metadata *type,
// Install callbacks for tracking when a new dylib is loaded so we can // Install callbacks for tracking when a new dylib is loaded so we can
// scan it. // scan it.
installCallbacksToInspectDylib();
auto origType = type; auto origType = type;
unsigned numSections = 0; unsigned numSections = 0;