Skip to content

[Runtime] Fix dyld protocol conformances. #41501

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 22, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 41 additions & 52 deletions stdlib/public/runtime/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,11 @@ _dyld_find_foreign_type_protocol_conformance_on_disk(
// Set this to 1 to enable logging of calls to the dyld shared cache conformance
// table
#if 0
#define SHARED_CACHE_LOG(fmt, ...) \
#define DYLD_CONFORMANCES_LOG(fmt, ...) \
fprintf(stderr, "PROTOCOL CONFORMANCE: " fmt "\n", __VA_ARGS__)
#define SHARED_CACHE_LOG_ENABLED 1
#else
#define SHARED_CACHE_LOG(fmt, ...) (void)0
#define DYLD_CONFORMANCES_LOG(fmt, ...) (void)0
#endif

// Enable dyld shared cache acceleration only when it's available and we have
Expand Down Expand Up @@ -462,13 +462,13 @@ struct ConformanceState {
dyldSharedCacheStart ? dyldSharedCacheStart + length : 0;
validateDyldResults = runtime::environment::
SWIFT_DEBUG_VALIDATE_SHARED_CACHE_PROTOCOL_CONFORMANCES();
SHARED_CACHE_LOG("Shared cache range is %#lx-%#lx",
dyldSharedCacheStart, dyldSharedCacheEnd);
DYLD_CONFORMANCES_LOG("Shared cache range is %#lx-%#lx",
dyldSharedCacheStart, dyldSharedCacheEnd);
} else {
SHARED_CACHE_LOG(
"Disabling shared cache optimizations due to unknown "
"optimizations version %u",
_dyld_swift_optimizations_version());
DYLD_CONFORMANCES_LOG("Disabling dyld protocol conformance "
"optimizations due to unknown "
"optimizations version %u",
_dyld_swift_optimizations_version());
dyldSharedCacheStart = 0;
dyldSharedCacheEnd = 0;
}
Expand Down Expand Up @@ -574,8 +574,8 @@ void swift::addImageProtocolConformanceBlockCallbackUnsafe(
// Sections in the shared cache are ignored in favor of the shared cache's
// pre-built tables.
if (C.inSharedCache(conformances)) {
SHARED_CACHE_LOG("Skipping conformances section %p in the shared cache",
conformances);
DYLD_CONFORMANCES_LOG(
"Skipping conformances section %p in the shared cache", conformances);
if (C.validateDyldResults)
C.DyldOptimizedSections.push_back(
ConformanceSection{conformances, conformancesSize});
Expand All @@ -584,15 +584,15 @@ void swift::addImageProtocolConformanceBlockCallbackUnsafe(
} else if (_dyld_has_preoptimized_swift_protocol_conformances(
reinterpret_cast<const mach_header *>(baseAddress))) {
// dyld may optimize images outside the shared cache. Skip those too.
SHARED_CACHE_LOG("Skipping conformances section %p optimized by dyld",
conformances);
DYLD_CONFORMANCES_LOG(
"Skipping conformances section %p optimized by dyld", conformances);
if (C.validateDyldResults)
C.DyldOptimizedSections.push_back(
ConformanceSection{conformances, conformancesSize});
return;
#endif
} else {
SHARED_CACHE_LOG(
DYLD_CONFORMANCES_LOG(
"Adding conformances section %p outside the shared cache",
conformances);
}
Expand Down Expand Up @@ -801,15 +801,15 @@ static _dyld_protocol_conformance_result getDyldSharedCacheConformance(
const ClassMetadata *objcClassMetadata,
const ContextDescriptor *description, llvm::StringRef foreignTypeIdentity) {
if (!foreignTypeIdentity.empty()) {
SHARED_CACHE_LOG(
DYLD_CONFORMANCES_LOG(
"_dyld_find_foreign_type_protocol_conformance(%p, %.*s, %zu)", protocol,
(int)foreignTypeIdentity.size(), foreignTypeIdentity.data(),
foreignTypeIdentity.size());
return _dyld_find_foreign_type_protocol_conformance(
protocol, foreignTypeIdentity.data(), foreignTypeIdentity.size());
} else {
SHARED_CACHE_LOG("_dyld_find_protocol_conformance(%p, %p, %p)", protocol,
objcClassMetadata, description);
DYLD_CONFORMANCES_LOG("_dyld_find_protocol_conformance(%p, %p, %p)",
protocol, objcClassMetadata, description);
return _dyld_find_protocol_conformance(protocol, objcClassMetadata,
description);
}
Expand All @@ -823,15 +823,17 @@ static _dyld_protocol_conformance_result getDyldOnDiskConformance(
if (&_dyld_find_foreign_type_protocol_conformance_on_disk &&
&_dyld_find_protocol_conformance_on_disk) {
if (!foreignTypeIdentity.empty()) {
SHARED_CACHE_LOG("_dyld_find_foreign_type_protocol_conformance_on_disk(%"
"p, %.*s, %zu, 0)",
protocol, (int)foreignTypeIdentity.size(),
foreignTypeIdentity.data(), foreignTypeIdentity.size());
DYLD_CONFORMANCES_LOG(
"_dyld_find_foreign_type_protocol_conformance_on_disk(%"
"p, %.*s, %zu, 0)",
protocol, (int)foreignTypeIdentity.size(), foreignTypeIdentity.data(),
foreignTypeIdentity.size());
return _dyld_find_foreign_type_protocol_conformance_on_disk(
protocol, foreignTypeIdentity.data(), foreignTypeIdentity.size(), 0);
} else {
SHARED_CACHE_LOG("_dyld_find_protocol_conformance_on_disk(%p, %p, %p, 0)",
protocol, objcClassMetadata, description);
DYLD_CONFORMANCES_LOG(
"_dyld_find_protocol_conformance_on_disk(%p, %p, %p, 0)", protocol,
objcClassMetadata, description);
return _dyld_find_protocol_conformance_on_disk(
protocol, objcClassMetadata, description, 0);
}
Expand Down Expand Up @@ -859,8 +861,9 @@ findConformanceWithDyld(ConformanceState &C, const Metadata *type,
auto objcClassMetadata = swift_getObjCClassFromMetadataConditional(type);
#if SHARED_CACHE_LOG_ENABLED
auto typeName = swift_getTypeName(type, true);
SHARED_CACHE_LOG("Looking up conformance of %.*s to %s", (int)typeName.length,
typeName.data, protocol->Name.get());
DYLD_CONFORMANCES_LOG("Looking up conformance of %.*s to %s",
(int)typeName.length, typeName.data,
protocol->Name.get());
#endif
_dyld_protocol_conformance_result dyldResult;
if (C.scanSectionsBackwards) {
Expand All @@ -878,19 +881,7 @@ findConformanceWithDyld(ConformanceState &C, const Metadata *type,
dyldResult = getDyldOnDiskConformance(C, protocol, objcClassMetadata,
description, foreignTypeIdentity);
}
if (!foreignTypeIdentity.empty()) {
SHARED_CACHE_LOG(
"_dyld_find_foreign_type_protocol_conformance(%p, %.*s, %zu)", protocol,
(int)foreignTypeIdentity.size(), foreignTypeIdentity.data(),
foreignTypeIdentity.size());
dyldResult = _dyld_find_foreign_type_protocol_conformance(
protocol, foreignTypeIdentity.data(), foreignTypeIdentity.size());
} else {
SHARED_CACHE_LOG("_dyld_find_protocol_conformance(%p, %p, %p)", protocol,
objcClassMetadata, description);
dyldResult = _dyld_find_protocol_conformance(protocol, objcClassMetadata,
description);
}

switch (dyldResult.kind) {
case _dyld_protocol_conformance_result_kind_found_descriptor: {
auto *conformanceDescriptor =
Expand All @@ -902,45 +893,43 @@ findConformanceWithDyld(ConformanceState &C, const Metadata *type,
type, instantiateSuperclassMetadata));

if (conformanceDescriptor->getGenericWitnessTable()) {
SHARED_CACHE_LOG(
"Found generic conformance descriptor %p for %s in shared "
"cache, continuing",
DYLD_CONFORMANCES_LOG(
"DYLD found generic conformance descriptor %p for %s, continuing",
conformanceDescriptor, protocol->Name.get());
return std::make_tuple(nullptr, conformanceDescriptor, false);
} else {
// When there are no generics, we can retrieve the witness table cheaply,
// so do it up front.
SHARED_CACHE_LOG("Found conformance descriptor %p for %s in shared cache",
conformanceDescriptor, protocol->Name.get());
DYLD_CONFORMANCES_LOG("DYLD Found conformance descriptor %p for %s",
conformanceDescriptor, protocol->Name.get());
auto *witnessTable = conformanceDescriptor->getWitnessTable(type);
return std::make_tuple(witnessTable, conformanceDescriptor, false);
}
break;
}
case _dyld_protocol_conformance_result_kind_found_witness_table:
// If we found a witness table then we're done.
SHARED_CACHE_LOG(
"Found witness table %p for conformance to %s in shared cache",
dyldResult.value, protocol->Name.get());
DYLD_CONFORMANCES_LOG("DYLD found witness table %p for conformance to %s",
dyldResult.value, protocol->Name.get());
return std::make_tuple(reinterpret_cast<const WitnessTable *>(dyldResult.value), nullptr,
false);
case _dyld_protocol_conformance_result_kind_not_found:
// If nothing is found, then we'll proceed with checking the runtime's
// caches and scanning conformance records.
SHARED_CACHE_LOG("Conformance to %s not found in shared cache",
protocol->Name.get());
DYLD_CONFORMANCES_LOG("DYLD did not find conformance to %s",
protocol->Name.get());
return std::make_tuple(nullptr, nullptr, false);
break;
case _dyld_protocol_conformance_result_kind_definitive_failure:
// This type is known not to conform to this protocol. Return failure
// without any further checks.
SHARED_CACHE_LOG("Found definitive failure for %s in shared cache",
protocol->Name.get());
DYLD_CONFORMANCES_LOG("DYLD found definitive failure for %s",
protocol->Name.get());
return std::make_tuple(nullptr, nullptr, true);
default:
// Other values may be added. Consider them equivalent to not_found until
// we implement code to handle them.
SHARED_CACHE_LOG(
DYLD_CONFORMANCES_LOG(
"Unknown result kind %lu from _dyld_find_protocol_conformance()",
(unsigned long)dyldResult.kind);
return std::make_tuple(nullptr, nullptr, false);
Expand Down Expand Up @@ -1015,8 +1004,8 @@ swift_conformsToProtocolMaybeInstantiateSuperclasses(
assert(matchingType);
auto witness = dyldCachedConformanceDescriptor->getWitnessTable(matchingType);
C.cacheResult(type, protocol, witness, /*always cache*/ 0);
SHARED_CACHE_LOG("Caching generic conformance to %s found in shared cache",
protocol->Name.get());
DYLD_CONFORMANCES_LOG("Caching generic conformance to %s found by DYLD",
protocol->Name.get());
return {witness, false};
}

Expand Down