Skip to content

[Runtime] Add entry point to canonicalize metadata. #32506

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
Show file tree
Hide file tree
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
40 changes: 38 additions & 2 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,8 @@ template <typename Runtime> class TargetEnumDescriptor;
template <typename Runtime> class TargetStructDescriptor;
template <typename Runtime> struct TargetGenericMetadataPattern;

using TypeContextDescriptor = TargetTypeContextDescriptor<InProcess>;

// FIXME: https://bugs.swift.org/browse/SR-1155
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winvalid-offsetof"
Expand Down Expand Up @@ -723,6 +725,10 @@ struct TargetMetadata {

bool satisfiesClassConstraint() const;

const TypeContextDescriptor *getDescription() const;

bool isStaticallySpecializedGenericMetadata() const;

bool isCanonicalStaticallySpecializedGenericMetadata() const;

#if SWIFT_OBJC_INTEROP
Expand Down Expand Up @@ -1304,6 +1310,14 @@ struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
}
#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())
Expand Down Expand Up @@ -1449,6 +1463,18 @@ struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
return reinterpret_cast<const uint32_t *>(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())
Expand Down Expand Up @@ -1525,6 +1551,18 @@ struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
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())
Expand Down Expand Up @@ -3820,8 +3858,6 @@ class TargetTypeContextDescriptor
}
};

using TypeContextDescriptor = TargetTypeContextDescriptor<InProcess>;

/// Storage for class metadata bounds. This is the variable returned
/// by getAddrOfClassMetadataBounds in the compiler.
///
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
20 changes: 20 additions & 0 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions lib/AST/Availability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ ASTContext::getCompareProtocolConformanceDescriptorsAvailability() {
return getSwiftFutureAvailability();
}

AvailabilityContext
ASTContext::getIntermodulePrespecializedGenericMetadataAvailability() {
return getSwiftFutureAvailability();
}

AvailabilityContext ASTContext::getSwift52Availability() {
auto target = LangOpts.Target;

Expand Down
11 changes: 11 additions & 0 deletions lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
61 changes: 61 additions & 0 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,11 @@ namespace {
GenericCacheEntry(MetadataCacheKey key, Args &&...args)
: VariadicMetadataCacheEntryBase(key) {}

AllocationResult allocate(const Metadata *candidate) {
return {const_cast<Metadata *>(candidate),
PrivateMetadataState::Complete};
}

AllocationResult allocate(const TypeContextDescriptor *description,
const void * const *arguments) {
// Find a pattern. Currently we always use the default pattern.
Expand Down Expand Up @@ -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<StructMetadata>(this))
return metadata->isStaticallySpecializedGenericMetadata();
if (auto *metadata = dyn_cast<EnumMetadata>(this))
return metadata->isStaticallySpecializedGenericMetadata();
if (auto *metadata = dyn_cast<ClassMetadata>(this))
return metadata->isStaticallySpecializedGenericMetadata();

return false;
}

template <> const TypeContextDescriptor *Metadata::getDescription() const {
if (auto *metadata = dyn_cast<StructMetadata>(this))
return metadata->getDescription();
if (auto *metadata = dyn_cast<EnumMetadata>(this))
return metadata->getDescription();
if (auto *metadata = dyn_cast<ClassMetadata>(this))
return metadata->getDescription();

return nullptr;
}

template <>
bool Metadata::isCanonicalStaticallySpecializedGenericMetadata() const {
if (auto *metadata = dyn_cast<StructMetadata>(this))
Expand Down Expand Up @@ -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<const Metadata *>;
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<const void *const *>(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,
Expand Down