Skip to content

Commit 17f5bef

Browse files
authored
Merge pull request #19358 from DougGregor/associated-conformance-resilience
[ABI] Associated conformance resilience
2 parents a2898cb + 8a9df1c commit 17f5bef

18 files changed

+228
-32
lines changed

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ NODE(CurryThunk)
210210
NODE(DispatchThunk)
211211
NODE(MethodDescriptor)
212212
NODE(ProtocolRequirementsBaseDescriptor)
213+
NODE(AssociatedConformanceDescriptor)
213214
NODE(AssociatedTypeDescriptor)
214215
NODE(ThrowsAnnotation)
215216
NODE(EmptyList)

include/swift/IRGen/Linking.h

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,13 @@ class LinkEntity {
206206
/// The pointer is an AssociatedTypeDecl*.
207207
AssociatedTypeDescriptor,
208208

209+
/// An descriptor for an associated conformance within a protocol, which
210+
/// will alias the TargetProtocolRequirement descripting this
211+
/// particular associated conformance.
212+
/// The pointer is a ProtocolDecl*; the index of the associated conformance
213+
/// is stored in the data.
214+
AssociatedConformanceDescriptor,
215+
209216
/// A function which returns the default type metadata for the associated
210217
/// type of a protocol. The secondary pointer is a ProtocolDecl*.
211218
/// The index of the associated type declaration is stored in the data.
@@ -342,6 +349,21 @@ class LinkEntity {
342349
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind));
343350
}
344351

