Skip to content

Commit 78f3017

Browse files
authored
Merge pull request #19266 from DougGregor/associated-type-resilience
Associated type resilience
2 parents 9bff72a + dd77314 commit 78f3017

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+633
-169
lines changed

docs/ABI/Mangling.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ types where the metadata itself has unknown layout.)
138138
global ::= type generic-signature 'TH' // key path equality
139139
global ::= type generic-signature 'Th' // key path hasher
140140

141+
global ::= protocol 'TL' // protocol requirements base descriptor
142+
global ::= assoc-type-name 'Tl' // associated type descriptor
143+
144+
141145
REABSTRACT-THUNK-TYPE ::= 'R' // reabstraction thunk helper function
142146
REABSTRACT-THUNK-TYPE ::= 'r' // reabstraction thunk
143147

include/swift/ABI/Metadata.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,9 +2501,9 @@ class TargetGenericParamRef {
25012501
/// The protocol the associated type belongs to.
25022502
RelativeIndirectablePointer<TargetProtocolDescriptor<Runtime>,
25032503
/*nullable*/ false> Protocol;
2504-
/// The index of the associated type metadata within a witness table for
2505-
/// the protocol.
2506-
unsigned Index;
2504+
/// A reference to the associated type descriptor within the protocol.
2505+
RelativeIndirectablePointer<TargetProtocolRequirement<Runtime>,
2506+
/*nullable*/ false> Requirement;
25072507
};
25082508

25092509
/// A forward iterator that walks through the associated type path, which is

include/swift/Demangling/DemangleNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,8 @@ NODE(GenericTypeParamDecl)
208208
NODE(CurryThunk)
209209
NODE(DispatchThunk)
210210
NODE(MethodDescriptor)
211+
NODE(ProtocolRequirementsBaseDescriptor)
212+
NODE(AssociatedTypeDescriptor)
211213
NODE(ThrowsAnnotation)
212214
NODE(EmptyList)
213215
NODE(FirstElementMarker)

