diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index aa5ece97b10c2..97ef725102b6e 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -492,6 +492,8 @@ template class TargetEnumDescriptor; template class TargetStructDescriptor; template struct TargetGenericMetadataPattern; +using TypeContextDescriptor = TargetTypeContextDescriptor; + // FIXME: https://bugs.swift.org/browse/SR-1155 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winvalid-offsetof" @@ -723,6 +725,10 @@ struct TargetMetadata { bool satisfiesClassConstraint() const; + const TypeContextDescriptor *getDescription() const; + + bool isStaticallySpecializedGenericMetadata() const; + bool isCanonicalStaticallySpecializedGenericMetadata() const; #if SWIFT_OBJC_INTEROP @@ -1304,6 +1310,14 @@ struct TargetClassMetadata : public TargetAnyClassMetadata { } #endif + bool isStaticallySpecializedGenericMetadata() const { + auto *description = getDescription(); + if (!description->isGeneric()) + return false; + + return this->Flags & ClassFlags::IsStaticSpecialization; + } + bool isCanonicalStaticallySpecializedGenericMetadata() const { auto *description = getDescription(); if (!description->isGeneric()) @@ -1449,6 +1463,18 @@ struct TargetStructMetadata : public TargetValueMetadata { return reinterpret_cast(asWords + offset); } + bool isStaticallySpecializedGenericMetadata() const { + auto *description = getDescription(); + if (!description->isGeneric()) + return false; + + auto *trailingFlags = getTrailingFlags(); + if (trailingFlags == nullptr) + return false; + + return trailingFlags->isStaticSpecialization(); + } + bool isCanonicalStaticallySpecializedGenericMetadata() const { auto *description = getDescription(); if (!description->isGeneric()) @@ -1525,6 +1551,18 @@ struct TargetEnumMetadata : public TargetValueMetadata { return *asWords; } + bool isStaticallySpecializedGenericMetadata() const { + auto *description = getDescription(); + if (!description->isGeneric()) + return false; + + auto *trailingFlags = getTrailingFlags(); + if (trailingFlags == nullptr) + return false; + + return trailingFlags->isStaticSpecialization(); + } + bool isCanonicalStaticallySpecializedGenericMetadata() const { auto *description = getDescription(); if (!description->isGeneric()) @@ -3820,8 +3858,6 @@ class TargetTypeContextDescriptor } }; -using TypeContextDescriptor = TargetTypeContextDescriptor; - /// Storage for class metadata bounds. This is the variable returned /// by getAddrOfClassMetadataBounds in the compiler. /// diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 44aff1b7cd009..e39912ba058c0 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -658,6 +658,10 @@ class ASTContext final { /// platform. AvailabilityContext getCompareProtocolConformanceDescriptorsAvailability(); + /// Get the runtime availability of support for inter-module prespecialized + /// generic metadata. + AvailabilityContext getIntermodulePrespecializedGenericMetadataAvailability(); + /// Get the runtime availability of features introduced in the Swift 5.2 /// compiler for the target platform. AvailabilityContext getSwift52Availability(); diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 4ad4b8751ab31..8d5537ed2e94b 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -320,6 +320,26 @@ MetadataResponse swift_getSingletonMetadata(MetadataRequest request, const TypeContextDescriptor *description); +/// Fetch a uniqued metadata object for the generic nominal type described by +/// the provided candidate metadata, using that candidate metadata if there is +/// not already a canonical metadata. +/// +/// Runtime availability: Swift 5.4 +/// +/// \param candidate A prespecialized metadata record for a type which is not +/// statically made to be canonical which will be canonicalized +/// if no other canonical metadata exists for the type. +/// \param cache A pointer to a cache which will be set to the canonical +/// metadata record for the type described by the candidate +/// metadata record. If the cache has already been populated, its +/// contents will be returned. +/// \returns The canonical metadata for the specialized generic type described +/// by the provided candidate metadata. +SWIFT_RUNTIME_EXPORT SWIFT_CC(swift) MetadataResponse + swift_getCanonicalSpecializedMetadata(MetadataRequest request, + const Metadata *candidate, + const Metadata **cache); + /// Fetch a uniqued metadata object for a generic nominal type. SWIFT_RUNTIME_EXPORT SWIFT_CC(swift) MetadataResponse diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 910c1d2788245..4dac4fca66765 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -645,6 +645,14 @@ FUNCTION(GetGenericMetadata, swift_getGenericMetadata, ARGS(SizeTy, Int8PtrTy, TypeContextDescriptorPtrTy), ATTRS(NoUnwind, ReadOnly)) +// MetadataResponse swift_getCanonicalSpecializedMetadata(MetadataRequest request, +// Metadata *candidate); +FUNCTION(GetCanonicalSpecializedMetadata, swift_getCanonicalSpecializedMetadata, + SwiftCC, GetCanonicalSpecializedMetadataAvailability, + RETURNS(TypeMetadataResponseTy), + ARGS(SizeTy, TypeMetadataPtrTy, TypeMetadataPtrPtrTy), + ATTRS(NoUnwind, ReadOnly)) + // MetadataResponse swift_getOpaqueTypeMetadata(MetadataRequest request, // const void * const *arguments, // const OpaqueTypeDescriptor *descriptor, diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index a1ebba5ca9003..a28946dc49bc4 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -318,6 +318,11 @@ ASTContext::getCompareProtocolConformanceDescriptorsAvailability() { return getSwiftFutureAvailability(); } +AvailabilityContext +ASTContext::getIntermodulePrespecializedGenericMetadataAvailability() { + return getSwiftFutureAvailability(); +} + AvailabilityContext ASTContext::getSwift52Availability() { auto target = LangOpts.Target; diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index f9545f7c9a366..3005c271f6e52 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -271,6 +271,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen, MetadataKindTy // MetadataKind Kind; }); TypeMetadataPtrTy = TypeMetadataStructTy->getPointerTo(DefaultAS); + TypeMetadataPtrPtrTy = TypeMetadataPtrTy->getPointerTo(DefaultAS); TypeMetadataResponseTy = createStructType(*this, "swift.metadata_response", { TypeMetadataPtrTy, @@ -670,6 +671,16 @@ namespace RuntimeConstants { } return RuntimeAvailability::AlwaysAvailable; } + + RuntimeAvailability + GetCanonicalSpecializedMetadataAvailability(ASTContext &context) { + auto featureAvailability = + context.getIntermodulePrespecializedGenericMetadataAvailability(); + if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) { + return RuntimeAvailability::ConditionallyAvailable; + } + return RuntimeAvailability::AlwaysAvailable; + } } // namespace RuntimeConstants // We don't use enough attributes to justify generalizing the diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 1bad7269cba6a..6b3d384b73783 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -635,6 +635,7 @@ class IRGenModule { llvm::FunctionType *DeallocatingDtorTy; /// void (%swift.refcounted*) llvm::StructType *TypeMetadataStructTy; /// %swift.type = type { ... } llvm::PointerType *TypeMetadataPtrTy;/// %swift.type* + llvm::PointerType *TypeMetadataPtrPtrTy; /// %swift.type** union { llvm::StructType *TypeMetadataResponseTy; /// { %swift.type*, iSize } llvm::StructType *TypeMetadataDependencyTy; /// { %swift.type*, iSize } diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 18dc96a828c6e..2a5b1a6279f75 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -268,6 +268,11 @@ namespace { GenericCacheEntry(MetadataCacheKey key, Args &&...args) : VariadicMetadataCacheEntryBase(key) {} + AllocationResult allocate(const Metadata *candidate) { + return {const_cast(candidate), + PrivateMetadataState::Complete}; + } + AllocationResult allocate(const TypeContextDescriptor *description, const void * const *arguments) { // Find a pattern. Currently we always use the default pattern. @@ -436,6 +441,28 @@ SWIFT_ALLOWED_RUNTIME_GLOBAL_CTOR_END extern "C" void *_objc_empty_cache; #endif +template <> bool Metadata::isStaticallySpecializedGenericMetadata() const { + if (auto *metadata = dyn_cast(this)) + return metadata->isStaticallySpecializedGenericMetadata(); + if (auto *metadata = dyn_cast(this)) + return metadata->isStaticallySpecializedGenericMetadata(); + if (auto *metadata = dyn_cast(this)) + return metadata->isStaticallySpecializedGenericMetadata(); + + return false; +} + +template <> const TypeContextDescriptor *Metadata::getDescription() const { + if (auto *metadata = dyn_cast(this)) + return metadata->getDescription(); + if (auto *metadata = dyn_cast(this)) + return metadata->getDescription(); + if (auto *metadata = dyn_cast(this)) + return metadata->getDescription(); + + return nullptr; +} + template <> bool Metadata::isCanonicalStaticallySpecializedGenericMetadata() const { if (auto *metadata = dyn_cast(this)) @@ -673,6 +700,40 @@ swift::swift_allocateGenericValueMetadata(const ValueTypeDescriptor *description return metadata; } +MetadataResponse swift::swift_getCanonicalSpecializedMetadata( + MetadataRequest request, const Metadata *candidate, + const Metadata **cacheMetadataPtr) { + assert(candidate->isStaticallySpecializedGenericMetadata() && + !candidate->isCanonicalStaticallySpecializedGenericMetadata()); + auto *description = candidate->getDescription(); + assert(description); + + using CachedMetadata = std::atomic; + auto cachedMetadataAddr = ((CachedMetadata *)cacheMetadataPtr); + auto *cachedMetadata = cachedMetadataAddr->load(SWIFT_MEMORY_ORDER_CONSUME); + if (SWIFT_LIKELY(cachedMetadata != nullptr)) { + // Cached metadata pointers are always complete. + return MetadataResponse{(const Metadata *)cachedMetadata, + MetadataState::Complete}; + } + + auto &cache = getCache(*description); + assert(description->getFullGenericContextHeader().Base.NumKeyArguments == + cache.NumKeyParameters + cache.NumWitnessTables); + const void *const *arguments = + reinterpret_cast(candidate->getGenericArgs()); + auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables, + arguments); + auto result = cache.getOrInsert(key, request, candidate); + + assert( + !result.second.Value->isCanonicalStaticallySpecializedGenericMetadata()); + + cachedMetadataAddr->store(result.second.Value, std::memory_order_release); + + return result.second; +} + /// The primary entrypoint. MetadataResponse swift::swift_getGenericMetadata(MetadataRequest request,