Skip to content

[Runtime] Allow overrides or swift_getAssociated(Type|Conformance)Witness #20592

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
21 changes: 21 additions & 0 deletions stdlib/public/runtime/CompatibilityOverride.def
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
# define OVERRIDE_FOREIGN OVERRIDE
# define OVERRIDE_PROTOCOLCONFORMANCE OVERRIDE
# define OVERRIDE_KEYPATH OVERRIDE
# define OVERRIDE_WITNESSTABLE OVERRIDE
#else
# ifndef OVERRIDE_METADATALOOKUP
# define OVERRIDE_METADATALOOKUP(...)
Expand All @@ -63,6 +64,9 @@
# ifndef OVERRIDE_KEYPATH
# define OVERRIDE_KEYPATH(...)
# endif
# ifndef OVERRIDE_WITNESSTABLE
# define OVERRIDE_WITNESSTABLE(...)
# endif
#endif

OVERRIDE_METADATALOOKUP(getTypeByMangledName, const Metadata *,
Expand Down Expand Up @@ -140,6 +144,22 @@ OVERRIDE_KEYPATH(getKeyPath, const HeapObject *, , swift::,
(const void *pattern, const void *arguments),
(pattern, arguments))

OVERRIDE_WITNESSTABLE(getAssociatedTypeWitnessSlow, MetadataResponse,
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL, swift::,
(MetadataRequest request, WitnessTable *wtable,
const Metadata *conformingType,
const ProtocolRequirement *reqBase,
const ProtocolRequirement *assocType),
(request, wtable, conformingType, reqBase, assocType))

OVERRIDE_WITNESSTABLE(getAssociatedConformanceWitnessSlow, const WitnessTable *,
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL, swift::,
(WitnessTable *wtable, const Metadata *conformingType,
const Metadata *assocType,
const ProtocolRequirement *reqBase,
const ProtocolRequirement *assocConformance),
(wtable, conformingType, assocType, reqBase,
assocConformance))
#if SWIFT_OBJC_INTEROP

OVERRIDE_OBJC(dynamicCastObjCClass, const void *, , swift::,
Expand Down Expand Up @@ -183,3 +203,4 @@ OVERRIDE_FOREIGN(dynamicCastForeignClassUnconditional, const void *, , swift::,
#undef OVERRIDE_FOREIGN
#undef OVERRIDE_PROTOCOLCONFORMANCE
#undef OVERRIDE_KEYPATH
#undef OVERRIDE_WITNESSTABLE
52 changes: 46 additions & 6 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4053,13 +4053,13 @@ static StringRef findAssociatedTypeName(const ProtocolDescriptor *protocol,
return StringRef();
}

MetadataResponse
swift::swift_getAssociatedTypeWitness(MetadataRequest request,
static MetadataResponse
swift_getAssociatedTypeWitnessSlowImpl(
MetadataRequest request,
WitnessTable *wtable,
const Metadata *conformingType,
const ProtocolRequirement *reqBase,
const ProtocolRequirement *assocType) {

#ifndef NDEBUG
{
const ProtocolConformanceDescriptor *conformance = wtable->Description;
Expand All @@ -4077,7 +4077,7 @@ swift::swift_getAssociatedTypeWitness(MetadataRequest request,
unsigned witnessIndex = assocType - reqBase;
auto witness = ((const void* const *)wtable)[witnessIndex];
if (LLVM_LIKELY((uintptr_t(witness) &
ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) {
ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) {
// Cached metadata pointers are always complete.
return MetadataResponse{(const Metadata *)witness, MetadataState::Complete};
}
Expand Down Expand Up @@ -4158,7 +4158,26 @@ swift::swift_getAssociatedTypeWitness(MetadataRequest request,
return response;
}

const WitnessTable *swift::swift_getAssociatedConformanceWitness(
MetadataResponse
swift::swift_getAssociatedTypeWitness(MetadataRequest request,
WitnessTable *wtable,
const Metadata *conformingType,
const ProtocolRequirement *reqBase,
const ProtocolRequirement *assocType) {
// If the low bit of the witness is clear, it's already a metadata pointer.
unsigned witnessIndex = assocType - reqBase;
auto witness = ((const void* const *)wtable)[witnessIndex];
if (LLVM_LIKELY((uintptr_t(witness) &
ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) {
// Cached metadata pointers are always complete.
return MetadataResponse{(const Metadata *)witness, MetadataState::Complete};
}

return swift_getAssociatedTypeWitnessSlow(request, wtable, conformingType,
reqBase, assocType);
}

static const WitnessTable *swift_getAssociatedConformanceWitnessSlowImpl(
WitnessTable *wtable,
const Metadata *conformingType,
const Metadata *assocType,
Expand All @@ -4177,7 +4196,7 @@ const WitnessTable *swift::swift_getAssociatedConformanceWitness(
}
#endif

// Call the access function.
// Retrieve the witness.
unsigned witnessIndex = assocConformance - reqBase;
auto witness = ((const void* const *)wtable)[witnessIndex];
// Fast path: we've already resolved this to a witness table, so return it.
Expand Down Expand Up @@ -4222,6 +4241,26 @@ const WitnessTable *swift::swift_getAssociatedConformanceWitness(
swift_runtime_unreachable("Invalid mangled associate conformance");
}

const WitnessTable *swift::swift_getAssociatedConformanceWitness(
WitnessTable *wtable,
const Metadata *conformingType,
const Metadata *assocType,
const ProtocolRequirement *reqBase,
const ProtocolRequirement *assocConformance) {
// Retrieve the witness.
unsigned witnessIndex = assocConformance - reqBase;
auto witness = ((const void* const *)wtable)[witnessIndex];
// Fast path: we've already resolved this to a witness table, so return it.
if (LLVM_LIKELY((uintptr_t(witness) &
ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) {
return static_cast<const WitnessTable *>(witness);
}

return swift_getAssociatedConformanceWitnessSlow(wtable, conformingType,
assocType, reqBase,
assocConformance);
}

/***************************************************************************/
/*** Recursive metadata dependencies ***************************************/
/***************************************************************************/
Expand Down Expand Up @@ -4842,4 +4881,5 @@ const HeapObject *swift_getKeyPathImpl(const void *pattern,
const void *arguments);

#define OVERRIDE_KEYPATH COMPATIBILITY_OVERRIDE
#define OVERRIDE_WITNESSTABLE COMPATIBILITY_OVERRIDE
#include "CompatibilityOverride.def"
34 changes: 34 additions & 0 deletions stdlib/public/runtime/Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,40 @@ class TypeInfo {
const Metadata *findConformingSuperclass(
const Metadata *type,
const ProtocolConformanceDescriptor *conformance);

/// Retrieve an associated type witness from the given witness table.
///
/// \param wtable The witness table.
/// \param conformingType Metadata for the conforming type.
/// \param reqBase "Base" requirement used to compute the witness index
/// \param assocType Associated type descriptor.
///
/// \returns metadata for the associated type witness.
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
MetadataResponse swift_getAssociatedTypeWitnessSlow(
MetadataRequest request,
WitnessTable *wtable,
const Metadata *conformingType,
const ProtocolRequirement *reqBase,
const ProtocolRequirement *assocType);

/// Retrieve an associated conformance witness table from the given witness
/// table.
///
/// \param wtable The witness table.
/// \param conformingType Metadata for the conforming type.
/// \param assocType Metadata for the associated type.
/// \param reqBase "Base" requirement used to compute the witness index
/// \param assocConformance Associated conformance descriptor.
///
/// \returns corresponding witness table.
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
const WitnessTable *swift_getAssociatedConformanceWitnessSlow(
WitnessTable *wtable,
const Metadata *conformingType,
const Metadata *assocType,
const ProtocolRequirement *reqBase,
const ProtocolRequirement *assocConformance);
} // end namespace swift

#endif /* SWIFT_RUNTIME_PRIVATE_H */
29 changes: 28 additions & 1 deletion unittests/runtime/CompatibilityOverride.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,25 @@ using namespace swift;
bool EnableOverride;
bool Ran;

namespace {
template<typename T>
T getEmptyValue() {
return (T)0;
}

template<>
MetadataResponse getEmptyValue<MetadataResponse>() {
return MetadataResponse{nullptr, MetadataState::Complete};
}
}

#define OVERRIDE(name, ret, attrs, namespace, typedArgs, namedArgs) \
static ret name ## Override(COMPATIBILITY_UNPAREN typedArgs, \
Original_ ## name originalImpl) { \
if (!EnableOverride) \
return originalImpl namedArgs; \
Ran = true; \
return (ret)0; \
return getEmptyValue<ret>(); \
}
#include "../../stdlib/public/runtime/CompatibilityOverride.def"

Expand Down Expand Up @@ -164,4 +175,20 @@ TEST_F(CompatibilityOverrideTest, test_swift_conformsToProtocol) {
ASSERT_EQ(Result, nullptr);
}

TEST_F(CompatibilityOverrideTest, test_swift_getAssociatedTypeWitnessSlow) {
auto Result = swift_getAssociatedTypeWitnessSlow(MetadataState::Complete,
nullptr, nullptr,
nullptr, nullptr);
ASSERT_EQ(Result.Value, nullptr);
ASSERT_EQ(Result.State, MetadataState::Complete);
}

TEST_F(CompatibilityOverrideTest,
test_swift_getAssociatedConformanceWitnessSlow) {
auto Result = swift_getAssociatedConformanceWitnessSlow(
nullptr, nullptr, nullptr,
nullptr, nullptr);
ASSERT_EQ(Result, nullptr);
}

#endif