mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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:
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ***************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user