[ABI] Use mangled names for associated type witnesses.

Rather than storing associated type metadata access functions in
witness tables, initially store a pointer to a mangled type name.
On first access, demangle that type name and replace the witness
table entry with the resulting type metadata.

This reduces the code size of protocol conformances, because we no
longer need to create associated type metadata access functions for
every associated type, and the mangled names are much smaller (and
sharable). The same code size improvements apply to defaulted
associated types for resilient protocols, although those are more
rare. Witness tables themselves are slightly smaller, because we
don’t need separate private entries in them to act as caches.

On the caller side, associated type metadata is always produced via
a call to swift_getAssociatedTypeWitness(), which handles the demangling
and caching behavior.

In all, this reduces the size of the standard library by ~70k. There
are additional code-size wins that are possible with follow-on work:

* We can stop emitting type metadata access functions for non-resilient
types that have constant metadata (like `Int`), because they’re only
currently used as associated type metadata access functions.
* We can stop emitting separate associated type reflection metadata,
because the reflection infrastructure can use these mangled names
directly.
This commit is contained in:
Doug Gregor
2018-09-21 17:15:15 -07:00
parent 98b84734ba
commit b531b3923f
13 changed files with 192 additions and 229 deletions

View File

@@ -1700,11 +1700,6 @@ using TargetWitnessTablePointer =
using WitnessTablePointer = TargetWitnessTablePointer<InProcess>;
using AssociatedTypeAccessFunction =
SWIFT_CC(swift) MetadataResponse(MetadataRequest request,
const Metadata *self,
const WitnessTable *selfConformance);
using AssociatedWitnessTableAccessFunction =
SWIFT_CC(swift) WitnessTable *(const Metadata *associatedType,
const Metadata *self,

View File

@@ -580,6 +580,12 @@ public:
bool isInstance() const { return Value & IsInstanceMask; }
int_type getIntValue() const { return Value; }
enum : uintptr_t {
/// Bit used to indicate that an associated type witness is a pointer to
/// a mangled name (vs. a pointer to metadata).
AssociatedTypeMangledNameMask = 0x01
};
};
/// Flags that go in a TargetConformanceDescriptor structure.

View File

@@ -410,6 +410,20 @@ swift_getGenericWitnessTable(GenericWitnessTable *genericTable,
const Metadata *type,
void **const *instantiationArgs);
/// Retrieve an associated type witness from the given witness table.
///
/// \param wtable The witness table.
/// \param conformingType Metadata for the conforming type.
/// \param assocType Associated type descriptor.
///
/// \returns metadata for the associated type witness.
SWIFT_RUNTIME_EXPORT
MetadataResponse swift_getAssociatedTypeWitness(
MetadataRequest request,
WitnessTable *wtable,
const Metadata *conformingType,
const ProtocolRequirement *assocType);
/// \brief Fetch a uniqued metadata for a function type.
SWIFT_RUNTIME_EXPORT
const FunctionTypeMetadata *

View File