352+
void setForProtocolAndAssociatedConformance(Kind kind,
353+
const ProtocolDecl *proto,
354+
CanType associatedType,
355+
ProtocolDecl *associatedProtocol){
356+
assert(isDeclKind(kind));
357+
Pointer = static_cast<ValueDecl *>(const_cast<ProtocolDecl *>(proto));
358+
SecondaryPointer = nullptr;
359+
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)) |
360+
LINKENTITY_SET_FIELD(AssociatedConformanceIndex,
361+
getAssociatedConformanceIndex(
362+
proto,
363+
associatedType,
364+
associatedProtocol));
365+
}
366+
345367
void setForProtocolConformance(Kind kind, const ProtocolConformance *c) {
346368
assert(isProtocolConformanceKind(kind) && !isTypeKind(kind));
347369
Pointer = nullptr;
@@ -407,14 +429,12 @@ class LinkEntity {
407429
}
408430

409431
// We store associated conformances using their index in the requirement
410-
// list of the requirement signature of the conformance's protocol.
411-
static unsigned getAssociatedConformanceIndex(
412-
const ProtocolConformance *conformance,
432+
// list of the requirement signature of the protocol.
433+
static unsigned getAssociatedConformanceIndex(const ProtocolDecl *proto,
413434
CanType associatedType,
414435
ProtocolDecl *requirement) {
415436
unsigned index = 0;
416-
for (const auto &reqt :
417-
conformance->getProtocol()->getRequirementSignature()) {
437+
for (const auto &reqt : proto->getRequirementSignature()) {
418438
if (reqt.getKind() == RequirementKind::Conformance &&
419439
reqt.getFirstType()->getCanonicalType() == associatedType &&
420440
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() ==
@@ -426,15 +446,31 @@ class LinkEntity {
426446
llvm_unreachable("requirement not found in protocol");
427447
}
428448

449+
// We store associated conformances using their index in the requirement
450+
// list of the requirement signature of the conformance's protocol.
451+
static unsigned getAssociatedConformanceIndex(
452+
const ProtocolConformance *conformance,
453+
CanType associatedType,
454+
ProtocolDecl *requirement) {
455+
return getAssociatedConformanceIndex(conformance->getProtocol(),
456+
associatedType, requirement);
457+
}
458+
429459
static std::pair<CanType, ProtocolDecl*>
430-
getAssociatedConformanceByIndex(const ProtocolConformance *conformance,
460+
getAssociatedConformanceByIndex(const ProtocolDecl *proto,
431461
unsigned index) {
432-
auto &reqt = conformance->getProtocol()->getRequirementSignature()[index];
462+
auto &reqt = proto->getRequirementSignature()[index];
433463
assert(reqt.getKind() == RequirementKind::Conformance);
434464
return { reqt.getFirstType()->getCanonicalType(),
435465
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() };
436466
}
437467

468+
static std::pair<CanType, ProtocolDecl*>
469+
getAssociatedConformanceByIndex(const ProtocolConformance *conformance,
470+
unsigned index) {
471+
return getAssociatedConformanceByIndex(conformance->getProtocol(), index);
472+
}
473+
438474
void setForType(Kind kind, CanType type) {
439475
assert(isTypeKind(kind));
440476
Pointer = type.getPointer();
@@ -758,6 +794,18 @@ class LinkEntity {
758794
return entity;
759795
}
760796

797+
static LinkEntity
798+
forAssociatedConformanceDescriptor(ProtocolDecl *proto,
799+
CanType associatedType,
800+
ProtocolDecl *associatedProtocol) {
801+
LinkEntity entity;
802+
entity.setForProtocolAndAssociatedConformance(
803+
Kind::AssociatedConformanceDescriptor,
804+
proto, associatedType,
805+
associatedProtocol);
806+
return entity;
807+
}
808+
761809
static LinkEntity
762810
forAssociatedTypeMetadataAccessFunction(const ProtocolConformance *C,
763811
AssociatedType association) {
@@ -872,9 +920,15 @@ class LinkEntity {
872920
}
873921

874922
std::pair<CanType, ProtocolDecl *> getAssociatedConformance() const {
875-
assert(getKind() == Kind::AssociatedTypeWitnessTableAccessFunction);
876-
return getAssociatedConformanceByIndex(getProtocolConformance(),
923+
if (getKind() == Kind::AssociatedTypeWitnessTableAccessFunction) {
924+
return getAssociatedConformanceByIndex(getProtocolConformance(),
877925
LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));
926+
}
927+
928+
assert(getKind() == Kind::AssociatedConformanceDescriptor);
929+
return getAssociatedConformanceByIndex(
930+
cast<ProtocolDecl>(getDecl()),
931+
LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));
878932
}
879933

880934
ProtocolDecl *getAssociatedProtocol() const {

lib/Demangling/Demangler.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,6 +1827,14 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
18271827
return createWithChild(Node::Kind::DefaultAssociatedTypeMetadataAccessor,
18281828
popAssocTypeName());
18291829

1830+
case 'n': {
1831+
NodePointer requirementTy = popProtocol();
1832+
auto assocTypePath = popAssocTypePath();
1833+
NodePointer protoTy = popNode(Node::Kind::Type);
1834+
return createWithChildren(Node::Kind::AssociatedConformanceDescriptor,
1835+
protoTy, assocTypePath, requirementTy);
1836+
}
1837+
18301838
case 'H':
18311839
case 'h': {
18321840
auto nodeKind = c == 'H' ? Node::Kind::KeyPathEqualsThunkHelper

lib/Demangling/NodePrinter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ class NodePrinter {
308308
case Node::Kind::ProtocolListWithClass:
309309
case Node::Kind::Allocator:
310310
case Node::Kind::ArgumentTuple:
311+
case Node::Kind::AssociatedConformanceDescriptor:
311312
case Node::Kind::AssociatedTypeDescriptor:
312313
case Node::Kind::AssociatedTypeMetadataAccessor:
313314
case Node::Kind::AssociatedTypeWitnessTableAccessor:
@@ -1555,6 +1556,14 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
15551556
Printer << "lazy cache variable for type metadata for ";
15561557
print(Node->getChild(0));
15571558
return nullptr;
1559+
case Node::Kind::AssociatedConformanceDescriptor:
1560+
Printer << "associated conformance descriptor for ";
1561+
print(Node->getChild(0));
1562+
Printer << ".";
1563+
print(Node->getChild(1));
1564+
Printer << ": ";
1565+
print(Node->getChild(2));
1566+
return nullptr;
15581567
case Node::Kind::AssociatedTypeDescriptor:
15591568
Printer << "associated type descriptor for ";
15601569
print(Node->getChild(0));

lib/Demangling/OldRemangler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,10 @@ void Remangler::mangleAssociatedTypeDescriptor(Node *node) {
884884
Out << "<associated-type-descriptor>";
885885
}
886886

887+
void Remangler::mangleAssociatedConformanceDescriptor(Node *node) {
888+
Out << "<associated-conformance-descriptor>";
889+
}
890+
887891
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
888892
Out << "Wt";
889893
mangleChildNodes(node); // protocol conformance, identifier

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,11 @@ void Remangler::mangleAssociatedTypeDescriptor(Node *node) {
574574
Buffer << "Tl";
575575
}
576576

577+
void Remangler::mangleAssociatedConformanceDescriptor(Node *node) {
578+
mangleChildNodes(node);
579+
Buffer << "Tn";
580+
}
581+
577582
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
578583
mangleChildNodes(node); // protocol conformance, identifier
579584
Buffer << "Wt";

lib/IRGen/GenDecl.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3387,6 +3387,26 @@ 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+
3400+
llvm::GlobalValue *IRGenModule::defineAssociatedConformanceDescriptor(
3401+
ProtocolDecl *proto,
3402+
CanType subject,
3403+
ProtocolDecl *requirement,
3404+
llvm::Constant *definition) {
3405+
auto entity = LinkEntity::forAssociatedConformanceDescriptor(proto, subject,
3406+
requirement);
3407+
return defineAlias(entity, definition);
3408+
}
3409+
33903410
llvm::Constant *IRGenModule::getAddrOfProtocolConformanceDescriptor(
33913411
const NormalProtocolConformance *conformance,
33923412
ConstantInit definition) {

lib/IRGen/GenMeta.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,16 @@ namespace {
709709
B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy));
710710
}
711711

712+
if (entry.isAssociatedConformance()) {
713+
// Define the associated conformance descriptor to point to the
714+
// current position in the protocol descriptor.
715+
IGM.defineAssociatedConformanceDescriptor(
716+
Proto,
717+
entry.getAssociatedConformancePath(),
718+
entry.getAssociatedConformanceRequirement(),
719+
B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy));
720+
}
721+
712722
auto reqt = B.beginStruct(IGM.ProtocolRequirementStructTy);
713723

714724
auto info = getRequirementInfo(entry);

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/IRGenMangler.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,19 @@ class IRGenMangler : public Mangle::ASTMangler {
184184
return finalize();
185185
}
186186

187+
std::string mangleAssociatedConformanceDescriptor(
188+
const ProtocolDecl *proto,
189+
CanType subject,
190+
const ProtocolDecl *requirement) {
191+
beginMangling();
192+
appendAnyGenericType(proto);
193+
bool isFirstAssociatedTypeIdentifier = true;
194+
appendAssociatedTypePath(subject, isFirstAssociatedTypeIdentifier);
195+
appendProtocolName(requirement);
196+
appendOperator("Tn");
197+
return finalize();
198+
}
199+
187200
std::string mangleProtocolConformanceDescriptor(
188201
const ProtocolConformance *Conformance) {
189202
beginMangling();
@@ -413,13 +426,6 @@ class IRGenMangler : public Mangle::ASTMangler {
413426

414427
std::string manglePartialApplyForwarder(StringRef FuncName);
415428

416-
std::string mangleForProtocolDescriptor(ProtocolType *Proto) {
417-
beginMangling();
418-
appendProtocolName(Proto->getDecl(), /*allowStandardSubstitution=*/false);
419-
appendOperator("P");
420-
return finalize();
421-
}
422-
423429
std::string mangleTypeForForeignMetadataUniquing(Type type) {
424430
return mangleTypeWithoutPrefix(type);
425431
}

lib/IRGen/IRGenModule.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,13 @@ private: \
12341234
llvm::GlobalValue *defineAssociatedTypeDescriptor(
12351235
AssociatedTypeDecl *assocType,
12361236
llvm::Constant *definition);
1237+
llvm::Constant *getAddrOfAssociatedConformanceDescriptor(
1238+
AssociatedConformance conformance);
1239+
llvm::GlobalValue *defineAssociatedConformanceDescriptor(
1240+
ProtocolDecl *proto,
1241+
CanType subject,
1242+
ProtocolDecl *requirement,
1243+
llvm::Constant *definition);
12371244

12381245
llvm::Constant *getAddrOfProtocolDescriptor(ProtocolDecl *D,
12391246
ConstantInit definition = ConstantInit());

0 commit comments

Comments
 (0)