Skip to content

Order-independent protocol witness table instantiation #15387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 30, 2018
Merged
44 changes: 25 additions & 19 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ Globals
global ::= context 'MXX' // anonymous context descriptor
global ::= context identifier 'MXY' // anonymous context descriptor
global ::= type assoc_type_path 'MXA' // generic parameter ref
global ::= nominal-type 'Mo' // class metadata immediate member base offset
global ::= protocol 'Mp' // protocol descriptor
global ::= protocol-conformance 'Mc' // protocol conformance descriptor
global ::= protocol 'WR' // protocol requirement table

global ::= nominal-type 'Mo' // class metadata immediate member base offset

global ::= type 'MF' // metadata for remote mirrors: field descriptor
global ::= type 'MB' // metadata for remote mirrors: builtin type descriptor
global ::= protocol-conformance 'MA' // metadata for remote mirrors: associated type descriptor
Expand All @@ -76,35 +78,27 @@ Globals
global ::= mangled-name 'Ta' // ObjC partial application forwarder

global ::= type 'w' VALUE-WITNESS-KIND // value witness

global ::= protocol-conformance 'Mc' // protocol conformance descriptor
global ::= protocol-conformance 'WP' // protocol witness table
global ::= protocol-conformance 'Wa' // protocol witness table accessor

global ::= protocol-conformance 'WG' // generic protocol witness table
global ::= protocol-conformance 'Wp' // protocol witness table pattern
global ::= protocol-conformance 'Wr' // resilient witness table
global ::= protocol-conformance 'WI' // generic protocol witness table instantiation function
global ::= type protocol-conformance 'WL' // lazy protocol witness table cache variable
global ::= entity 'Wo' // witness table offset
global ::= protocol-conformance 'WP' // protocol witness table

global ::= protocol-conformance identifier 'Wt' // associated type metadata accessor
global ::= protocol-conformance assoc_type_path nominal-type 'WT' // associated type witness table accessor
global ::= type protocol-conformance 'Wl' // lazy protocol witness table accessor

global ::= type 'WV' // value witness table
global ::= entity 'Wv' DIRECTNESS // field offset
global ::= entity 'WC' // resilient enum tag index

global ::= type 'Wy' // Outlined Copy Function Type
global ::= type 'We' // Outlined Consume Function Type
global ::= type 'Wr' // Outlined Retain Function Type
global ::= type 'Ws' // Outlined Release Function Type
global ::= type 'Wb' INDEX // Outlined InitializeWithTake Function Type
global ::= type 'Wc' INDEX // Outlined InitializeWithCopy Function Type
global ::= type 'Wd' INDEX // Outlined AssignWithTake Function Type
global ::= type 'Wf' INDEX // Outlined AssignWithCopy Function Type
global ::= type 'Wh' INDEX // Outlined Destroy Function Type
global ::= entity 'Wvd' // field offset
global ::= entity 'WC' // resilient enum tag index

assoc_type_path ::= identifier '_' identifier*

DIRECTNESS ::= 'd' // direct
DIRECTNESS ::= 'i' // indirect

A direct symbol resolves directly to the address of an object. An
indirect symbol resolves to the address of a pointer to the object.
They are distinct manglings to make a certain class of bugs
Expand Down Expand Up @@ -175,6 +169,18 @@ The types in a reabstraction thunk helper function are always non-polymorphic
``<VALUE-WITNESS-KIND>`` differentiates the kinds of value
witness functions for a type.

::

global ::= generic-signature? type 'WOy' // Outlined copy
global ::= generic-signature? type 'WOe' // Outlined consume
global ::= generic-signature? type 'WOr' // Outlined retain
global ::= generic-signature? type 'WOs' // Outlined release
global ::= generic-signature? type 'WOb' // Outlined initializeWithTake
global ::= generic-signature? type 'WOc' // Outlined initializeWithCopy
global ::= generic-signature? type 'WOd' // Outlined assignWithTake
global ::= generic-signature? type 'WOf' // Outlined assignWithCopy
global ::= generic-signature? type 'WOh' // Outlined destroy

