Skip to content

Commit c8b886f

Browse files
authored
Merge pull request #15387 from slavapestov/protocol-resilience
Order-independent protocol witness table instantiation
2 parents fcd86e3 + be07366 commit c8b886f

28 files changed

+605
-307
lines changed

docs/ABI/Mangling.rst

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,11 @@ Globals
6363
global ::= context 'MXX' // anonymous context descriptor
6464
global ::= context identifier 'MXY' // anonymous context descriptor
6565
global ::= type assoc_type_path 'MXA' // generic parameter ref
66-
global ::= nominal-type 'Mo' // class metadata immediate member base offset
6766
global ::= protocol 'Mp' // protocol descriptor
68-
global ::= protocol-conformance 'Mc' // protocol conformance descriptor
67+
global ::= protocol 'WR' // protocol requirement table
68+
69+
global ::= nominal-type 'Mo' // class metadata immediate member base offset
70+
6971
global ::= type 'MF' // metadata for remote mirrors: field descriptor
7072
global ::= type 'MB' // metadata for remote mirrors: builtin type descriptor
7173
global ::= protocol-conformance 'MA' // metadata for remote mirrors: associated type descriptor
@@ -76,35 +78,27 @@ Globals
7678
global ::= mangled-name 'Ta' // ObjC partial application forwarder
7779

7880
global ::= type 'w' VALUE-WITNESS-KIND // value witness
81+
82+
global ::= protocol-conformance 'Mc' // protocol conformance descriptor
83+
global ::= protocol-conformance 'WP' // protocol witness table
7984
global ::= protocol-conformance 'Wa' // protocol witness table accessor
85+
8086
global ::= protocol-conformance 'WG' // generic protocol witness table
87+
global ::= protocol-conformance 'Wp' // protocol witness table pattern
88+
global ::= protocol-conformance 'Wr' // resilient witness table
8189
global ::= protocol-conformance 'WI' // generic protocol witness table instantiation function
8290
global ::= type protocol-conformance 'WL' // lazy protocol witness table cache variable
83-
global ::= entity 'Wo' // witness table offset
84-
global ::= protocol-conformance 'WP' // protocol witness table
8591

8692
global ::= protocol-conformance identifier 'Wt' // associated type metadata accessor
8793
global ::= protocol-conformance assoc_type_path nominal-type 'WT' // associated type witness table accessor
8894
global ::= type protocol-conformance 'Wl' // lazy protocol witness table accessor
95+
8996
global ::= type 'WV' // value witness table
90-
global ::= entity 'Wv' DIRECTNESS // field offset
91-
global ::= entity 'WC' // resilient enum tag index
92-
93-
global ::= type 'Wy' // Outlined Copy Function Type
94-
global ::= type 'We' // Outlined Consume Function Type
95-
global ::= type 'Wr' // Outlined Retain Function Type
96-
global ::= type 'Ws' // Outlined Release Function Type
97-
global ::= type 'Wb' INDEX // Outlined InitializeWithTake Function Type
98-
global ::= type 'Wc' INDEX // Outlined InitializeWithCopy Function Type
99-
global ::= type 'Wd' INDEX // Outlined AssignWithTake Function Type
100-
global ::= type 'Wf' INDEX // Outlined AssignWithCopy Function Type
101-
global ::= type 'Wh' INDEX // Outlined Destroy Function Type
97+
global ::= entity 'Wvd' // field offset
98+
global ::= entity 'WC' // resilient enum tag index
10299

103100
assoc_type_path ::= identifier '_' identifier*
104101

105-
DIRECTNESS ::= 'd' // direct
106-
DIRECTNESS ::= 'i' // indirect
107-
108102
A direct symbol resolves directly to the address of an object. An
109103
indirect symbol resolves to the address of a pointer to the object.
110104
They are distinct manglings to make a certain class of bugs
@@ -175,6 +169,18 @@ The types in a reabstraction thunk helper function are always non-polymorphic
175169
``<VALUE-WITNESS-KIND>`` differentiates the kinds of value
176170
witness functions for a type.
177171

