diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index b9a02796d6d8a..54210b255b560 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -653,6 +653,11 @@ class ASTContext final { /// for the target platform. AvailabilityContext getCompareTypeContextDescriptorsAvailability(); + /// Get the runtime availability of the + /// swift_compareProtocolConformanceDescriptors entry point for the target + /// platform. + AvailabilityContext getCompareProtocolConformanceDescriptorsAvailability(); + /// 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 7ca3498d6cf79..4ad4b8751ab31 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -423,6 +423,21 @@ const WitnessTable *swift_getAssociatedConformanceWitness( const ProtocolRequirement *reqBase, const ProtocolRequirement *assocConformance); +/// Determine whether two protocol conformance descriptors describe the same +/// conformance of a type to a protocol. +/// +/// Runtime availability: Swift 5.4 +/// +/// \param lhs The first protocol conformance descriptor to compare. +/// \param rhs The second protocol conformance descriptor to compare. +/// +/// \returns true if both describe the same conformance, false otherwise. +SWIFT_RUNTIME_EXPORT +SWIFT_CC(swift) +bool swift_compareProtocolConformanceDescriptors( + const ProtocolConformanceDescriptor *lhs, + const ProtocolConformanceDescriptor *rhs); + /// Fetch a uniqued metadata for a function type. SWIFT_RUNTIME_EXPORT const FunctionTypeMetadata * diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 052ef6e78b7f7..910c1d2788245 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -735,6 +735,18 @@ FUNCTION(GetAssociatedConformanceWitness, ProtocolRequirementStructTy->getPointerTo()), ATTRS(NoUnwind, ReadNone)) +// SWIFT_RUNTIME_EXPORT +// SWIFT_CC(swift) bool swift_compareProtocolConformanceDescriptors( +// const ProtocolConformanceDescriptor *lhs, +// const ProtocolConformanceDescriptor *rhs); +FUNCTION(CompareProtocolConformanceDescriptors, + swift_compareProtocolConformanceDescriptors, SwiftCC, + CompareProtocolConformanceDescriptorsAvailability, + RETURNS(Int1Ty), + ARGS(ProtocolConformanceDescriptorPtrTy, + ProtocolConformanceDescriptorPtrTy), + ATTRS(NoUnwind, ReadNone)) + // Metadata *swift_getMetatypeMetadata(Metadata *instanceTy); FUNCTION(GetMetatypeMetadata, swift_getMetatypeMetadata, C_CC, AlwaysAvailable, RETURNS(TypeMetadataPtrTy), diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 4d5f7a093806d..ecdbe6451fdf8 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -299,6 +299,11 @@ AvailabilityContext ASTContext::getCompareTypeContextDescriptorsAvailability() { return getSwiftFutureAvailability(); } +AvailabilityContext +ASTContext::getCompareProtocolConformanceDescriptorsAvailability() { + return getSwiftFutureAvailability(); +} + AvailabilityContext ASTContext::getSwift52Availability() { auto target = LangOpts.Target; diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index e48694064d49c..c7d01eb932b15 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -660,6 +660,16 @@ namespace RuntimeConstants { } return RuntimeAvailability::AlwaysAvailable; } + + RuntimeAvailability + CompareProtocolConformanceDescriptorsAvailability(ASTContext &Context) { + auto featureAvailability = + Context.getCompareProtocolConformanceDescriptorsAvailability(); + 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/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index a3c94074cddb5..5703748dfc182 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -4993,6 +4993,12 @@ const WitnessTable *swift::swift_getAssociatedConformanceWitness( assocConformance); } +bool swift::swift_compareProtocolConformanceDescriptors( + const ProtocolConformanceDescriptor *lhs, + const ProtocolConformanceDescriptor *rhs) { + return MetadataCacheKey::compareProtocolConformanceDescriptors(lhs, rhs) == 0; +} + /***************************************************************************/ /*** Recursive metadata dependencies ***************************************/ /***************************************************************************/ diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h index 047f97816197d..6e471273e4702 100644 --- a/stdlib/public/runtime/MetadataCache.h +++ b/stdlib/public/runtime/MetadataCache.h @@ -386,6 +386,14 @@ class MetadataCacheKey { auto *aDescription = awt->getDescription(); auto *bDescription = bwt->getDescription(); + return compareProtocolConformanceDescriptors(aDescription, bDescription); + } + +public: + /// Compare two conformance descriptors, checking their contents if necessary. + static int compareProtocolConformanceDescriptors( + const ProtocolConformanceDescriptor *aDescription, + const ProtocolConformanceDescriptor *bDescription) { if (aDescription == bDescription) return 0; @@ -405,6 +413,7 @@ class MetadataCacheKey { bDescription->getProtocol()); } +private: /// Compare the content from two keys. static int compareContent(const void * const *adata, const void * const *bdata,