Skip to content

Commit 8a9df1c

Browse files
committed
[IRGen] Implement resilient access pattern for associated conformances.
When referencing an associated conformance in a witness table for a resilient protocol, use the associated conformance descriptor to compute the index into the witness table at run-time. Another part of rdar://problem/44167982.
1 parent 4549fcd commit 8a9df1c

File tree

5 files changed

+58
-12
lines changed

5 files changed

+58
-12
lines changed

lib/IRGen/GenDecl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3387,6 +3387,16 @@ llvm::GlobalValue *IRGenModule::defineAssociatedTypeDescriptor(
33873387
return defineAlias(entity, definition);
33883388
}
33893389

3390+
llvm::Constant *IRGenModule::getAddrOfAssociatedConformanceDescriptor(
3391+
AssociatedConformance conformance) {
3392+
auto entity = LinkEntity::forAssociatedConformanceDescriptor(
3393+
conformance.getSourceProtocol(),
3394+
conformance.getAssociation(),
3395+
conformance.getAssociatedRequirement());
3396+
return getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(),
3397+
ProtocolRequirementStructTy, DebugTypeInfo());
3398+
}
3399+
33903400
llvm::GlobalValue *IRGenModule::defineAssociatedConformanceDescriptor(
33913401
ProtocolDecl *proto,
33923402
CanType subject,

lib/IRGen/GenProto.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,10 +2500,30 @@ static llvm::Value *
25002500
emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF,
25012501
llvm::Value *parentMetadata,
25022502
llvm::Value *wtable,
2503-
WitnessIndex index,
2503+
AssociatedConformance conformance,
25042504
llvm::Value *associatedTypeMetadata) {
2505-
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable,
2506-
index.forProtocolWitnessTable());
2505+
auto sourceProtocol = conformance.getSourceProtocol();
2506+
llvm::Value *witness;
2507+
if (IGF.IGM.isResilient(sourceProtocol, ResilienceExpansion::Maximal)) {
2508+
// For resilient protocols, use the associated conformance descriptor to
2509+
// determine the index.
2510+
auto assocConformanceDescriptor =
2511+
IGF.IGM.getAddrOfAssociatedConformanceDescriptor(conformance);
2512+
2513+
auto index =
2514+
computeResilientWitnessTableIndex(IGF, sourceProtocol,
2515+
assocConformanceDescriptor);
2516+
2517+
witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index);
2518+
} else {
2519+
// For non-resilient protocols, the index is a constant.
2520+
auto &pi = IGF.IGM.getProtocolInfo(sourceProtocol,
2521+
ProtocolInfoKind::RequirementSignature);
2522+
2523+
auto index = pi.getAssociatedConformanceIndex(conformance);
2524+
witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable,
2525+
index.forProtocolWitnessTable());
2526+
}
25072527

25082528
// Cast the witness to the appropriate function type.
25092529
auto sig = IGF.IGM.getAssociatedTypeWitnessTableAccessFunctionSignature();
@@ -2663,14 +2683,17 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
26632683

26642684
if (!source) return MetadataResponse();
26652685

2666-
WitnessIndex index(component.getPrimaryIndex(), /*prefix*/ false);
26672686
auto sourceMetadata = IGF.emitTypeMetadataRef(sourceType);
26682687
auto associatedMetadata = IGF.emitTypeMetadataRef(sourceKey.Type);
26692688
auto sourceWTable = source.getMetadata();
26702689

2690+
AssociatedConformance associatedConformanceRef(sourceProtocol,
2691+
association,
2692+
associatedRequirement);
26712693
auto associatedWTable =
26722694
emitAssociatedTypeWitnessTableRef(IGF, sourceMetadata, sourceWTable,
2673-
index, associatedMetadata);
2695+
associatedConformanceRef,
2696+
associatedMetadata);
26742697

26752698
setProtocolWitnessTableName(IGF.IGM, associatedWTable, sourceKey.Type,
26762699
associatedRequirement);
@@ -3396,13 +3419,7 @@ Signature IRGenModule::getAssociatedTypeMetadataAccessFunctionSignature() {
33963419
return Signature(fnType, attrs, SwiftCC);
33973420
}
33983421

3399-
/// Compute the index into a witness table for a resilient protocol given
3400-
/// a reference to a descriptor of one of the requirements in that witness
3401-
/// table.
3402-
///
3403-
/// Given an index into the witness table for a resilient protocol that
3404-
/// was compiuted
3405-
static llvm::Value *computeResilientWitnessTableIndex(
3422+
llvm::Value *irgen::computeResilientWitnessTableIndex(
34063423
IRGenFunction &IGF,
34073424
ProtocolDecl *proto,
34083425
llvm::Constant *reqtDescriptor) {

lib/IRGen/GenProto.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ namespace irgen {
7070
SILDeclRef member,
7171
ProtocolConformanceRef conformance);
7272

73+
/// Compute the index into a witness table for a resilient protocol given
74+
/// a reference to a descriptor of one of the requirements in that witness
75+
/// table.
76+
llvm::Value *computeResilientWitnessTableIndex(
77+
IRGenFunction &IGF,
78+
ProtocolDecl *proto,
79+
llvm::Constant *reqtDescriptor);
80+
7381
/// Given a type T and an associated type X of some protocol P to
7482
/// which T conforms, return the type metadata for T.X.
7583
///

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,8 @@ private: \
12341234
llvm::GlobalValue *defineAssociatedTypeDescriptor(
12351235
AssociatedTypeDecl *assocType,
12361236
llvm::Constant *definition);
1237+
llvm::Constant *getAddrOfAssociatedConformanceDescriptor(
1238+
AssociatedConformance conformance);
12371239
llvm::GlobalValue *defineAssociatedConformanceDescriptor(
12381240
ProtocolDecl *proto,
12391241
CanType subject,

test/IRGen/protocol_resilience_descriptors.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,12 @@ public func assocTypeMetadata<PWR: ProtocolWithRequirements>(_: PWR.Type) -> PWR
7575
// CHECK-USAGE: load i8*, i8** [[WITNESS_ADDR]], align {{(4|8)}}
7676
return PWR.T.self
7777
}
78+
79+
func useOtherResilientProtocol<T: OtherResilientProtocol>(_: T.Type) { }
80+
81+
// CHECK-USAGE: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$S31protocol_resilience_descriptors23extractAssocConformanceyyx010resilient_A0012ProtocolWithE12TypeDefaultsRzlF"
82+
public func extractAssocConformance<T: ProtocolWithAssocTypeDefaults>(_: T) {
83+
// CHECK-USAGE: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %T.ProtocolWithAssocTypeDefaults, [[INT]] udiv ([[INT]] sub ([[INT]] ptrtoint (%swift.protocol_requirement* @"$S2T218resilient_protocol29ProtocolWithAssocTypeDefaultsPTl" to [[INT]]), [[INT]] ptrtoint (%swift.protocol_requirement* @"$S18resilient_protocol29ProtocolWithAssocTypeDefaultsTL" to [[INT]])), [[INT]] 8)
84+
// CHECK-USAGE: load i8*, i8** [[WITNESS_ADDR]]
85+
useOtherResilientProtocol(T.T2.self)
86+
}

0 commit comments

Comments
 (0)