Skip to content

Commit 8f30faa

Browse files
committed
Include access functions for the metadata and witness tables
of associated types in protocol witness tables. We use the global access functions when the result isn't dependent, and a simple accessor when the result can be cheaply recovered from the conforming metadata. Otherwise, we add a cache slot to a private section of the witness table, forcing an instantiation per conformance. Like generic type metadata, concrete instantiations of generic conformances are memoized. There's a fair amount of code in this patch that can't be dynamically tested at the moment because of the widespread reliance on recursive expansion of archetypes / dependent types. That's something we're now theoretically in a position to change, and as we do so, we'll test more of this code. This speculatively re-applies 7576a91, i.e. reverts commit 11ab3d5. We have not been able to duplicate the build failure in independent testing; it might have been spurious or unrelated.
1 parent be4bf81 commit 8f30faa

30 files changed

+1606
-250
lines changed

docs/ABI.rst

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -743,15 +743,17 @@ Globals
743743
global ::= 'PA' .* // partial application forwarder
744744
global ::= 'PAo' .* // ObjC partial application forwarder
745745
global ::= 'w' value-witness-kind type // value witness
746-
global ::= 'WV' type // value witness table
747-
global ::= 'Wo' entity // witness table offset
748-
global ::= 'Wv' directness entity // field offset
749-
global ::= 'WP' protocol-conformance // protocol witness table
750746
global ::= 'Wa' protocol-conformance // protocol witness table accessor
747+
global ::= 'WG' protocol-conformance // generic protocol witness table
748+
global ::= 'WI' protocol-conformance // generic protocol witness table instantiation function
751749
global ::= 'Wl' type protocol-conformance // lazy protocol witness table accessor
752750
global ::= 'WL' protocol-conformance // lazy protocol witness table cache variable
753-
global ::= 'WD' protocol-conformance // dependent proto witness table generator
754-
global ::= 'Wd' protocol-conformance // dependent proto witness table template
751+
global ::= 'Wo' entity // witness table offset
752+
global ::= 'WP' protocol-conformance // protocol witness table
753+
global ::= 'Wt' protocol-conformance identifier // associated type metadata accessor
754+
global ::= 'WT' protocol-conformance identifier nominal-type // associated type witness table accessor
755+
global ::= 'Wv' directness entity // field offset
756+
global ::= 'WV' type // value witness table
755757
global ::= entity // some identifiable thing
756758
global ::= 'TO' global // ObjC-as-swift thunk
757759
global ::= 'To' global // swift-as-ObjC thunk

include/swift/Basic/DemangleNodes.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ NODE(ArchetypeRef)
3030
NODE(ArgumentTuple)
3131
NODE(AssociatedType)
3232
NODE(AssociatedTypeRef)
33+
NODE(AssociatedTypeMetadataAccessor)
34+
NODE(AssociatedTypeWitnessTableAccessor)
3335
NODE(AutoClosureType)
3436
NODE(BoundGenericClass)
3537
NODE(BoundGenericEnum)
@@ -49,8 +51,6 @@ NODE(DependentGenericSameTypeRequirement)
4951
NODE(DependentGenericType)
5052
NODE(DependentMemberType)
5153
NODE(DependentGenericParamType)
52-
NODE(DependentProtocolWitnessTableGenerator)
53-
NODE(DependentProtocolWitnessTableTemplate)
5454
CONTEXT_NODE(Destructor)
5555
CONTEXT_NODE(DidSet)
5656
NODE(Directness)
@@ -71,6 +71,8 @@ NODE(FunctionSignatureSpecializationParamKind)
7171
NODE(FunctionSignatureSpecializationParamPayload)
7272
NODE(FunctionType)
7373
NODE(Generics)
74+
NODE(GenericProtocolWitnessTable)
75+
NODE(GenericProtocolWitnessTableInstantiationFunction)
7476
NODE(GenericSpecialization)
7577
NODE(GenericSpecializationParam)
7678
NODE(GenericType)