include/swift/IRGen/Linking.h

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@ class LinkEntity {
194194
/// The pointer is a ProtocolDecl*.
195195
ProtocolDescriptor,
196196

197+
/// The alias referring to the base of the requirements within the
198+
/// protocol descriptor, which is used to determine the offset of a
199+
/// particular requirement in the witness table.
200+
/// The pointer is a ProtocolDecl*.
201+
ProtocolRequirementsBaseDescriptor,
202+
203+
/// An descriptor for an associated type within a protocol, which
204+
/// will alias the TargetProtocolRequirement descripting this
205+
/// particular associated type.
206+
/// The pointer is an AssociatedTypeDecl*.
207+
AssociatedTypeDescriptor,
208+
197209
/// A SIL function. The pointer is a SILFunction*.
198210
SILFunction,
199211

@@ -307,7 +319,7 @@ class LinkEntity {
307319
}
308320

309321
static bool isDeclKind(Kind k) {
310-
return k <= Kind::ProtocolDescriptor;
322+
return k <= Kind::AssociatedTypeDescriptor;
311323
}
312324
static bool isTypeKind(Kind k) {
313325
return k >= Kind::ProtocolWitnessTableLazyAccessFunction;
@@ -634,6 +646,12 @@ class LinkEntity {
634646
return entity;
635647
}
636648

649+
static LinkEntity forProtocolRequirementsBaseDescriptor(ProtocolDecl *decl) {
650+
LinkEntity entity;
651+
entity.setForDecl(Kind::ProtocolRequirementsBaseDescriptor, decl);
652+
return entity;
653+
}
654+
637655
static LinkEntity forValueWitness(CanType concreteType, ValueWitness witness) {
638656
LinkEntity entity;
639657
entity.Pointer = concreteType.getPointer();
@@ -728,6 +746,13 @@ class LinkEntity {
728746
return entity;
729747
}
730748

749+
static LinkEntity
750+
forAssociatedTypeDescriptor(AssociatedTypeDecl *assocType) {
751+
LinkEntity entity;
752+
entity.setForDecl(Kind::AssociatedTypeDescriptor, assocType);
753+
return entity;
754+
}
755+
731756
static LinkEntity
732757
forAssociatedTypeMetadataAccessFunction(const ProtocolConformance *C,
733758
AssociatedType association) {
@@ -824,9 +849,12 @@ class LinkEntity {
824849
}
825850

826851
AssociatedTypeDecl *getAssociatedType() const {
827-
assert(getKind() == Kind::AssociatedTypeMetadataAccessFunction);
828-
return getAssociatedTypeByIndex(getProtocolConformance(),
852+
if (getKind() == Kind::AssociatedTypeMetadataAccessFunction)
853+
return getAssociatedTypeByIndex(getProtocolConformance(),
829854
LINKENTITY_GET_FIELD(Data, AssociatedTypeIndex));
855+
856+
assert(getKind() == Kind::AssociatedTypeDescriptor);
857+
return reinterpret_cast<AssociatedTypeDecl *>(Pointer);
830858
}
831859

832860
std::pair<CanType, ProtocolDecl *> getAssociatedConformance() const {

include/swift/SIL/SILWitnessVisitor.h

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -51,32 +51,6 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
5151
// The protocol conformance descriptor gets added first.
5252
asDerived().addProtocolConformanceDescriptor();
5353

54-
// Associated types get added after the inherited conformances, but
55-
// before all the function requirements.
56-
bool haveAddedAssociatedTypes = false;
57-
auto addAssociatedTypes = [&] {
58-
if (haveAddedAssociatedTypes) return;
59-
haveAddedAssociatedTypes = true;
60-
61-
SmallVector<AssociatedTypeDecl *, 2> associatedTypes;
62-
for (Decl *member : protocol->getMembers()) {
63-
if (auto associatedType = dyn_cast<AssociatedTypeDecl>(member)) {
64-
// If this is a new associated type (which does not override an
65-
// existing associated type), add it.
66-
if (associatedType->getOverriddenDecls().empty())
67-
associatedTypes.push_back(associatedType);
68-
}
69-
}
70-
71-
// Sort associated types by name, for resilience.
72-
llvm::array_pod_sort(associatedTypes.begin(), associatedTypes.end(),
73-
TypeDecl::compare);
74-
75-
for (auto *associatedType : associatedTypes) {
76-
asDerived().addAssociatedType(AssociatedType(associatedType));
77-
}
78-
};
79-
8054
for (const auto &reqt : protocol->getRequirementSignature()) {
8155
switch (reqt.getKind()) {
8256
// These requirements don't show up in the witness table.
@@ -101,17 +75,12 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
10175
// come before any protocol requirements on associated types.
10276
if (auto parameter = dyn_cast<GenericTypeParamType>(type)) {
10377
assert(type->isEqual(protocol->getSelfInterfaceType()));
104-
assert(!haveAddedAssociatedTypes &&
105-
"unexpected ordering of conformances");
10678
assert(parameter->getDepth() == 0 && parameter->getIndex() == 0 &&
10779
"non-self type parameter in protocol");
10880
asDerived().addOutOfLineBaseProtocol(requirement);
10981
continue;
11082
}
11183

112-
// Add the associated types if we haven't yet.
113-
addAssociatedTypes();
114-
11584
// Otherwise, add an associated requirement.
11685
AssociatedConformance assocConf(protocol, type, requirement);
11786
asDerived().addAssociatedConformance(assocConf);
@@ -121,8 +90,15 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
12190
llvm_unreachable("bad requirement kind");
12291
}
12392

124-
// Add the associated types if we haven't yet.
125-
addAssociatedTypes();
93+
// Add the associated types.
94+
for (Decl *member : protocol->getMembers()) {
95+
if (auto associatedType = dyn_cast<AssociatedTypeDecl>(member)) {
96+
// If this is a new associated type (which does not override an
97+
// existing associated type), add it.
98+
if (associatedType->getOverriddenDecls().empty())
99+
asDerived().addAssociatedType(AssociatedType(associatedType));
100+
}
101+
}
126102

127103
if (asDerived().shouldVisitRequirementSignatureOnly())
128104
return;

lib/Demangling/Demangler.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1812,6 +1812,18 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
18121812
}
18131813
return result;
18141814
}
1815+
case 'l': {
1816+
auto assocTypeName = popAssocTypeName();
1817+
if (!assocTypeName)
1818+
return nullptr;
1819+
1820+
return createWithChild(Node::Kind::AssociatedTypeDescriptor,
1821+
assocTypeName);
1822+
}
1823+
case 'L':
1824+
return createWithChild(Node::Kind::ProtocolRequirementsBaseDescriptor,
1825+
popProtocol());
1826+
18151827
case 'H':
18161828
case 'h': {
18171829
auto nodeKind = c == 'H' ? Node::Kind::KeyPathEqualsThunkHelper

lib/Demangling/NodePrinter.cpp

Lines changed: 10 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::AssociatedTypeDescriptor:
311312
case Node::Kind::AssociatedTypeMetadataAccessor:
312313
case Node::Kind::AssociatedTypeWitnessTableAccessor:
313314
case Node::Kind::AutoClosureType:
@@ -406,6 +407,7 @@ class NodePrinter {
406407
case Node::Kind::ProtocolConformance:
407408
case Node::Kind::ProtocolConformanceDescriptor:
408409
case Node::Kind::ProtocolDescriptor:
410+
case Node::Kind::ProtocolRequirementsBaseDescriptor:
409411
case Node::Kind::ProtocolWitness:
410412
case Node::Kind::ProtocolWitnessTable:
411413
case Node::Kind::ProtocolWitnessTableAccessor:
@@ -1516,6 +1518,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
15161518
Printer << "protocol descriptor for ";
15171519
print(Node->getChild(0));
15181520
return nullptr;
1521+
case Node::Kind::ProtocolRequirementsBaseDescriptor:
1522+
Printer << "protocol requirements base descriptor for ";
1523+
print(Node->getChild(0));
1524+
return nullptr;
15191525
case Node::Kind::FullTypeMetadata:
15201526
Printer << "full type metadata for ";
15211527
print(Node->getChild(0));
@@ -1548,6 +1554,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
15481554
Printer << "lazy cache variable for type metadata for ";
15491555
print(Node->getChild(0));
15501556
return nullptr;
1557+
case Node::Kind::AssociatedTypeDescriptor:
1558+
Printer << "associated type descriptor for ";
1559+
print(Node->getChild(0));
1560+
return nullptr;
15511561
case Node::Kind::AssociatedTypeMetadataAccessor:
15521562
Printer << "associated type metadata accessor for ";
15531563
print(Node->getChild(1));

lib/Demangling/OldRemangler.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,10 @@ void Remangler::mangleProtocolDescriptor(Node *node) {
777777
mangleProtocolWithoutPrefix(node->begin()[0]);
778778
}
779779

780+
void Remangler::mangleProtocolRequirementsBaseDescriptor(Node *node) {
781+
Out << "<protocol-requirements-base-descriptor>";
782+
}
783+
780784
void Remangler::mangleProtocolWitnessTablePattern(Node *node) {
781785
unreachable("todo");
782786
}
@@ -876,6 +880,10 @@ void Remangler::mangleLazyProtocolWitnessTableCacheVariable(Node *node) {
876880
mangleChildNodes(node); // type, protocol conformance
877881
}
878882

883+
void Remangler::mangleAssociatedTypeDescriptor(Node *node) {
884+
Out << "<associated-type-descriptor>";
885+
}
886+
879887
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
880888
Out << "Wt";
881889
mangleChildNodes(node); // protocol conformance, identifier

lib/Demangling/Remangler.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,11 @@ void Remangler::mangleAssociatedTypeRef(Node *node) {
569569
addSubstitution(entry);
570570
}
571571

572+
void Remangler::mangleAssociatedTypeDescriptor(Node *node) {
573+
mangleChildNodes(node);
574+
Buffer << "Tl";
575+
}
576+
572577
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
573578
mangleChildNodes(node); // protocol conformance, identifier
574579
Buffer << "Wt";
@@ -1609,6 +1614,11 @@ void Remangler::mangleProtocolDescriptor(Node *node) {
16091614
Buffer << "Mp";
16101615
}
16111616

1617+
void Remangler::mangleProtocolRequirementsBaseDescriptor(Node *node) {
1618+
manglePureProtocol(getSingleChild(node));
1619+
Buffer << "TL";
1620+
}
1621+
16121622
void Remangler::mangleProtocolConformanceDescriptor(Node *node) {
16131623
mangleProtocolConformance(node->getChild(0));
16141624
Buffer << "Mc";

lib/IRGen/GenDecl.cpp

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -907,15 +907,13 @@ llvm::Constant *IRGenModule::getAddrOfAssociatedTypeGenericParamRef(
907907
auto proto = getConstantReferenceForProtocolDescriptor(
908908
assocType->getProtocol());
909909
B.addRelativeAddress(proto);
910-
911-
// Find the offset of the associated type entry in witness tables of this
912-
// protocol.
913-
auto &protoInfo = getProtocolInfo(assocType->getProtocol(),
914-
ProtocolInfoKind::RequirementSignature);
915-
auto index = protoInfo.getAssociatedTypeIndex(AssociatedType(assocType))
916-
.getValue();
917-
918-
B.addInt32(index);
910+
911+
// Add a reference to the associated type descriptor.
912+
auto assocTypeDescriptor =
913+
getAddrOfLLVMVariableOrGOTEquivalent(
914+
LinkEntity::forAssociatedTypeDescriptor(assocType),
915+
Alignment(4), ProtocolRequirementStructTy);
916+
B.addRelativeAddress(assocTypeDescriptor);
919917
}
920918

921919
// Null terminator.
@@ -3359,6 +3357,36 @@ llvm::Constant *IRGenModule::getAddrOfProtocolDescriptor(ProtocolDecl *D,
33593357
ProtocolDescriptorStructTy, DebugTypeInfo());
33603358
}
33613359

3360+
llvm::Constant *IRGenModule::getAddrOfProtocolRequirementsBaseDescriptor(
3361+
ProtocolDecl *proto) {
3362+
auto entity = LinkEntity::forProtocolRequirementsBaseDescriptor(proto);
3363+
return getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(),
3364+
ProtocolRequirementStructTy,
3365+
DebugTypeInfo());
3366+
}
3367+
3368+
llvm::GlobalValue *IRGenModule::defineProtocolRequirementsBaseDescriptor(
3369+
ProtocolDecl *proto,
3370+
llvm::Constant *definition) {
3371+
auto entity = LinkEntity::forProtocolRequirementsBaseDescriptor(proto);
3372+
return defineAlias(entity, definition);
3373+
}
3374+
3375+
llvm::Constant *IRGenModule::getAddrOfAssociatedTypeDescriptor(
3376+
AssociatedTypeDecl *assocType) {
3377+
auto entity = LinkEntity::forAssociatedTypeDescriptor(assocType);
3378+
return getAddrOfLLVMVariable(entity, getPointerAlignment(), ConstantInit(),
3379+
ProtocolRequirementStructTy,
3380+
DebugTypeInfo());
3381+
}
3382+
3383+
llvm::GlobalValue *IRGenModule::defineAssociatedTypeDescriptor(
3384+
AssociatedTypeDecl *assocType,
3385+
llvm::Constant *definition) {
3386+
auto entity = LinkEntity::forAssociatedTypeDescriptor(assocType);
3387+
return defineAlias(entity, definition);
3388+
}
3389+
33623390
llvm::Constant *IRGenModule::getAddrOfProtocolConformanceDescriptor(
33633391
const NormalProtocolConformance *conformance,
33643392
ConstantInit definition) {

lib/IRGen/GenMeta.cpp

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -667,14 +667,41 @@ namespace {
667667
B.fillPlaceholderWithInt(*NumRequirements, IGM.Int32Ty,
668668
pi.getNumWitnesses());
669669

670+
if (pi.getNumWitnesses() > 0) {
671+
// Define the protocol requirements "base" descriptor, which references
672+
// the beginning of the protocol requirements, offset so that
673+
// subtracting this address from the address of a given protocol
674+
// requirements gives the corresponding offset into the witness
675+
// table.
676+
auto address =
677+
B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy);
678+
int offset = WitnessTableFirstRequirementOffset;
679+
auto firstReqAdjustment = llvm::ConstantInt::get(IGM.Int32Ty, -offset);
680+
address = llvm::ConstantExpr::getGetElementPtr(nullptr, address,
681+
firstReqAdjustment);
682+
683+
IGM.defineProtocolRequirementsBaseDescriptor(Proto, address);
684+
}
685+
670686
for (auto &entry : pi.getWitnessEntries()) {
671-
if (Resilient && entry.isFunction()) {
672-
// Define the method descriptor.
673-
SILDeclRef func(entry.getFunction());
674-
auto *descriptor =
675-
B.getAddrOfCurrentPosition(
676-
IGM.ProtocolRequirementStructTy);
677-
IGM.defineMethodDescriptor(func, Proto, descriptor);
687+
if (Resilient) {
688+
if (entry.isFunction()) {
689+
// Define the method descriptor.
690+
SILDeclRef func(entry.getFunction());
691+
auto *descriptor =
692+
B.getAddrOfCurrentPosition(
693+
IGM.ProtocolRequirementStructTy);
694+
IGM.defineMethodDescriptor(func, Proto, descriptor);
695+
}
696+
}
697+
698+
if (entry.isAssociatedType()) {
699+
auto assocType = entry.getAssociatedType();
700+
// Define the associated type descriptor to point to the current
701+
// position in the protocol descriptor.
702+
IGM.defineAssociatedTypeDescriptor(
703+
assocType,
704+
B.getAddrOfCurrentPosition(IGM.ProtocolRequirementStructTy));
678705
}
679706

680707
auto reqt = B.beginStruct(IGM.ProtocolRequirementStructTy);

0 commit comments

Comments
 (0)