Skip to content

Commit b140802

Browse files
committed
[metadata prespecialization] Allow more noncanonical records.
Previously, noncanonical records were only allowed if one of the arguments was from the module where the record was to be emitted. Here, that restriction is lifted. Now getSpecializedGenericMetadata will, on first run, register all canonical metadata with the global cache before attempting to bless the passed-in noncanonical record, allowing noncanonical records to be for the same arguments as a canonical record (since in the case that a canonical record does exist, it will be returned).
1 parent 5114f22 commit b140802

File tree

2 files changed

+25
-53
lines changed

2 files changed

+25
-53
lines changed

lib/IRGen/MetadataRequest.cpp

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -846,57 +846,7 @@ bool irgen::isSpecializedNominalTypeMetadataStaticallyAddressable(
846846
return !isGenericWithoutPrespecializedConformance() &&
847847
metadataAccessIsTrivial() && witnessTablesAreReferenceable();
848848
});
849-
auto anyArgumentIsFromCurrentModule =
850-
llvm::any_of(environment->getGenericParams(), [&](auto parameter) {
851-
auto signature = environment->getGenericSignature();
852-
const auto protocols = signature->getRequiredProtocols(parameter);
853-
auto argument = ((Type *)parameter)->subst(substitutions);
854-
auto canonicalType = argument->getCanonicalType();
855-
856-
auto argumentIsFromCurrentModule = [&]() {
857-
if (auto *argumentNominal = argument->getAnyNominal()) {
858-
return IGM.getSwiftModule() == argumentNominal->getModuleContext();
859-
}
860-
return false;
861-
};
862-
auto anyConformanceIsFromCurrentModule = [&]() {
863-
return llvm::any_of(protocols, [&](ProtocolDecl *protocol) {
864-
auto conformance =
865-
signature->lookupConformance(canonicalType, protocol);
866-
if (!conformance.isConcrete()) {
867-
return false;
868-
}
869-
auto rootConformance =
870-
conformance.getConcrete()->getRootConformance();
871-
return IGM.getSwiftModule() ==
872-
rootConformance->getDeclContext()->getParentModule();
873-
});
874-
};
875-
876-
return argumentIsFromCurrentModule() ||
877-
anyConformanceIsFromCurrentModule();
878-
});
879849
return allArgumentsAreStaticallyAddressable &&
880-
// A type's metadata cannot be prespecialized non-canonically if it
881-
// could be specialized canonically. The reasons for that:
882-
// (1) Canonically prespecialized metadata is not registered with the
883-
// runtime; at runtime, whether canonically prespecialized
884-
// metadata exists can only be determined by calling the metadata
885-
// accessor.
886-
// (2) At compile time, there is no way to determine whether the
887-
// defining module has prespecialized metadata at a particular
888-
// argument list.
889-
// (3) Subsequent versions of the defining module may add or remove
890-
// prespecialized metadata.
891-
//
892-
// To account for that, we only allow non-canonical prespecialization
893-
// when at least one of the arguments is from the current module
894-
// where non-canonical prespecialization might occur. Consequently,
895-
// some prespecialization opportunities may be missed (such as when
896-
// an argument comes from a module which it is known the defining
897-
// module does not depend on).
898-
!((canonicality == NoncanonicalSpecializedMetadata) &&
899-
!anyArgumentIsFromCurrentModule) &&
900850
IGM.getTypeInfoForUnlowered(type).isFixedSize(
901851
ResilienceExpansion::Maximal);
902852
}

stdlib/public/runtime/Metadata.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -720,15 +720,37 @@ MetadataResponse swift::swift_getCanonicalSpecializedMetadata(
720720
auto &cache = getCache(*description);
721721
assert(description->getFullGenericContextHeader().Base.NumKeyArguments ==
722722
cache.NumKeyParameters + cache.NumWitnessTables);
723+
if (auto *classDescription = dyn_cast<ClassDescriptor>(description)) {
724+
auto canonicalMetadataAccessors = classDescription->getCanonicalMetadataPrespecializationAccessors();
725+
for (auto &canonicalMetadataAccessorPtr : canonicalMetadataAccessors) {
726+
auto *canonicalMetadataAccessor = canonicalMetadataAccessorPtr.get();
727+
auto response = canonicalMetadataAccessor(request);
728+
auto *canonicalMetadata = response.Value;
729+
const void *const *arguments =
730+
reinterpret_cast<const void *const *>(canonicalMetadata->getGenericArgs());
731+
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
732+
arguments);
733+
auto result = cache.getOrInsert(key, MetadataRequest(MetadataState::Complete, /*isNonBlocking*/true), canonicalMetadata);
734+
assert(result.second.Value == canonicalMetadata);
735+
}
736+
} else {
737+
auto canonicalMetadatas = description->getCanonicicalMetadataPrespecializations();
738+
for (auto &canonicalMetadataPtr : canonicalMetadatas) {
739+
Metadata *canonicalMetadata = canonicalMetadataPtr.get();
740+
const void *const *arguments =
741+
reinterpret_cast<const void *const *>(canonicalMetadata->getGenericArgs());
742+
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
743+
arguments);
744+
auto result = cache.getOrInsert(key, MetadataRequest(MetadataState::Complete, /*isNonBlocking*/true), canonicalMetadata);
745+
assert(result.second.Value == canonicalMetadata);
746+
}
747+
}
723748
const void *const *arguments =
724749
reinterpret_cast<const void *const *>(candidate->getGenericArgs());
725750
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
726751
arguments);
727752
auto result = cache.getOrInsert(key, request, candidate);
728753

729-
assert(
730-
!result.second.Value->isCanonicalStaticallySpecializedGenericMetadata());
731-
732754
cachedMetadataAddr->store(result.second.Value, std::memory_order_release);
733755

734756
return result.second;

0 commit comments

Comments
 (0)