include/swift/Basic/RelativePointer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ class RelativeDirectPointerImpl {
102102
return reinterpret_cast<PointerTy>(absolute);
103103
}
104104

105+
/// A zero relative offset encodes a null reference.
106+
bool isNull() const & {
107+
return RelativeOffset == 0;
108+
}
105109
};
106110

107111
/// A direct relative reference to an object.
@@ -122,6 +126,8 @@ class RelativeDirectPointer :
122126
const typename super::ValueTy *operator->() const & {
123127
return this->get();
124128
}
129+
130+
using super::isNull;
125131
};
126132

127133
/// A specialization of RelativeDirectPointer for function pointers,
@@ -139,6 +145,8 @@ class RelativeDirectPointer<RetTy (ArgTy...)> :
139145
RetTy operator()(ArgTy...arg) {
140146
return this->get()(std::forward<ArgTy>(arg)...);
141147
}
148+
149+
using super::isNull;
142150
};
143151

144152
}

include/swift/Runtime/Metadata.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2106,6 +2106,25 @@ struct GenericMetadata {
21062106
}
21072107
};
21082108

2109+
/// \brief The control structure of a generic protocol conformance.
2110+
struct GenericWitnessTable {
2111+
/// The size of the witness table in words.
2112+
uint16_t WitnessTableSizeInWords;
2113+
2114+
/// The amount to copy from the pattern in words. The rest is zeroed.
2115+
uint16_t WitnessTableSizeInWordsToCopy;
2116+
2117+
/// The pattern.
2118+
RelativeDirectPointer<WitnessTable> Pattern;
2119+
2120+
/// The instantiation function, which is called after the template is copied.
2121+
RelativeDirectPointer<void(WitnessTable *instantiatedTable,
2122+
const Metadata *type,
2123+
void * const *instantiationArgs)> Instantiator;
2124+
2125+
void *PrivateData[swift::NumGenericMetadataPrivateDataWords];
2126+
};
2127+
21092128
/// The structure of a protocol conformance record.
21102129
///
21112130
/// This contains enough static information to recover the witness table for a
@@ -2333,6 +2352,20 @@ swift_allocateGenericClassMetadata(GenericMetadata *pattern,
23332352
extern "C" Metadata *
23342353
swift_allocateGenericValueMetadata(GenericMetadata *pattern,
23352354
const void *arguments);
2355+
2356+
/// Instantiate a generic protocol witness table.
2357+
///
2358+
///
2359+
/// \param instantiationArgs - An opaque pointer that's forwarded to
2360+
/// the instantiation function, used for conditional conformances.
2361+
/// This API implicitly embeds an assumption that these arguments
2362+
/// never form part of the uniquing key for the conformance, which
2363+
/// is ultimately a statement about the user model of overlapping
2364+
/// conformances.
2365+
extern "C" const WitnessTable *
2366+
swift_getGenericWitnessTable(GenericWitnessTable *genericTable,
2367+
const Metadata *type,
2368+
void * const *instantiationArgs);
23362369

23372370
/// \brief Fetch a uniqued metadata for a function type.
23382371
extern "C" const FunctionTypeMetadata *

lib/Basic/Demangle.cpp

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,18 @@ class Demangler {
577577
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance);
578578
return witnessTable;
579579
}
580+
if (Mangled.nextIf('G')) {
581+
auto witnessTable =
582+
NodeFactory::create(Node::Kind::GenericProtocolWitnessTable);
583+
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance);
584+
return witnessTable;
585+
}
586+
if (Mangled.nextIf('I')) {
587+
auto witnessTable = NodeFactory::create(
588+
Node::Kind::GenericProtocolWitnessTableInstantiationFunction);
589+
DEMANGLE_CHILD_OR_RETURN(witnessTable, ProtocolConformance);
590+
return witnessTable;
591+
}
580592
if (Mangled.nextIf('l')) {
581593
auto accessor =
582594
NodeFactory::create(Node::Kind::LazyProtocolWitnessTableAccessor);
@@ -597,17 +609,20 @@ class Demangler {
597609
DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance);
598610
return tableTemplate;
599611
}
600-
if (Mangled.nextIf('D')) {
601-
auto tableGenerator = NodeFactory::create(
602-
Node::Kind::DependentProtocolWitnessTableGenerator);
603-
DEMANGLE_CHILD_OR_RETURN(tableGenerator, ProtocolConformance);
604-
return tableGenerator;
612+
if (Mangled.nextIf('t')) {
613+
auto accessor = NodeFactory::create(
614+
Node::Kind::AssociatedTypeMetadataAccessor);
615+
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
616+
DEMANGLE_CHILD_OR_RETURN(accessor, DeclName);
617+
return accessor;
605618
}
606-
if (Mangled.nextIf('d')) {
607-
auto tableTemplate = NodeFactory::create(
608-
Node::Kind::DependentProtocolWitnessTableTemplate);
609-
DEMANGLE_CHILD_OR_RETURN(tableTemplate, ProtocolConformance);
610-
return tableTemplate;
619+
if (Mangled.nextIf('T')) {
620+
auto accessor = NodeFactory::create(
621+
Node::Kind::AssociatedTypeWitnessTableAccessor);
622+
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolConformance);
623+
DEMANGLE_CHILD_OR_RETURN(accessor, DeclName);
624+
DEMANGLE_CHILD_OR_RETURN(accessor, ProtocolName);
625+
return accessor;
611626
}
612627
return nullptr;
613628
}
@@ -2352,6 +2367,8 @@ class NodePrinter {
23522367

23532368
case Node::Kind::Allocator:
23542369
case Node::Kind::ArgumentTuple:
2370+
case Node::Kind::AssociatedTypeMetadataAccessor:
2371+
case Node::Kind::AssociatedTypeWitnessTableAccessor:
23552372
case Node::Kind::AutoClosureType:
23562373
case Node::Kind::CFunctionPointer:
23572374
case Node::Kind::Constructor:
@@ -2363,8 +2380,6 @@ class NodePrinter {
23632380
case Node::Kind::DependentGenericParamCount:
23642381
case Node::Kind::DependentGenericConformanceRequirement:
23652382
case Node::Kind::DependentGenericSameTypeRequirement:
2366-
case Node::Kind::DependentProtocolWitnessTableGenerator:
2367-
case Node::Kind::DependentProtocolWitnessTableTemplate:
23682383
case Node::Kind::Destructor:
23692384
case Node::Kind::DidSet:
23702385
case Node::Kind::DirectMethodReferenceAttribute:
@@ -2381,6 +2396,8 @@ class NodePrinter {
23812396
case Node::Kind::FunctionSignatureSpecializationParamPayload:
23822397
case Node::Kind::FunctionType:
23832398
case Node::Kind::Generics:
2399+
case Node::Kind::GenericProtocolWitnessTable:
2400+
case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
23842401
case Node::Kind::GenericSpecialization:
23852402
case Node::Kind::GenericSpecializationParam:
23862403
case Node::Kind::GenericType:
@@ -3165,14 +3182,6 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
31653182
case Node::Kind::PostfixOperator:
31663183
Printer << pointer->getText() << " postfix";
31673184
return;
3168-
case Node::Kind::DependentProtocolWitnessTableGenerator:
3169-
Printer << "dependent protocol witness table generator for ";
3170-
print(pointer->getFirstChild());
3171-
return;
3172-
case Node::Kind::DependentProtocolWitnessTableTemplate:
3173-
Printer << "dependent protocol witness table template for ";
3174-
print(pointer->getFirstChild());
3175-
return;
31763185
case Node::Kind::LazyProtocolWitnessTableAccessor:
31773186
Printer << "lazy protocol witness table accessor for type ";
31783187
print(pointer->getChild(0));
@@ -3193,6 +3202,14 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
31933202
Printer << "protocol witness table for ";
31943203
print(pointer->getFirstChild());
31953204
return;
3205+
case Node::Kind::GenericProtocolWitnessTable:
3206+
Printer << "generic protocol witness table for ";
3207+
print(pointer->getFirstChild());
3208+
return;
3209+
case Node::Kind::GenericProtocolWitnessTableInstantiationFunction:
3210+
Printer << "instantiation function for generic protocol witness table for ";
3211+
print(pointer->getFirstChild());
3212+
return;
31963213
case Node::Kind::ProtocolWitness: {
31973214
Printer << "protocol witness for ";
31983215
print(pointer->getChild(1));
@@ -3279,6 +3296,20 @@ void NodePrinter::print(NodePointer pointer, bool asContext, bool suppressType)
32793296
Printer << "lazy cache variable for type metadata for ";
32803297
print(pointer->getChild(0));
32813298
return;
3299+
case Node::Kind::AssociatedTypeMetadataAccessor:
3300+
Printer << "associated type metadata accessor for ";
3301+
print(pointer->getChild(1));
3302+
Printer << " in ";
3303+
print(pointer->getChild(0));
3304+
return;
3305+
case Node::Kind::AssociatedTypeWitnessTableAccessor:
3306+
Printer << "associated type witness table accessor for ";
3307+
print(pointer->getChild(1));
3308+
Printer << " : ";
3309+
print(pointer->getChild(2));
3310+
Printer << " in ";
3311+
print(pointer->getChild(0));
3312+
return;
32823313
case Node::Kind::NominalTypeDescriptor:
32833314
Printer << "nominal type descriptor for ";
32843315
print(pointer->getChild(0));

lib/Basic/Remangle.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,17 @@ void Remangler::mangleProtocolWitnessTable(Node *node) {
698698
mangleSingleChildNode(node); // protocol conformance
699699
}
700700

701+
void Remangler::mangleGenericProtocolWitnessTable(Node *node) {
702+
Out << "WG";
703+
mangleSingleChildNode(node); // protocol conformance
704+
}
705+
706+
void Remangler::mangleGenericProtocolWitnessTableInstantiationFunction(
707+
Node *node) {
708+
Out << "WI";
709+
mangleSingleChildNode(node); // protocol conformance
710+
}
711+
701712
void Remangler::mangleProtocolWitnessTableAccessor(Node *node) {
702713
Out << "Wa";
703714
mangleSingleChildNode(node); // protocol conformance
@@ -713,14 +724,17 @@ void Remangler::mangleLazyProtocolWitnessTableCacheVariable(Node *node) {
713724
mangleChildNodes(node); // type, protocol conformance
714725
}
715726

716-
void Remangler::mangleDependentProtocolWitnessTableGenerator(Node *node) {
717-
Out << "WD";
718-
mangleSingleChildNode(node); // protocol conformance
727+
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
728+
Out << "Wt";
729+
mangleChildNodes(node); // protocol conformance, identifier
719730
}
720731

721-
void Remangler::mangleDependentProtocolWitnessTableTemplate(Node *node) {
722-
Out << "Wd";
723-
mangleSingleChildNode(node); // protocol conformance
732+
void Remangler::mangleAssociatedTypeWitnessTableAccessor(Node *node) {
733+
Out << "WT";
734+
assert(node->getNumChildren() == 3);
735+
mangleChildNode(node, 0); // protocol conformance
736+
mangleChildNode(node, 1); // identifier
737+
mangleProtocolWithoutPrefix(node->begin()[2].get()); // type
724738
}
725739

726740
void Remangler::mangleReabstractionThunkHelper(Node *node) {

0 commit comments

Comments
 (0)