Skip to content

Commit cda11b9

Browse files
committed
[Runtime] Add prespecialized-caching getGenericMetadata variant.
Add a new entry point for getting generic metadata which adds the canonical metadata records attached to the nominal type descriptor to the metadata cache. Change the implementation of the primary entry-point swift_getGenericMetadata to stop looking through canonical prespecialized records. Change the implementation of swift_getCanonicalSpecializedMetadata to use the caching token attached to the nominal type descriptor to add canonical prespecialized metadata records to the metadata cache only once rather than using the cache variables to limit the number of times the attempt was made.
1 parent a68fcb1 commit cda11b9

File tree

4 files changed

+114
-64
lines changed

4 files changed

+114
-64
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "swift/ABI/Metadata.h"
2121
#include "swift/Reflection/Records.h"
22+
#include "swift/Runtime/Once.h"
2223

2324
namespace swift {
2425

@@ -340,6 +341,31 @@ SWIFT_RUNTIME_EXPORT SWIFT_CC(swift) MetadataResponse
340341
const Metadata *candidate,
341342
const Metadata **cache);
342343

344+
/// Fetch a uniqued metadata object for the generic nominal type described by
345+
/// the provided description and arguments, adding the canonical
346+
/// prespecializations attached to the type descriptor to the metadata cache on
347+
/// first run.
348+
///
349+
/// In contrast to swift_getGenericMetadata, this function is for use by
350+
/// metadata accessors for which canonical generic metadata has been specialized
351+
/// at compile time.
352+
///
353+
/// Runtime availability: Swift 5.4
354+
///
355+
/// \param request A specification of the metadata to be returned.
356+
/// \param arguments The generic arguments--metadata and witness tables--which
357+
/// the returned metadata is to have been instantiated with.
358+
/// \param description The type descriptor for the generic type whose
359+
/// generic metadata is to have been instantiated.
360+
/// \param token The token that ensures that prespecialized records are added to
361+
/// the metadata cache only once.
362+
/// \returns The canonical metadata for the specialized generic type described
363+
/// by the provided candidate metadata.
364+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift) MetadataResponse
365+
swift_getCanonicalPrespecializedGenericMetadata(
366+
MetadataRequest request, const void *const *arguments,
367+
const TypeContextDescriptor *description, swift_once_t *token);
368+
343369
/// Fetch a uniqued metadata object for a generic nominal type.
344370
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
345371
MetadataResponse

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,18 @@ FUNCTION(GetCanonicalSpecializedMetadata, swift_getCanonicalSpecializedMetadata,
653653
ARGS(SizeTy, TypeMetadataPtrTy, TypeMetadataPtrPtrTy),
654654
ATTRS(NoUnwind, ReadOnly))
655655

656+
// MetadataResponse
657+
// swift_getCanonicalPrespecializedGenericMetadata(MetadataRequest request,
658+
// const void * const *arguments,
659+
// const TypeContextDescriptor *description,
660+
// swift_once_t *cachedFlag)
661+
FUNCTION(GetCanonicalPrespecializedGenericMetadata,
662+
swift_getCanonicalPrespecializedGenericMetadata,
663+
SwiftCC, GetCanonicalPrespecializedGenericMetadataAvailability,
664+
RETURNS(TypeMetadataResponseTy),
665+
ARGS(SizeTy, Int8PtrTy, TypeContextDescriptorPtrTy, OnceTy->getPointerTo()),
666+
ATTRS(NoUnwind, ReadOnly))
667+
656668
// MetadataResponse swift_getOpaqueTypeMetadata(MetadataRequest request,
657669
// const void * const *arguments,
658670
// const OpaqueTypeDescriptor *descriptor,

lib/IRGen/IRGenModule.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,16 @@ namespace RuntimeConstants {
697697
return RuntimeAvailability::AlwaysAvailable;
698698
}
699699

