diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index d9eea5cbf9d7f..e836289df95e4 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -2943,6 +2943,12 @@ struct TargetProtocolDescriptor final NumRequirements}; } + /// Retrieve the requirement base descriptor address. + ConstTargetPointer> + getRequirementBaseDescriptor() const { + return getRequirements().data() - WitnessTableFirstRequirementOffset; + } + #ifndef NDEBUG LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, "only for use in the debugger"); diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 37b06c8dd4d04..7038eafe77206 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -414,6 +414,7 @@ swift_getGenericWitnessTable(GenericWitnessTable *genericTable, /// /// \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. @@ -422,6 +423,7 @@ MetadataResponse swift_getAssociatedTypeWitness( MetadataRequest request, WitnessTable *wtable, const Metadata *conformingType, + const ProtocolRequirement *reqBase, const ProtocolRequirement *assocType); /// \brief Fetch a uniqued metadata for a function type. diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 9afe1cb506df9..9aaed27f5167c 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -649,12 +649,14 @@ FUNCTION(GetGenericWitnessTable, swift_getGenericWitnessTable, C_CC, // MetadataRequest request, // WitnessTable *wtable, // const Metadata *conformingType, +// ProtocolRequirement *reqBase, // ProtocolRequirement *assocType); FUNCTION(GetAssociatedTypeWitness, swift_getAssociatedTypeWitness, C_CC, RETURNS(TypeMetadataResponseTy), ARGS(SizeTy, WitnessTablePtrTy, TypeMetadataPtrTy, + ProtocolRequirementStructTy->getPointerTo(), ProtocolRequirementStructTy->getPointerTo()), ATTRS(NoUnwind, ReadNone)) diff --git a/lib/IRGen/GenProto.cpp b/lib/IRGen/GenProto.cpp index 97c3e5e208c2e..b1412faed690e 100644 --- a/lib/IRGen/GenProto.cpp +++ b/lib/IRGen/GenProto.cpp @@ -3554,6 +3554,11 @@ irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF, DynamicMetadataRequest request) { auto &IGM = IGF.IGM; + // Extract the requirements base descriptor. + auto reqBaseDescriptor = + IGM.getAddrOfProtocolRequirementsBaseDescriptor( + associatedType.getSourceProtocol()); + // Extract the associated type descriptor. auto assocTypeDescriptor = IGM.getAddrOfAssociatedTypeDescriptor(associatedType.getAssociation()); @@ -3563,6 +3568,7 @@ irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF, { request.get(IGF), wtable, parentMetadata, + reqBaseDescriptor, assocTypeDescriptor }); call->setDoesNotThrow(); call->setDoesNotAccessMemory(); diff --git a/stdlib/public/runtime/Casting.cpp b/stdlib/public/runtime/Casting.cpp index 99727d1897045..0c1d1c954ad4d 100644 --- a/stdlib/public/runtime/Casting.cpp +++ b/stdlib/public/runtime/Casting.cpp @@ -2550,8 +2550,10 @@ MetadataResponse _getBridgedObjectiveCType( assert(assocTypeRequirement->Flags.getKind() == ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction); auto mutableWTable = (WitnessTable *)wtable; - return swift_getAssociatedTypeWitness(request, mutableWTable, conformingType, - assocTypeRequirement); + return swift_getAssociatedTypeWitness( + request, mutableWTable, conformingType, + protocol->getRequirementBaseDescriptor(), + assocTypeRequirement); } } // unnamed namespace diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index f2c94d7b8ecea..5f788854ab241 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -3998,21 +3998,24 @@ MetadataResponse swift::swift_getAssociatedTypeWitness(MetadataRequest request, WitnessTable *wtable, const Metadata *conformingType, + const ProtocolRequirement *reqBase, const ProtocolRequirement *assocType) { - const ProtocolConformanceDescriptor *conformance = wtable->Description; - const ProtocolDescriptor *protocol = conformance->getProtocol(); - auto requirements = protocol->getRequirements(); - assert(assocType >= requirements.begin() && - assocType < requirements.end()); - const auto &req = *assocType; - (void)req; - assert(req.Flags.getKind() == +#ifndef NDEBUG + { + const ProtocolConformanceDescriptor *conformance = wtable->Description; + const ProtocolDescriptor *protocol = conformance->getProtocol(); + auto requirements = protocol->getRequirements(); + assert(assocType >= requirements.begin() && + assocType < requirements.end()); + assert(reqBase == requirements.data() - WitnessTableFirstRequirementOffset); + assert(assocType->Flags.getKind() == ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction); + } +#endif // If the low bit of the witness is clear, it's already a metadata pointer. - unsigned witnessIndex = (assocType - requirements.begin()) + - WitnessTableFirstRequirementOffset; + unsigned witnessIndex = assocType - reqBase; auto witness = ((const void* const *)wtable)[witnessIndex]; if (LLVM_LIKELY((uintptr_t(witness) & ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) { @@ -4034,6 +4037,10 @@ swift::swift_getAssociatedTypeWitness(MetadataRequest request, ++mangledNameBase; } + // Dig out the protocol. + const ProtocolConformanceDescriptor *conformance = wtable->Description; + const ProtocolDescriptor *protocol = conformance->getProtocol(); + // Extract the mangled name itself. StringRef mangledName = Demangle::makeSymbolicMangledNameStringRef(mangledNameBase); diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 5bbeed370e85c..adc35fe33c306 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -1200,6 +1200,7 @@ swift::_getTypeByMangledName(StringRef typeName, MetadataState::Abstract, const_cast(witnessTable), base, + protocol->getRequirementBaseDescriptor(), *assocTypeReq).Value; }); diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index cdffff8c8d857..ce1015d69f987 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -671,7 +671,10 @@ static const Metadata *resolveGenericParamRef( current = swift_getAssociatedTypeWitness( MetadataState::Abstract, const_cast(witnessTable), - current, assocTypeReq).Value; + current, + assocTypeRef.Protocol + ->getRequirementBaseDescriptor(), + assocTypeReq).Value; if (!current) return nullptr; } diff --git a/test/IRGen/associated_types.swift b/test/IRGen/associated_types.swift index b1517c49d8ffd..6811108762fee 100644 --- a/test/IRGen/associated_types.swift +++ b/test/IRGen/associated_types.swift @@ -75,7 +75,7 @@ func testFastRuncible(_ t: T, u: U) // 1. Get the type metadata for U.RuncerType.Runcee. // 1a. Get the type metadata for U.RuncerType. // Note that we actually look things up in T, which is going to prove unfortunate. -// CHECK: [[T2:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %T.Runcible, %swift.type* %T, %swift.protocol_requirement* getelementptr inbounds (<{{.*}}>, <{{.*}}>* @"$s16associated_types8RuncibleMp", i32 0, i32 14)) [[NOUNWIND_READNONE:#.*]] +// CHECK: [[T2:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %T.Runcible, %swift.type* %T, %swift.protocol_requirement* getelementptr{{.*}}i32 12), i32 -1), %swift.protocol_requirement* getelementptr inbounds (<{{.*}}>, <{{.*}}>* @"$s16associated_types8RuncibleMp", i32 0, i32 14)) [[NOUNWIND_READNONE:#.*]] // CHECK-NEXT: %T.RuncerType = extractvalue %swift.metadata_response [[T2]], 0 // CHECK-NEXT: store %swift.type* // 2. Get the witness table for U.RuncerType.Runcee : Speedy @@ -85,7 +85,7 @@ func testFastRuncible(_ t: T, u: U) // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8** (%swift.type*, %swift.type*, i8**)* // CHECK-NEXT: %T.RuncerType.FastRuncer = call swiftcc i8** [[T2]](%swift.type* %T.RuncerType, %swift.type* %U, i8** %U.FastRuncible) // 1c. Get the type metadata for U.RuncerType.Runcee. -// CHECK-NEXT: [[T2:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %T.RuncerType.FastRuncer, %swift.type* %T.RuncerType, %swift.protocol_requirement* getelementptr inbounds (<{{.*}}>, <{{.*}}>* @"$s16associated_types10FastRuncerMp", i32 0, i32 10)) +// CHECK-NEXT: [[T2:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %T.RuncerType.FastRuncer, %swift.type* %T.RuncerType, {{.*}}, %swift.protocol_requirement* getelementptr inbounds (<{{.*}}>, <{{.*}}>* @"$s16associated_types10FastRuncerMp", i32 0, i32 10)) // CHECK-NEXT: %T.RuncerType.Runcee = extractvalue %swift.metadata_response [[T2]], 0 // CHECK-NEXT: store %swift.type* // 2b. Get the witness table for U.RuncerType.Runcee : Speedy. diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil index 45e68fe950dc2..aa332023f9748 100644 --- a/test/IRGen/generic_structs.sil +++ b/test/IRGen/generic_structs.sil @@ -256,7 +256,7 @@ struct GenericLayoutWithAssocType { // CHECK: [[T0_GEP:%.*]] = getelementptr inbounds i8*, i8** %T.ParentHasAssociatedType, i32 1 // CHECK: [[T0:%.*]] = load i8*, i8** [[T0_GEP]] // CHECK: [[T1:%.*]] = bitcast i8* [[T0]] to i8** -// CHECK: [[T4:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.HasAssociatedType, %swift.type* %T, %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl") +// CHECK: [[T4:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.HasAssociatedType, %swift.type* %T, %swift.protocol_requirement* @"$s15generic_structs17HasAssociatedTypeTL", %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl") // CHECK: %T.Assoc = extractvalue %swift.metadata_response [[T4]], 0 @@ -265,5 +265,5 @@ struct GenericLayoutWithAssocType { // CHECK: [[T2:%.*]] = bitcast i8* [[T1]] to i8** (%swift.type*, %swift.type*, i8**)* // CHECK: %T.Assoc.HasAssociatedType = call swiftcc i8** [[T2]](%swift.type* %T.Assoc, %swift.type* %T, i8** %T.ParentHasAssociatedType) -// CHECK: [[T2:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.Assoc.HasAssociatedType, %swift.type* %T.Assoc, %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl") +// CHECK: [[T2:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.Assoc.HasAssociatedType, %swift.type* %T.Assoc, %swift.protocol_requirement* @"$s15generic_structs17HasAssociatedTypeTL", %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl") // CHECK: %T.Assoc.Assoc = extractvalue %swift.metadata_response [[T2]], 0 diff --git a/test/IRGen/protocol_resilience_descriptors.swift b/test/IRGen/protocol_resilience_descriptors.swift index 69246deec2e0d..9971af43ee79b 100644 --- a/test/IRGen/protocol_resilience_descriptors.swift +++ b/test/IRGen/protocol_resilience_descriptors.swift @@ -82,7 +82,7 @@ where Element: ProtocolWithRequirements, Element.T == Y { // CHECK-USAGE: define{{( dllexport)?}}{{( protected)?}} swiftcc %swift.type* @"$s31protocol_resilience_descriptors17assocTypeMetadatay1TQzmxm010resilient_A024ProtocolWithRequirementsRzlF"(%swift.type*, %swift.type* [[PWD:%.*]], i8** [[WTABLE:%.*]]) public func assocTypeMetadata(_: PWR.Type) -> PWR.T.Type { - // CHECK-USAGE: call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %PWR.ProtocolWithRequirements, %swift.type* %PWR, %swift.protocol_requirement* @"$s1T18resilient_protocol24ProtocolWithRequirementsPTl") + // CHECK-USAGE: call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %PWR.ProtocolWithRequirements, %swift.type* %PWR, %swift.protocol_requirement* @"$s18resilient_protocol24ProtocolWithRequirementsTL", %swift.protocol_requirement* @"$s1T18resilient_protocol24ProtocolWithRequirementsPTl") return PWR.T.self }