Entities
~~~~~~~~

Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ NODE(GenericPartialSpecialization)
NODE(GenericPartialSpecializationNotReAbstracted)
NODE(GenericProtocolWitnessTable)
NODE(GenericProtocolWitnessTableInstantiationFunction)
NODE(ResilientProtocolWitnessTable)
NODE(GenericSpecialization)
NODE(GenericSpecializationNotReAbstracted)
NODE(GenericSpecializationParam)
Expand Down
10 changes: 10 additions & 0 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ class LinkEntity {
/// The secondary pointer is a ProtocolConformance*.
GenericProtocolWitnessTableInstantiationFunction,

/// A list of key/value pairs that resiliently specify a witness table.
ResilientProtocolWitnessTable,

/// A function which returns the type metadata for the associated type
/// of a protocol. The secondary pointer is a ProtocolConformance*.
/// The index of the associated type declaration is stored in the data.
Expand Down Expand Up @@ -641,6 +644,13 @@ class LinkEntity {
return entity;
}

static LinkEntity
forResilientProtocolWitnessTable(const ProtocolConformance *C) {
LinkEntity entity;
entity.setForProtocolConformance(Kind::ResilientProtocolWitnessTable, C);
return entity;
}

static LinkEntity
forGenericProtocolWitnessTableInstantiationFunction(
const ProtocolConformance *C) {
Expand Down
65 changes: 56 additions & 9 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -1991,14 +1991,11 @@ struct TargetProtocolDescriptor {
/// Additional flags.
ProtocolDescriptorFlags Flags;

/// The number of non-defaultable requirements in the protocol.
uint16_t NumMandatoryRequirements;

/// The number of requirements described by the Requirements array.
/// If any requirements beyond MinimumWitnessTableSizeInWords are present
/// in the witness table template, they will be not be overwritten with
/// defaults.
uint16_t NumRequirements;
uint32_t NumRequirements;

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

void *getDefaultWitness(unsigned index) const {
return Requirements.get()[index].DefaultImplementation.get();
}

// This is only used in unittests/Metadata.cpp.
constexpr TargetProtocolDescriptor<Runtime>(const char *Name,
const TargetProtocolDescriptorList<Runtime> *Inherited,
Expand All @@ -2026,7 +2019,6 @@ struct TargetProtocolDescriptor {
_ObjC_InstanceProperties(nullptr),
DescriptorSize(sizeof(TargetProtocolDescriptor<Runtime>)),
Flags(Flags),
NumMandatoryRequirements(0),
NumRequirements(0),
Requirements(nullptr),
Superclass(nullptr),
Expand Down Expand Up @@ -2277,6 +2269,57 @@ struct TargetGenericBoxHeapMetadata : public TargetBoxHeapMetadata<Runtime> {
};
using GenericBoxHeapMetadata = TargetGenericBoxHeapMetadata<InProcess>;

/// \brief The control structure of a generic or resilient protocol
/// conformance witness.
///
/// Resilient conformances must use a pattern where new requirements
/// with default implementations can be added and the order of existing
/// requirements can be changed.
///
/// This is accomplished by emitting an order-independent series of
/// relative pointer pairs, consisting of a protocol requirement together
/// with a witness. The requirement is identified by an indirect relative
/// pointer to the protocol dispatch thunk.
template <typename Runtime>
struct TargetResilientWitness {
RelativeIndirectPointer<void> Function;
RelativeDirectPointer<void> Witness;
};
using ResilientWitness = TargetResilientWitness<InProcess>;

template <typename Runtime>
struct TargetResilientWitnessTable final
: public swift::ABI::TrailingObjects<
TargetResilientWitnessTable<Runtime>,
TargetResilientWitness<Runtime>> {
uint32_t NumWitnesses;

using TrailingObjects = swift::ABI::TrailingObjects<
TargetResilientWitnessTable<Runtime>,
TargetResilientWitness<Runtime>>;
friend TrailingObjects;

template<typename T>
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;

size_t numTrailingObjects(
OverloadToken<TargetResilientWitness<Runtime>>) const {
return NumWitnesses;
}

llvm::ArrayRef<TargetResilientWitness<Runtime>>
getWitnesses() const {
return {this->template getTrailingObjects<TargetResilientWitness<Runtime>>(),
NumWitnesses};
}

const TargetResilientWitness<Runtime> &
getWitness(unsigned i) const {
return getWitnesses()[i];
}
};
using ResilientWitnessTable = TargetResilientWitnessTable<InProcess>;

/// \brief The control structure of a generic or resilient protocol
/// conformance.
///
Expand Down Expand Up @@ -2306,6 +2349,10 @@ struct TargetGenericWitnessTable {
/// The pattern.
RelativeDirectPointer<const TargetWitnessTable<Runtime>> Pattern;

/// The resilient witness table, if any.
RelativeDirectPointer<const TargetResilientWitnessTable<Runtime>,
/*nullable*/ true> ResilientWitnesses;

/// The instantiation function, which is called after the template is copied.
RelativeDirectPointer<void(TargetWitnessTable<Runtime> *instantiatedTable,
const TargetMetadata<Runtime> *type,
Expand Down
24 changes: 0 additions & 24 deletions include/swift/SIL/SILDefaultWitnessTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,33 +150,9 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
}
}

/// Return the minimum witness table size, in words.
///
/// This will not change if requirements with default implementations are
/// added at the end of the protocol.
unsigned getMinimumWitnessTableSize() const;

/// Return the default witness table size, in words.
///
/// This is the number of resilient default entries that were known when the
/// protocol definition was compiled; at runtime, it may be smaller or larger,
/// so this should only be used when emitting metadata for the protocol
/// definition itself.
unsigned getDefaultWitnessTableSize() const {
return Entries.size() - getMinimumWitnessTableSize();
}

/// Return all of the default witness table entries.
ArrayRef<Entry> getEntries() const { return Entries; }

/// Return all of the resilient default implementations.
///
/// This is the array of witnesses actually emitted as part of the protocol's
/// metadata; see the comment in getMinimumWitnessTableSize().
ArrayRef<Entry> getResilientDefaultEntries() {
return Entries.slice(getMinimumWitnessTableSize());
}

/// Verify that the default witness table is well-formed.
void verify(const SILModule &M) const;

Expand Down
1 change: 0 additions & 1 deletion include/swift/SIL/SILWitnessTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class SILModule;
class ProtocolConformance;
class NormalProtocolConformance;
enum IsSerialized_t : unsigned char;
enum class ResilienceStrategy : unsigned;

/// A mapping from each requirement of a protocol to the SIL-level entity
/// satisfying the requirement for a concrete type.
Expand Down
4 changes: 4 additions & 0 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2087,6 +2087,10 @@ NodePointer Demangler::demangleWitness() {
return createWithChild(Node::Kind::ProtocolRequirementArray,
popProtocol());

case 'r':
return createWithChild(Node::Kind::ResilientProtocolWitnessTable,
popProtocolConformance());

case 'l': {
NodePointer Conf = popProtocolConformance();
NodePointer Type = popNode(Node::Kind::Type);
Expand Down
5 changes: 5 additions & 0 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ class NodePrinter {
case Node::Kind::ReflectionMetadataFieldDescriptor:
case Node::Kind::ReflectionMetadataAssocTypeDescriptor:
case Node::Kind::ReflectionMetadataSuperclassDescriptor:
case Node::Kind::ResilientProtocolWitnessTable:
case Node::Kind::GenericTypeParamDecl:
case Node::Kind::ThrowsAnnotation:
case Node::Kind::EmptyList:
Expand Down Expand Up @@ -1316,6 +1317,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
Printer << "instantiation function for generic protocol witness table for ";
print(Node->getFirstChild());
return nullptr;
case Node::Kind::ResilientProtocolWitnessTable:
Printer << "resilient protocol witness table for ";
print(Node->getFirstChild());
return nullptr;
case Node::Kind::VTableThunk: {
Printer << "vtable thunk for ";
print(Node->getChild(1));
Expand Down
4 changes: 4 additions & 0 deletions lib/Demangling/OldRemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,10 @@ void Remangler::mangleGenericProtocolWitnessTable(Node *node) {
mangleSingleChildNode(node); // protocol conformance
}

void Remangler::mangleResilientProtocolWitnessTable(Node *node) {
unreachable("todo");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're definitively not going to support remangling these things with the old remangler, we should probably do something consistent for all them. At any rate, "todo" does not seem like the right message. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only want to remangle things that come up in a nominal type, and these new symbols are definitely not it. I'll change the todo to something else.


void Remangler::mangleGenericProtocolWitnessTableInstantiationFunction(
Node *node) {
Out << "WI";
Expand Down
5 changes: 5 additions & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,11 @@ void Remangler::mangleGenericProtocolWitnessTableInstantiationFunction(Node *nod
Buffer << "WI";
}

void Remangler::mangleResilientProtocolWitnessTable(Node *node) {
mangleSingleChildNode(node);
Buffer << "Wr";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add this to Mangling.rst. Also, I think I poked you about an earlier mangling you should've done that for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, will do.

}

void Remangler::mangleGenericPartialSpecialization(Node *node) {
for (NodePointer Child : *node) {
if (Child->getKind() == Node::Kind::GenericSpecializationParam) {
Expand Down
Loading