172+
::
173+
174+
global ::= generic-signature? type 'WOy' // Outlined copy
175+
global ::= generic-signature? type 'WOe' // Outlined consume
176+
global ::= generic-signature? type 'WOr' // Outlined retain
177+
global ::= generic-signature? type 'WOs' // Outlined release
178+
global ::= generic-signature? type 'WOb' // Outlined initializeWithTake
179+
global ::= generic-signature? type 'WOc' // Outlined initializeWithCopy
180+
global ::= generic-signature? type 'WOd' // Outlined assignWithTake
181+
global ::= generic-signature? type 'WOf' // Outlined assignWithCopy
182+
global ::= generic-signature? type 'WOh' // Outlined destroy
183+
178184
Entities
179185
~~~~~~~~
180186

include/swift/Demangling/DemangleNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ NODE(GenericPartialSpecialization)
8181
NODE(GenericPartialSpecializationNotReAbstracted)
8282
NODE(GenericProtocolWitnessTable)
8383
NODE(GenericProtocolWitnessTableInstantiationFunction)
84+
NODE(ResilientProtocolWitnessTable)
8485
NODE(GenericSpecialization)
8586
NODE(GenericSpecializationNotReAbstracted)
8687
NODE(GenericSpecializationParam)

include/swift/IRGen/Linking.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ class LinkEntity {
215215
/// The secondary pointer is a ProtocolConformance*.
216216
GenericProtocolWitnessTableInstantiationFunction,
217217

218+
/// A list of key/value pairs that resiliently specify a witness table.
219+
ResilientProtocolWitnessTable,
220+
218221
/// A function which returns the type metadata for the associated type
219222
/// of a protocol. The secondary pointer is a ProtocolConformance*.
220223
/// The index of the associated type declaration is stored in the data.
@@ -641,6 +644,13 @@ class LinkEntity {
641644
return entity;
642645
}
643646

647+
static LinkEntity
648+
forResilientProtocolWitnessTable(const ProtocolConformance *C) {
649+
LinkEntity entity;
650+
entity.setForProtocolConformance(Kind::ResilientProtocolWitnessTable, C);
651+
return entity;
652+
}
653+
644654
static LinkEntity
645655
forGenericProtocolWitnessTableInstantiationFunction(
646656
const ProtocolConformance *C) {

include/swift/Runtime/Metadata.h

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,14 +1991,11 @@ struct TargetProtocolDescriptor {
19911991
/// Additional flags.
19921992
ProtocolDescriptorFlags Flags;
19931993

1994-
/// The number of non-defaultable requirements in the protocol.
1995-
uint16_t NumMandatoryRequirements;
1996-
19971994
/// The number of requirements described by the Requirements array.
19981995
/// If any requirements beyond MinimumWitnessTableSizeInWords are present
19991996
/// in the witness table template, they will be not be overwritten with
20001997
/// defaults.
2001-
uint16_t NumRequirements;
1998+
uint32_t NumRequirements;
20021999

20032000
/// Requirement descriptions.
20042001
RelativeDirectPointer<TargetProtocolRequirement<Runtime>> Requirements;
@@ -2011,10 +2008,6 @@ struct TargetProtocolDescriptor {
20112008
/// as the requirements.
20122009
RelativeDirectPointer<const char, /*Nullable=*/true> AssociatedTypeNames;
20132010

2014-
void *getDefaultWitness(unsigned index) const {
2015-
return Requirements.get()[index].DefaultImplementation.get();
2016-
}
2017-
20182011
// This is only used in unittests/Metadata.cpp.
20192012
constexpr TargetProtocolDescriptor<Runtime>(const char *Name,
20202013
const TargetProtocolDescriptorList<Runtime> *Inherited,
@@ -2026,7 +2019,6 @@ struct TargetProtocolDescriptor {
20262019
_ObjC_InstanceProperties(nullptr),
20272020
DescriptorSize(sizeof(TargetProtocolDescriptor<Runtime>)),
20282021
Flags(Flags),
2029-
NumMandatoryRequirements(0),
20302022
NumRequirements(0),
20312023
Requirements(nullptr),
20322024
Superclass(nullptr),
@@ -2277,6 +2269,57 @@ struct TargetGenericBoxHeapMetadata : public TargetBoxHeapMetadata<Runtime> {
22772269
};
22782270
using GenericBoxHeapMetadata = TargetGenericBoxHeapMetadata<InProcess>;
22792271

2272+
/// \brief The control structure of a generic or resilient protocol
2273+
/// conformance witness.
2274+
///
2275+
/// Resilient conformances must use a pattern where new requirements
2276+
/// with default implementations can be added and the order of existing
2277+
/// requirements can be changed.
2278+
///
2279+
/// This is accomplished by emitting an order-independent series of
2280+
/// relative pointer pairs, consisting of a protocol requirement together
2281+
/// with a witness. The requirement is identified by an indirect relative
2282+
/// pointer to the protocol dispatch thunk.
2283+
template <typename Runtime>
2284+
struct TargetResilientWitness {
2285+
RelativeIndirectPointer<void> Function;
2286+
RelativeDirectPointer<void> Witness;
2287+
};
2288+
using ResilientWitness = TargetResilientWitness<InProcess>;
2289+
2290+
template <typename Runtime>
2291+
struct TargetResilientWitnessTable final
2292+
: public swift::ABI::TrailingObjects<
2293+
TargetResilientWitnessTable<Runtime>,
2294+
TargetResilientWitness<Runtime>> {
2295+
uint32_t NumWitnesses;
2296+
2297+
using TrailingObjects = swift::ABI::TrailingObjects<
2298+
TargetResilientWitnessTable<Runtime>,
2299+
TargetResilientWitness<Runtime>>;
2300+
friend TrailingObjects;
2301+
2302+
template<typename T>
2303+
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;
2304+
2305+
size_t numTrailingObjects(
2306+
OverloadToken<TargetResilientWitness<Runtime>>) const {
2307+
return NumWitnesses;
2308+
}
2309+
2310+
llvm::ArrayRef<TargetResilientWitness<Runtime>>
2311+
getWitnesses() const {
2312+
return {this->template getTrailingObjects<TargetResilientWitness<Runtime>>(),
2313+
NumWitnesses};
2314+
}
2315+
2316+
const TargetResilientWitness<Runtime> &
2317+
getWitness(unsigned i) const {
2318+
return getWitnesses()[i];
2319+
}
2320+
};
2321+
using ResilientWitnessTable = TargetResilientWitnessTable<InProcess>;
2322+
22802323
/// \brief The control structure of a generic or resilient protocol
22812324
/// conformance.
22822325
///
@@ -2306,6 +2349,10 @@ struct TargetGenericWitnessTable {
23062349
/// The pattern.
23072350
RelativeDirectPointer<const TargetWitnessTable<Runtime>> Pattern;
23082351

2352+
/// The resilient witness table, if any.
2353+
RelativeDirectPointer<const TargetResilientWitnessTable<Runtime>,
2354+
/*nullable*/ true> ResilientWitnesses;
2355+
23092356
/// The instantiation function, which is called after the template is copied.
23102357
RelativeDirectPointer<void(TargetWitnessTable<Runtime> *instantiatedTable,
23112358
const TargetMetadata<Runtime> *type,

include/swift/SIL/SILDefaultWitnessTable.h

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -150,33 +150,9 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
150150
}
151151
}
152152

153-
/// Return the minimum witness table size, in words.
154-
///
155-
/// This will not change if requirements with default implementations are
156-
/// added at the end of the protocol.
157-
unsigned getMinimumWitnessTableSize() const;
158-
159-
/// Return the default witness table size, in words.
160-
///
161-
/// This is the number of resilient default entries that were known when the
162-
/// protocol definition was compiled; at runtime, it may be smaller or larger,
163-
/// so this should only be used when emitting metadata for the protocol
164-
/// definition itself.
165-
unsigned getDefaultWitnessTableSize() const {
166-
return Entries.size() - getMinimumWitnessTableSize();
167-
}
168-
169153
/// Return all of the default witness table entries.
170154
ArrayRef<Entry> getEntries() const { return Entries; }
171155

172-
/// Return all of the resilient default implementations.
173-
///
174-
/// This is the array of witnesses actually emitted as part of the protocol's
175-
/// metadata; see the comment in getMinimumWitnessTableSize().
176-
ArrayRef<Entry> getResilientDefaultEntries() {
177-
return Entries.slice(getMinimumWitnessTableSize());
178-
}
179-
180156
/// Verify that the default witness table is well-formed.
181157
void verify(const SILModule &M) const;
182158

include/swift/SIL/SILWitnessTable.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class SILModule;
3737
class ProtocolConformance;
3838
class NormalProtocolConformance;
3939
enum IsSerialized_t : unsigned char;
40-
enum class ResilienceStrategy : unsigned;
4140

4241
/// A mapping from each requirement of a protocol to the SIL-level entity
4342
/// satisfying the requirement for a concrete type.

lib/Demangling/Demangler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2087,6 +2087,10 @@ NodePointer Demangler::demangleWitness() {
20872087
return createWithChild(Node::Kind::ProtocolRequirementArray,
20882088
popProtocol());
20892089

2090+
case 'r':
2091+
return createWithChild(Node::Kind::ResilientProtocolWitnessTable,
2092+
popProtocolConformance());
2093+
20902094
case 'l': {
20912095
NodePointer Conf = popProtocolConformance();
20922096
NodePointer Type = popNode(Node::Kind::Type);

lib/Demangling/NodePrinter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ class NodePrinter {
443443
case Node::Kind::ReflectionMetadataFieldDescriptor:
444444
case Node::Kind::ReflectionMetadataAssocTypeDescriptor:
445445
case Node::Kind::ReflectionMetadataSuperclassDescriptor:
446+
case Node::Kind::ResilientProtocolWitnessTable:
446447
case Node::Kind::GenericTypeParamDecl:
447448
case Node::Kind::ThrowsAnnotation:
448449
case Node::Kind::EmptyList:
@@ -1316,6 +1317,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
13161317
Printer << "instantiation function for generic protocol witness table for ";
13171318
print(Node->getFirstChild());
13181319
return nullptr;
1320+
case Node::Kind::ResilientProtocolWitnessTable:
1321+
Printer << "resilient protocol witness table for ";
1322+
print(Node->getFirstChild());
1323+
return nullptr;
13191324
case Node::Kind::VTableThunk: {
13201325
Printer << "vtable thunk for ";
13211326
print(Node->getChild(1));

lib/Demangling/OldRemangler.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,10 @@ void Remangler::mangleGenericProtocolWitnessTable(Node *node) {
834834
mangleSingleChildNode(node); // protocol conformance
835835
}
836836

837+
void Remangler::mangleResilientProtocolWitnessTable(Node *node) {
838+
unreachable("todo");
839+
}
840+
837841
void Remangler::mangleGenericProtocolWitnessTableInstantiationFunction(
838842
Node *node) {
839843
Out << "WI";

lib/Demangling/Remangler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,11 @@ void Remangler::mangleGenericProtocolWitnessTableInstantiationFunction(Node *nod
10561056
Buffer << "WI";
10571057
}
10581058

1059+
void Remangler::mangleResilientProtocolWitnessTable(Node *node) {
1060+
mangleSingleChildNode(node);
1061+
Buffer << "Wr";
1062+
}
1063+
10591064
void Remangler::mangleGenericPartialSpecialization(Node *node) {
10601065
for (NodePointer Child : *node) {
10611066
if (Child->getKind() == Node::Kind::GenericSpecializationParam) {

0 commit comments

Comments
 (0)