700+
RuntimeAvailability
701+
GetCanonicalPrespecializedGenericMetadataAvailability(ASTContext &context) {
702+
auto featureAvailability =
703+
context.getPrespecializedGenericMetadataAvailability();
704+
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
705+
return RuntimeAvailability::ConditionallyAvailable;
706+
}
707+
return RuntimeAvailability::AlwaysAvailable;
708+
}
709+
700710
RuntimeAvailability ConcurrencyAvailability(ASTContext &context) {
701711
auto featureAvailability = context.getConcurrencyAvailability();
702712
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {

stdlib/public/runtime/Metadata.cpp

Lines changed: 66 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -706,24 +706,13 @@ swift::swift_allocateGenericValueMetadata(const ValueTypeDescriptor *description
706706
return metadata;
707707
}
708708

709-
MetadataResponse swift::swift_getCanonicalSpecializedMetadata(
710-
MetadataRequest request, const Metadata *candidate,
711-
const Metadata **cacheMetadataPtr) {
712-
assert(candidate->isStaticallySpecializedGenericMetadata() &&
713-
!candidate->isCanonicalStaticallySpecializedGenericMetadata());
714-
auto *description = candidate->getDescription();
715-
assert(description);
716-
717-
using CachedMetadata = std::atomic<const Metadata *>;
718-
auto cachedMetadataAddr = ((CachedMetadata *)cacheMetadataPtr);
719-
auto *cachedMetadata = cachedMetadataAddr->load(SWIFT_MEMORY_ORDER_CONSUME);
720-
if (SWIFT_LIKELY(cachedMetadata != nullptr)) {
721-
// Cached metadata pointers are always complete.
722-
return MetadataResponse{(const Metadata *)cachedMetadata,
723-
MetadataState::Complete};
724-
}
725-
709+
// Look into the canonical prespecialized metadata attached to the type
710+
// descriptor and add them to the metadata cache.
711+
static void
712+
_cacheCanonicalSpecializedMetadata(const TypeContextDescriptor *description) {
726713
auto &cache = getCache(*description);
714+
auto request =
715+
MetadataRequest(MetadataState::Complete, /*isNonBlocking*/ true);
727716
assert(description->getFullGenericContextHeader().Base.NumKeyArguments ==
728717
cache.NumKeyParameters + cache.NumWitnessTables);
729718
if (auto *classDescription = dyn_cast<ClassDescriptor>(description)) {
@@ -753,8 +742,47 @@ MetadataResponse swift::swift_getCanonicalSpecializedMetadata(
753742
assert(result.second.Value == canonicalMetadata);
754743
}
755744
}
745+
}
746+
747+
static void
748+
cacheCanonicalSpecializedMetadata(const TypeContextDescriptor *description,
749+
swift_once_t *token) {
750+
swift_once(
751+
token,
752+
[](void *uncastDescription) {
753+
auto *description = (const TypeContextDescriptor *)uncastDescription;
754+
_cacheCanonicalSpecializedMetadata(description);
755+
},
756+
(void *)description);
757+
}
758+
759+
MetadataResponse swift::swift_getCanonicalSpecializedMetadata(
760+
MetadataRequest request, const Metadata *candidate,
761+
const Metadata **cacheMetadataPtr) {
762+
assert(candidate->isStaticallySpecializedGenericMetadata() &&
763+
!candidate->isCanonicalStaticallySpecializedGenericMetadata());
764+
auto *description = candidate->getDescription();
765+
assert(description);
766+
767+
using CachedMetadata = std::atomic<const Metadata *>;
768+
auto cachedMetadataAddr = ((CachedMetadata *)cacheMetadataPtr);
769+
auto *cachedMetadata = cachedMetadataAddr->load(SWIFT_MEMORY_ORDER_CONSUME);
770+
if (SWIFT_LIKELY(cachedMetadata != nullptr)) {
771+
// Cached metadata pointers are always complete.
772+
return MetadataResponse{(const Metadata *)cachedMetadata,
773+
MetadataState::Complete};
774+
}
775+
776+
if (auto *token =
777+
description
778+
->getCanonicalMetadataPrespecializationCachingOnceToken()) {
779+
cacheCanonicalSpecializedMetadata(description, token);
780+
// NOTE: If there is no token, then there are no canonical prespecialized
781+
// metadata records, either.
782+
}
756783
const void *const *arguments =
757784
reinterpret_cast<const void *const *>(candidate->getGenericArgs());
785+
auto &cache = getCache(*description);
758786
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
759787
arguments);
760788
auto result = cache.getOrInsert(key, request, candidate);
@@ -764,64 +792,38 @@ MetadataResponse swift::swift_getCanonicalSpecializedMetadata(
764792
return result.second;
765793
}
766794

767-
// Look into the canonical prespecialized metadata attached to the type
768-
// descriptor and return matching records, if any.
769-
static Metadata *
770-
findCanonicalSpecializedMetadata(MetadataRequest request,
771-
const void *const *arguments,
772-
const TypeContextDescriptor *description) {
795+
SWIFT_CC(swift)
796+
static MetadataResponse
797+
_swift_getGenericMetadata(MetadataRequest request, const void *const *arguments,
798+
const TypeContextDescriptor *description) {
773799
auto &cache = getCache(*description);
800+
assert(description->getFullGenericContextHeader().Base.NumKeyArguments ==
801+
cache.NumKeyParameters + cache.NumWitnessTables);
774802
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
775803
arguments);
776-
auto prespecializedMetadatas =
777-
description->getCanonicicalMetadataPrespecializations();
778-
int index = 0;
779-
for (auto &prespecializedMetadataPtr : prespecializedMetadatas) {
780-
Metadata *prespecializationMetadata = prespecializedMetadataPtr.get();
781-
const void *const *prespecializationArguments =
782-
reinterpret_cast<const void *const *>(
783-
prespecializationMetadata->getGenericArgs());
784-
auto prespecializationKey =
785-
MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
786-
prespecializationArguments);
787-
if (key == prespecializationKey) {
788-
if (auto *classDescription = dyn_cast<ClassDescriptor>(description)) {
789-
auto canonicalMetadataAccessors =
790-
classDescription->getCanonicalMetadataPrespecializationAccessors();
791-
auto &canonicalMetadataAccessorPtr = canonicalMetadataAccessors[index];
792-
auto *canonicalMetadataAccessor = canonicalMetadataAccessorPtr.get();
793-
auto response = canonicalMetadataAccessor(request);
794-
return const_cast<Metadata *>(response.Value);
795-
} else {
796-
return prespecializationMetadata;
797-
}
798-
}
799-
++index;
800-
}
801-
return nullptr;
804+
auto result = cache.getOrInsert(key, request, description, arguments);
805+
806+
return result.second;
802807
}
803808

804809
/// The primary entrypoint.
805810
MetadataResponse
806811
swift::swift_getGenericMetadata(MetadataRequest request,
807-
const void * const *arguments,
812+
const void *const *arguments,
808813
const TypeContextDescriptor *description) {
809-
description = swift_auth_data_non_address(description, SpecialPointerAuthDiscriminators::TypeDescriptor);
810-
if (auto *prespecialization =
811-
findCanonicalSpecializedMetadata(request, arguments, description)) {
812-
return {prespecialization, MetadataState::Complete};
813-
}
814-
auto &cache = getCache(*description);
815-
assert(description->getFullGenericContextHeader().Base.NumKeyArguments ==
816-
cache.NumKeyParameters + cache.NumWitnessTables);
817-
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
818-
arguments);
819-
auto result = cache.getOrInsert(key, request, description, arguments);
814+
description = swift_auth_data_non_address(
815+
description, SpecialPointerAuthDiscriminators::TypeDescriptor);
816+
return _swift_getGenericMetadata(request, arguments, description);
817+
}
820818

821-
assert(
822-
!result.second.Value->isCanonicalStaticallySpecializedGenericMetadata());
819+
MetadataResponse swift::swift_getCanonicalPrespecializedGenericMetadata(
820+
MetadataRequest request, const void *const *arguments,
821+
const TypeContextDescriptor *description, swift_once_t *token) {
822+
description = swift_auth_data_non_address(
823+
description, SpecialPointerAuthDiscriminators::TypeDescriptor);
824+
cacheCanonicalSpecializedMetadata(description, token);
823825

824-
return result.second;
826+
return _swift_getGenericMetadata(request, arguments, description);
825827
}
826828

827829
/***************************************************************************/

0 commit comments

Comments
 (0)