@@ -645,6 +645,19 @@ FUNCTION(GetGenericWitnessTable, swift_getGenericWitnessTable, C_CC,
WitnessTablePtrPtrTy),
ATTRS(NoUnwind, ReadOnly))
// MetadataResponse swift_getAssociatedTypeWitness(
// MetadataRequest request,
// WitnessTable *wtable,
// const Metadata *conformingType,
// ProtocolRequirement *assocType);
FUNCTION(GetAssociatedTypeWitness, swift_getAssociatedTypeWitness, C_CC,
RETURNS(TypeMetadataResponseTy),
ARGS(SizeTy,
WitnessTablePtrTy,
TypeMetadataPtrTy,
ProtocolRequirementStructTy->getPointerTo()),
ATTRS(NoUnwind))
// Metadata *swift_getMetatypeMetadata(Metadata *instanceTy);
FUNCTION(GetMetatypeMetadata, swift_getMetatypeMetadata, C_CC,
RETURNS(TypeMetadataPtrTy),

View File

@@ -765,51 +765,15 @@ namespace {
entry.getAssociatedTypeWitness().Requirement != assocType)
continue;
auto witness = entry.getAssociatedTypeWitness().Witness;
return getDefaultAssociatedTypeMetadataAccessFunction(
AssociatedType(assocType), witness);
auto witness =
entry.getAssociatedTypeWitness().Witness->mapTypeOutOfContext()
->getCanonicalType();
return IGM.getAssociatedTypeWitness(witness);
}
return nullptr;
}
/// Create an associated type metadata access function for the default
/// associated type witness.
llvm::Constant *getDefaultAssociatedTypeMetadataAccessFunction(
AssociatedType requirement, CanType witness) {
auto accessor =
IGM.getAddrOfDefaultAssociatedTypeMetadataAccessFunction(requirement);
IRGenFunction IGF(IGM, accessor);
if (IGM.DebugInfo)
IGM.DebugInfo->emitArtificialFunction(IGF, accessor);
Explosion parameters = IGF.collectParameters();
auto request = DynamicMetadataRequest(parameters.claimNext());
llvm::Value *self = parameters.claimNext();
llvm::Value *wtable = parameters.claimNext();
CanType selfInContext =
Proto->mapTypeIntoContext(Proto->getProtocolSelfType())
->getCanonicalType();
// Bind local Self type data from the metadata argument.
IGF.bindLocalTypeDataFromTypeMetadata(selfInContext, IsExact, self,
MetadataState::Abstract);
IGF.setUnscopedLocalTypeData(
selfInContext,
LocalTypeDataKind::forAbstractProtocolWitnessTable(Proto),
wtable);
// Emit a reference to the type metadata.
auto response = IGF.emitTypeMetadataRef(witness, request);
response.ensureDynamicState(IGF);
auto returnValue = response.combine(IGF);
IGF.Builder.CreateRet(returnValue);
return accessor;
}
llvm::Constant *findDefaultAssociatedConformanceWitness(
CanType association,
ProtocolDecl *requirement) {

View File

@@ -1369,12 +1369,10 @@ llvm::Value *uniqueForeignWitnessTableRef(IRGenFunction &IGF,
#endif
auto associate =
ConformanceInContext.getTypeWitness(
requirement.getAssociation(), nullptr)->getCanonicalType();
llvm::Constant *metadataAccessFunction =
getAssociatedTypeMetadataAccessFunction(requirement, associate);
Table.addBitCast(metadataAccessFunction, IGM.Int8PtrTy);
Conformance.getTypeWitness(requirement.getAssociation(), nullptr)
->getCanonicalType();
llvm::Constant *witness = IGM.getAssociatedTypeWitness(associate);
Table.addBitCast(witness, IGM.Int8PtrTy);
}
void addAssociatedConformance(AssociatedConformance requirement) {
@@ -1433,10 +1431,6 @@ llvm::Value *uniqueForeignWitnessTableRef(IRGenFunction &IGF,
llvm::Constant *buildInstantiationFunction();
llvm::Constant *
getAssociatedTypeMetadataAccessFunction(AssociatedType requirement,
CanType associatedType);
llvm::Constant *
getAssociatedTypeWitnessTableAccessFunction(
AssociatedConformance requirement,
@@ -1506,99 +1500,20 @@ void WitnessTableBuilder::build() {
TableSize = Table.size();
}
/// Return the address of a function which will return the type metadata
/// for an associated type.
llvm::Constant *WitnessTableBuilder::
getAssociatedTypeMetadataAccessFunction(AssociatedType requirement,
CanType associatedType) {
// If the associated type is non-dependent, we can use an ordinary
// metadata access function. We'll just end up passing extra arguments.
bool hasArchetype = associatedType->hasArchetype();
if (!hasArchetype && !ResilientConformance) {
return getOrCreateTypeMetadataAccessFunction(IGM, associatedType);
}
llvm::Constant *IRGenModule::getAssociatedTypeWitness(CanType type) {
// FIXME: If we can directly reference constant type metadata, do so.
// Otherwise, emit an access function.
llvm::Function *accessor =
IGM.getAddrOfAssociatedTypeMetadataAccessFunction(&Conformance,
requirement);
if (IGM.getOptions().optimizeForSize())
accessor->addFnAttr(llvm::Attribute::NoInline);
// Form a reference to the mangled name for this type.
assert(!type->hasArchetype() && "type cannot contain archetypes");
auto typeRef = getTypeRef(type, /*alignment=*/2);
IRGenFunction IGF(IGM, accessor);
if (IGM.DebugInfo)
IGM.DebugInfo->emitArtificialFunction(IGF, accessor);
Explosion parameters = IGF.collectParameters();
auto request = DynamicMetadataRequest(parameters.claimNext());
llvm::Value *self = parameters.claimNext();
setTypeMetadataName(IGM, self, ConcreteType);
Address destTable(parameters.claimNext(), IGM.getPointerAlignment());
setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType,
requirement.getSourceProtocol());
// If the type witness does not involve any type parameters, directly
// reference the type metadata. We only needed a thunk so it could be
// relatively referenced.
if (!hasArchetype) {
assert(ResilientConformance &&
"Non-resilient conformances refer to accessor directly");
auto response = IGF.emitTypeMetadataRef(associatedType, request);
response.ensureDynamicState(IGF);
auto returnValue = response.combine(IGF);
IGF.Builder.CreateRet(returnValue);
return accessor;
}
IGF.bindLocalTypeDataFromSelfWitnessTable(
&Conformance,
destTable.getAddress(),
[&](CanType type) {
return Conformance.getDeclContext()->mapTypeIntoContext(type)
->getCanonicalType();
});
// If the associated type is directly fulfillable from the type,
// we don't need a cache entry.
// TODO: maybe we should have a cache entry anyway if the fulfillment
// is expensive.
if (auto fulfillment =
getFulfillmentMap().getTypeMetadata(associatedType)) {
// We don't know that 'self' is any better than an abstract metadata here.
auto source = MetadataResponse::forBounded(self, MetadataState::Abstract);
MetadataResponse response =
fulfillment->Path.followFromTypeMetadata(IGF, ConcreteType, source,
request, /*cache*/ nullptr);
response.ensureDynamicState(IGF);
auto returnValue = response.combine(IGF);
IGF.Builder.CreateRet(returnValue);
return accessor;
}
// Bind local type data from the metadata argument.
IGF.bindLocalTypeDataFromTypeMetadata(ConcreteType, IsExact, self,
MetadataState::Abstract);
// For now, assume that an associated type is cheap enough to access
// that it doesn't need a new cache entry.
if (auto archetype = dyn_cast<ArchetypeType>(associatedType)) {
auto response = emitArchetypeTypeMetadataRef(IGF, archetype, request);
response.ensureDynamicState(IGF);
auto returnValue = response.combine(IGF);
IGF.Builder.CreateRet(returnValue);
return accessor;
}
// Otherwise, we need a cache entry.
emitReturnOfCheckedLoadFromCache(IGF, destTable, self,
[&]() -> MetadataResponse {
return IGF.emitTypeMetadataRef(associatedType, request);
});
return accessor;
// Set the low bit to indicate that this is a mangled name.
auto witness = llvm::ConstantExpr::getPtrToInt(typeRef, IntPtrTy);
auto bit = llvm::ConstantInt::get(
IntPtrTy,
ProtocolRequirementFlags::AssociatedTypeMangledNameMask);
witness = llvm::ConstantExpr::getAdd(witness, bit);
return llvm::ConstantExpr::getIntToPtr(witness, Int8PtrTy);
}
/// Return a function which will return a particular witness table
@@ -1908,14 +1823,11 @@ llvm::Constant *WitnessTableBuilder::emitResilientWitnessTable() {
table.addRelativeAddress(assocTypeDescriptor);
// Associated type metadata access function.
auto associate =
ConformanceInContext.getTypeWitness(assocType, nullptr)
auto associate = Conformance.getTypeWitness(assocType, nullptr)
->getCanonicalType();
llvm::Constant *metadataAccessFunction =
getAssociatedTypeMetadataAccessFunction(AssociatedType(assocType),
associate);
table.addRelativeAddress(metadataAccessFunction);
llvm::Constant *witness = IGM.getAssociatedTypeWitness(associate);
table.addRelativeAddress(witness);
continue;
}
@@ -3624,46 +3536,18 @@ irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF,
llvm::Value *wtable,
AssociatedType associatedType,
DynamicMetadataRequest request) {
llvm::Value *witness;
auto &IGM = IGF.IGM;
if (IGM.isResilient(associatedType.getSourceProtocol(),
ResilienceExpansion::Maximal)) {
// For resilient protocols, use the associated type descriptor to
// determine the index.
// Extract the associated type descriptor.
auto assocTypeDescriptor =
IGM.getAddrOfAssociatedTypeDescriptor(associatedType.getAssociation());
auto index =
computeResilientWitnessTableIndex(IGF,
associatedType.getSourceProtocol(),
assocTypeDescriptor);
witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index);
} else {
// For non-resilient protocols, the index is a constant.
auto &pi = IGM.getProtocolInfo(associatedType.getSourceProtocol(),
ProtocolInfoKind::RequirementSignature);
auto index = pi.getAssociatedTypeIndex(IGM, associatedType);
witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable,
index.forProtocolWitnessTable());
}
// Cast the witness to the appropriate function type.
auto sig = IGM.getAssociatedTypeMetadataAccessFunctionSignature();
auto witnessTy = sig.getType();
witness = IGF.Builder.CreateBitCast(witness, witnessTy->getPointerTo());
FunctionPointer witnessFnPtr(witness, sig);
// Call the accessor.
assert((!IGF.IGM.DebugInfo || IGF.Builder.getCurrentDebugLocation() ||
!IGF.CurFn->getSubprogram()) &&
"creating a function call without a debug location");
auto call = IGF.Builder.CreateCall(witnessFnPtr,
// Call swift_getAssociatedTypeWitness().
auto call = IGF.Builder.CreateCall(IGM.getGetAssociatedTypeWitnessFn(),
{ request.get(IGF),
wtable,
parentMetadata,
wtable });
assocTypeDescriptor });
return MetadataResponse::handle(IGF, request, call);
}

View File

@@ -164,10 +164,10 @@ public:
}
};
llvm::Constant *IRGenModule::getTypeRef(CanType type) {
llvm::Constant *IRGenModule::getTypeRef(CanType type, unsigned alignment) {
IRGenMangler Mangler;
auto SymbolicName = Mangler.mangleTypeForReflection(*this, type);
return getAddrOfStringForTypeRef(SymbolicName);
return getAddrOfStringForTypeRef(SymbolicName, alignment);
}
class ReflectionMetadataBuilder {

View File

@@ -993,9 +993,10 @@ public:
/// reflection metadata.
llvm::SetVector<const StructDecl *> ImportedStructs;
llvm::Constant *getTypeRef(CanType type);
llvm::Constant *getTypeRef(CanType type, unsigned alignment = 1);
llvm::Constant *getAddrOfStringForTypeRef(StringRef mangling);
llvm::Constant *getAddrOfStringForTypeRef(const SymbolicMangling &mangling);
llvm::Constant *getAddrOfStringForTypeRef(const SymbolicMangling &mangling,
unsigned alignment = 1);
llvm::Constant *getAddrOfFieldName(StringRef Name);
llvm::Constant *getAddrOfCaptureDescriptor(SILFunction &caller,
CanSILFunctionType origCalleeType,
@@ -1004,6 +1005,9 @@ public:
const HeapLayout &layout);
llvm::Constant *getAddrOfBoxDescriptor(CanType boxedType);
/// Produce an associated type witness that refers to the given type.
llvm::Constant *getAssociatedTypeWitness(CanType type);
void emitAssociatedTypeMetadataRecord(const ProtocolConformance *Conformance);
void emitFieldMetadataRecord(const NominalTypeDecl *Decl);

View File

@@ -222,7 +222,8 @@ llvm::Constant *IRGenModule::getAddrOfStringForTypeRef(StringRef str) {
}
llvm::Constant *IRGenModule::getAddrOfStringForTypeRef(
const SymbolicMangling &mangling) {
const SymbolicMangling &mangling,
unsigned alignment) {
// Create a symbol name for the symbolic mangling. This is used as the
// uniquing key both for ODR coalescing and within this TU.
IRGenMangler mangler;
@@ -230,9 +231,12 @@ llvm::Constant *IRGenModule::getAddrOfStringForTypeRef(
mangler.mangleSymbolNameForSymbolicMangling(mangling);
// See if we emitted the constant already.
// FIXME: Make sure the existing variable has enough alignment. Otherwise,
// replace it.
auto &entry = StringsForTypeRef[symbolName];
if (entry.second)
if (entry.second && entry.first->getAlignment() >= alignment) {
return entry.second;
}
ConstantInitBuilder B(*this);
auto S = B.beginStruct();
@@ -284,7 +288,7 @@ llvm::Constant *IRGenModule::getAddrOfStringForTypeRef(
nullptr,
symbolName);
var->setVisibility(llvm::GlobalValue::HiddenVisibility);
var->setAlignment(1);
var->setAlignment(alignment);
setTrueConstGlobal(var);
var->setSection(getReflectionTypeRefSectionName());

View File

@@ -2502,19 +2502,12 @@ static inline bool swift_isClassOrObjCExistentialTypeImpl(const Metadata *T) {
namespace {
// protocol _ObjectiveCBridgeable {
struct _ObjectiveCBridgeableWitnessTable {
/// The protocol conformance descriptor.
const void *protocolConformanceDescriptor;
struct _ObjectiveCBridgeableWitnessTable : WitnessTable {
static_assert(WitnessTableFirstRequirementOffset == 1,
"Witness table layout changed");
// associatedtype _ObjectiveCType : class
SWIFT_CC(swift)
MetadataResponse (*ObjectiveCType)(
MetadataRequest request,
const Metadata *parentMetadata,
const _ObjectiveCBridgeableWitnessTable *witnessTable);
void *_ObjectiveCType;
// func _bridgeToObjectiveC() -> _ObjectiveCType
SWIFT_CC(swift)
@@ -2544,6 +2537,23 @@ struct _ObjectiveCBridgeableWitnessTable {
};
// }
/// Retrieve the bridged Objective-C type for the given type that
/// conforms to \c _ObjectiveCBridgeable.
MetadataResponse _getBridgedObjectiveCType(
MetadataRequest request,
const Metadata *conformingType,
const _ObjectiveCBridgeableWitnessTable *wtable) {
// FIXME: Can we directly reference the descriptor somehow?
const ProtocolConformanceDescriptor *conformance = wtable->Description;
const ProtocolDescriptor *protocol = conformance->getProtocol();
auto assocTypeRequirement = protocol->getRequirements().begin();
assert(assocTypeRequirement->Flags.getKind() ==
ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction);
auto mutableWTable = (WitnessTable *)wtable;
return swift_getAssociatedTypeWitness(request, mutableWTable, conformingType,
assocTypeRequirement);
}
} // unnamed namespace
extern "C" const ProtocolDescriptor PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable);
@@ -2634,7 +2644,7 @@ static bool _dynamicCastClassToValueViaObjCBridgeable(
DynamicCastFlags flags) {
// Determine the class type to which the target value type is bridged.
auto targetBridgedClass =
targetBridgeWitness->ObjectiveCType(MetadataState::Complete, targetType,
_getBridgedObjectiveCType(MetadataState::Complete, targetType,
targetBridgeWitness).Value;
// Dynamic cast the source object to the class type to which the target value
@@ -2888,7 +2898,7 @@ const Metadata *_getBridgedNonVerbatimObjectiveCType(
// Check if the type conforms to _BridgedToObjectiveC, in which case
// we'll extract its associated type.
if (const auto *bridgeWitness = findBridgeWitness(T)) {
return bridgeWitness->ObjectiveCType(MetadataState::Complete, T,
return _getBridgedObjectiveCType(MetadataState::Complete, T,
bridgeWitness).Value;
}
@@ -2980,7 +2990,7 @@ _bridgeNonVerbatimFromObjectiveC(
// Check if sourceValue has the _ObjectiveCType type required by the
// protocol.
const Metadata *objectiveCType =
bridgeWitness->ObjectiveCType(MetadataState::Complete, nativeType,
_getBridgedObjectiveCType(MetadataState::Complete, nativeType,
bridgeWitness).Value;
auto sourceValueAsObjectiveCType =
@@ -3031,7 +3041,7 @@ _bridgeNonVerbatimFromObjectiveCConditional(
// Dig out the Objective-C class type through which the native type
// is bridged.
const Metadata *objectiveCType =
bridgeWitness->ObjectiveCType(MetadataState::Complete, nativeType,
_getBridgedObjectiveCType(MetadataState::Complete, nativeType,
bridgeWitness).Value;
// Check whether we can downcast the source value to the Objective-C

View File

@@ -3915,6 +3915,76 @@ swift::swift_getGenericWitnessTable(GenericWitnessTable *genericTable,
return result.second;
}
MetadataResponse
swift::swift_getAssociatedTypeWitness(MetadataRequest request,
WitnessTable *wtable,
const Metadata *conformingType,
const ProtocolRequirement *assocType) {
const ProtocolConformanceDescriptor *conformance = wtable->Description;
const ProtocolDescriptor *protocol = conformance->getProtocol();
auto requirements = protocol->getRequirements();
if (assocType < requirements.begin() ||
assocType >= requirements.end()) {
fatalError(0,
"associated type descriptor %p is out of range for protocol %s;"
"requirement range is %p--%p\n",
assocType, protocol->Name.get(), requirements.begin(),
requirements.end());
}
const auto &req = *assocType;
if (req.Flags.getKind() !=
ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction) {
fatalError(0, "associated type descriptor %p refers to non-associated "
"type requirement in protocol %s\n",
assocType, protocol->Name.get());
}
// If the low bit of the witness is clear, it's already a metadata pointer.
unsigned witnessIndex = (assocType - requirements.begin()) +
WitnessTableFirstRequirementOffset;
auto witness = ((const void* const *)wtable)[witnessIndex];
if ((uintptr_t(witness) &
ProtocolRequirementFlags::AssociatedTypeMangledNameMask) == 0) {
return swift_checkMetadataState(request, (const Metadata *)witness);
}
// Demangle the associated type name.
const char *mangledName =
(const char *)(uintptr_t(witness) &
~ProtocolRequirementFlags::AssociatedTypeMangledNameMask);
const Metadata *assocTypeMetadata;
if (witness == req.DefaultImplementation) {
// The protocol's Self is the only generic parameter that can occur in the
// type.
assocTypeMetadata =
_getTypeByMangledName(mangledName,
[conformingType](unsigned depth, unsigned index) -> const Metadata * {
if (depth == 0 && index == 0)
return conformingType;
return nullptr;
});
} else {
// The generic parameters in the associated type name are those of the
// conforming type.
SubstGenericParametersFromMetadata substitutions(conformingType);
assocTypeMetadata = _getTypeByMangledName(mangledName, substitutions);
}
if (!assocTypeMetadata) {
fatalError(0,
"failed to demangle associated type at %p in protocol '%s' with "
"mangled name '%s'\n",
assocType, protocol->Name.get(), mangledName);
}
// Update the witness table.
((const void**)wtable)[witnessIndex] = assocTypeMetadata;
return swift_checkMetadataState(request, assocTypeMetadata);
}
/***************************************************************************/
/*** Recursive metadata dependencies ***************************************/
/***************************************************************************/

View File

@@ -784,7 +784,8 @@ namespace {
/// Find the offset of the protocol requirement for an associated type with
/// the given name in the given protocol descriptor.
Optional<unsigned> findAssociatedTypeByName(const ProtocolDescriptor *protocol,
Optional<const ProtocolRequirement *> findAssociatedTypeByName(
const ProtocolDescriptor *protocol,
StringRef name) {
// If we don't have associated type names, there's nothing to do.
const char *associatedTypeNamesPtr = protocol->AssociatedTypeNames.get();
@@ -820,7 +821,7 @@ Optional<unsigned> findAssociatedTypeByName(const ProtocolDescriptor *protocol,
continue;
if (currentAssocTypeIdx == matchingAssocTypeIdx)
return reqIdx + WitnessTableFirstRequirementOffset;
return requirements.begin() + reqIdx;
++currentAssocTypeIdx;
}
@@ -1191,12 +1192,15 @@ swift::_getTypeByMangledName(StringRef typeName,
if (!witnessTable) return nullptr;
// Look for the named associated type within the protocol.
auto assocTypeReqIndex = findAssociatedTypeByName(protocol, assocType);
if (!assocTypeReqIndex) return nullptr;
auto assocTypeReq = findAssociatedTypeByName(protocol, assocType);
if (!assocTypeReq) return nullptr;
// Call the associated type access function.
return ((AssociatedTypeAccessFunction * const *)witnessTable)[*assocTypeReqIndex]
(MetadataState::Abstract, base, witnessTable).Value;
return swift_getAssociatedTypeWitness(
MetadataState::Abstract,
const_cast<WitnessTable *>(witnessTable),
base,
*assocTypeReq).Value;
});
auto type = Demangle::decodeMangledType(builder, node);

View File

@@ -667,17 +667,12 @@ static const Metadata *resolveGenericParamRef(
swift_conformsToProtocol(current, assocTypeRef.Protocol);
if (!witnessTable) return nullptr;
// Determine the index of the associated type based on its offset
// from the beginning of the protocol's requirements.
auto protocolDescriptor = witnessTable->Description->getProtocol();
unsigned index = assocTypeRef.Requirement.get() -
protocolDescriptor->getRequirements().data();
// Call the associated type access function.
unsigned adjustedIndex = index + WitnessTableFirstRequirementOffset;
current =
((AssociatedTypeAccessFunction * const *)witnessTable)[adjustedIndex]
(MetadataState::Abstract, current, witnessTable).Value;
// Retrieve the associated type.
auto assocTypeReq = assocTypeRef.Requirement.get();
current = swift_getAssociatedTypeWitness(
MetadataState::Abstract,
const_cast<WitnessTable *>(witnessTable),
current, assocTypeReq).Value;
if (!current) return nullptr;
}