Skip to content

[ABI] Add default associated type witnesses to resilient protocols. #19336

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 5 commits into from
Sep 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ types where the metadata itself has unknown layout.)

global ::= protocol 'TL' // protocol requirements base descriptor
global ::= assoc-type-name 'Tl' // associated type descriptor
global ::= assoc-type-name 'TM' // default associated type witness accessor


REABSTRACT-THUNK-TYPE ::= 'R' // reabstraction thunk helper function
Expand Down
9 changes: 7 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3774,8 +3774,6 @@ struct SelfReferenceKind {
class ProtocolDecl final : public NominalTypeDecl {
SourceLoc ProtocolLoc;

llvm::DenseMap<ValueDecl *, Witness> DefaultWitnesses;

/// The generic signature representing exactly the new requirements introduced
/// by this protocol.
const Requirement *RequirementSignature = nullptr;
Expand Down Expand Up @@ -3967,6 +3965,13 @@ class ProtocolDecl final : public NominalTypeDecl {
Bits.ProtocolDecl.HasMissingRequirements = newValue;
}

/// Returns the default type witness for an associated type, or a null
/// type if there is no default.
Type getDefaultTypeWitness(AssociatedTypeDecl *assocType) const;

/// Set the default type witness for an associated type.
void setDefaultTypeWitness(AssociatedTypeDecl *assocType, Type witness);

/// Returns the default witness for a requirement, or nullptr if there is
/// no default.
Witness getDefaultWitness(ValueDecl *requirement) const;
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 @@ -30,6 +30,7 @@ NODE(ArgumentTuple)
NODE(AssociatedType)
NODE(AssociatedTypeRef)
NODE(AssociatedTypeMetadataAccessor)
NODE(DefaultAssociatedTypeMetadataAccessor)
NODE(AssociatedTypeWitnessTableAccessor)
NODE(AutoClosureType)
NODE(BoundGenericClass)
Expand Down
18 changes: 16 additions & 2 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ class LinkEntity {
/// The pointer is an AssociatedTypeDecl*.
AssociatedTypeDescriptor,

/// A function which returns the default type metadata for the associated
/// type of a protocol. The secondary pointer is a ProtocolDecl*.
/// The index of the associated type declaration is stored in the data.
DefaultAssociatedTypeMetadataAccessFunction,

/// A SIL function. The pointer is a SILFunction*.
SILFunction,

Expand Down Expand Up @@ -319,7 +324,7 @@ class LinkEntity {
}

static bool isDeclKind(Kind k) {
return k <= Kind::AssociatedTypeDescriptor;
return k <= Kind::DefaultAssociatedTypeMetadataAccessFunction;
}
static bool isTypeKind(Kind k) {
return k >= Kind::ProtocolWitnessTableLazyAccessFunction;
Expand Down Expand Up @@ -763,6 +768,14 @@ class LinkEntity {
return entity;
}

static LinkEntity
forDefaultAssociatedTypeMetadataAccessFunction(AssociatedType association) {
LinkEntity entity;
entity.setForDecl(Kind::DefaultAssociatedTypeMetadataAccessFunction,
association.getAssociation());
return entity;
}

static LinkEntity
forAssociatedTypeWitnessTableAccessFunction(const ProtocolConformance *C,
const AssociatedConformance &association) {
Expand Down Expand Up @@ -853,7 +866,8 @@ class LinkEntity {
return getAssociatedTypeByIndex(getProtocolConformance(),
LINKENTITY_GET_FIELD(Data, AssociatedTypeIndex));

assert(getKind() == Kind::AssociatedTypeDescriptor);
assert(getKind() == Kind::AssociatedTypeDescriptor ||
getKind() == Kind::DefaultAssociatedTypeMetadataAccessFunction);
return reinterpret_cast<AssociatedTypeDecl *>(Pointer);
}

Expand Down
43 changes: 8 additions & 35 deletions include/swift/SIL/SILDefaultWitnessTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "swift/SIL/SILAllocated.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILWitnessTable.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/ilist.h"
#include <string>
Expand All @@ -41,40 +42,9 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
public SILAllocated<SILDefaultWitnessTable>
{
public:
/// A default witness table entry describing the default witness for a method.
class Entry {
/// The method required.
SILDeclRef Requirement;
/// The witness for the method.
/// This can be null in case no default implementation is available.
SILFunction *Witness;

public:
Entry()
: Requirement(), Witness(nullptr) {}

Entry(SILDeclRef Requirement, SILFunction *Witness)
: Requirement(Requirement), Witness(Witness) {}

bool isValid() const {
return !Requirement.isNull() && Witness;
}

const SILDeclRef &getRequirement() const {
assert(isValid());
return Requirement;
}
SILFunction *getWitness() const {
assert(Witness != nullptr);
return Witness;
}
void removeWitnessMethod() {
if (Witness) {
Witness->decrementRefCount();
}
Witness = nullptr;
}
};
/// A default witness table entry describing the default witness for a
/// requirement.
using Entry = SILWitnessTable::Entry;

private:
/// The module which contains the SILDefaultWitnessTable.
Expand Down Expand Up @@ -147,7 +117,10 @@ class SILDefaultWitnessTable : public llvm::ilist_node<SILDefaultWitnessTable>,
for (Entry &entry : Entries) {
if (!entry.isValid())
continue;
auto *MW = entry.getWitness();
if (entry.getKind() != SILWitnessTable::Method)
continue;

auto *MW = entry.getMethodWitness().Witness;
if (MW && predicate(MW)) {
entry.removeWitnessMethod();
}
Expand Down
7 changes: 6 additions & 1 deletion include/swift/SIL/SILWitnessTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
{}

WitnessKind getKind() const { return Kind; }


bool isValid() const { return Kind != WitnessKind::Invalid; }

const MethodWitness &getMethodWitness() const {
assert(Kind == WitnessKind::Method);
return Method;
Expand All @@ -150,6 +152,9 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
}
Method.Witness = nullptr;
}

void print(llvm::raw_ostream &out, bool verbose,
const PrintOptions &options) const;
};

/// An entry for a conformance requirement that makes the requirement
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t VERSION_MINOR = 445; // Last change: generic typealias
const uint16_t VERSION_MINOR = 446; // Last change: sil default witness table

using DeclIDField = BCFixed<31>;

Expand Down
53 changes: 53 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ FOR_KNOWN_FOUNDATION_TYPES(CACHE_FOUNDATION_DECL)
/// Overridden declarations.
llvm::DenseMap<const ValueDecl *, ArrayRef<ValueDecl *>> Overrides;

/// Default witnesses.
llvm::DenseMap<std::pair<const ProtocolDecl *, ValueDecl *>, Witness>
DefaultWitnesses;

/// Default type witnesses for protocols.
llvm::DenseMap<std::pair<const ProtocolDecl *, AssociatedTypeDecl *>, Type>
DefaultTypeWitnesses;

/// \brief Structure that captures data that is segregated into different
/// arenas.
struct Arena {
Expand Down Expand Up @@ -1656,6 +1664,51 @@ void OverriddenDeclsRequest::cacheResult(
(void)ctx.getImpl().Overrides.insert({decl, overriddenCopy});
}

/// Returns the default witness for a requirement, or nullptr if there is
/// no default.
Witness ProtocolDecl::getDefaultWitness(ValueDecl *requirement) const {
loadAllMembers();

ASTContext &ctx = getASTContext();
auto found = ctx.getImpl().DefaultWitnesses.find({this, requirement});
if (found == ctx.getImpl().DefaultWitnesses.end())
return Witness();
return found->second;
}

/// Record the default witness for a requirement.
void ProtocolDecl::setDefaultWitness(ValueDecl *requirement, Witness witness) {
assert(witness);
ASTContext &ctx = getASTContext();
auto pair = ctx.getImpl().DefaultWitnesses.insert(
std::make_pair(std::make_pair(this, requirement), witness));
assert(pair.second && "Already have a default witness!");
(void) pair;
}

/// Returns the default type witness for an associated type, or a null
/// type if there is no default.
Type ProtocolDecl::getDefaultTypeWitness(AssociatedTypeDecl *assocType) const {
auto &ctx = getASTContext();
auto found = ctx.getImpl().DefaultTypeWitnesses.find({this, assocType});
if (found == ctx.getImpl().DefaultTypeWitnesses.end())
return Type();

return found->second;
}

/// Set the default type witness for an associated type.
void ProtocolDecl::setDefaultTypeWitness(AssociatedTypeDecl *assocType,
Type witness) {
assert(witness);
assert(!witness->hasArchetype() && "Only record interface types");
ASTContext &ctx = getASTContext();
auto pair = ctx.getImpl().DefaultTypeWitnesses.insert(
std::make_pair(std::make_pair(this, assocType), witness));
assert(pair.second && "Already have a default witness");
(void)pair;
}

bool ASTContext::canImportModule(std::pair<Identifier, SourceLoc> ModulePath) {
// If this module has already been successfully imported, it is importable.
if (getLoadedModule(ModulePath) != nullptr)
Expand Down
23 changes: 0 additions & 23 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4050,29 +4050,6 @@ void ProtocolDecl::setRequirementSignature(ArrayRef<Requirement> requirements) {
}
}

/// Returns the default witness for a requirement, or nullptr if there is
/// no default.
Witness ProtocolDecl::getDefaultWitness(ValueDecl *requirement) const {
loadAllMembers();

auto found = DefaultWitnesses.find(requirement);
if (found == DefaultWitnesses.end())
return Witness();
return found->second;
}

/// Record the default witness for a requirement.
void ProtocolDecl::setDefaultWitness(ValueDecl *requirement, Witness witness) {
assert(witness);
// The first type we insert a default witness, register a destructor for
// this type.
if (DefaultWitnesses.empty())
getASTContext().addDestructorCleanup(DefaultWitnesses);
auto pair = DefaultWitnesses.insert(std::make_pair(requirement, witness));
assert(pair.second && "Already have a default witness!");
(void) pair;
}

void AbstractStorageDecl::overwriteImplInfo(StorageImplInfo implInfo) {
setFieldsFromImplInfo(implInfo);
Accessors.getPointer()->overwriteImplInfo(implInfo);
Expand Down
3 changes: 3 additions & 0 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1823,6 +1823,9 @@ NodePointer Demangler::demangleThunkOrSpecialization() {
case 'L':
return createWithChild(Node::Kind::ProtocolRequirementsBaseDescriptor,
popProtocol());
case 'M':
return createWithChild(Node::Kind::DefaultAssociatedTypeMetadataAccessor,
popAssocTypeName());

case 'H':
case 'h': {
Expand Down
5 changes: 5 additions & 0 deletions lib/Demangling/NodePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ class NodePrinter {
case Node::Kind::Deallocator:
case Node::Kind::DeclContext:
case Node::Kind::DefaultArgumentInitializer:
case Node::Kind::DefaultAssociatedTypeMetadataAccessor:
case Node::Kind::DependentAssociatedTypeRef:
case Node::Kind::DependentGenericSignature:
case Node::Kind::DependentGenericParamCount:
Expand Down Expand Up @@ -1564,6 +1565,10 @@ NodePointer NodePrinter::print(NodePointer Node, bool asPrefixContext) {
Printer << " in ";
print(Node->getChild(0));
return nullptr;
case Node::Kind::DefaultAssociatedTypeMetadataAccessor:
Printer << "default associated type metadata accessor for ";
print(Node->getChild(0));
return nullptr;
case Node::Kind::AssociatedTypeWitnessTableAccessor:
Printer << "associated type witness table accessor 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 @@ -889,6 +889,10 @@ void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
mangleChildNodes(node); // protocol conformance, identifier
}

void Remangler::mangleDefaultAssociatedTypeMetadataAccessor(Node *node) {
Out << "<default-associated-type-metadata-accessor>";
}

void Remangler::mangleAssociatedTypeWitnessTableAccessor(Node *node) {
Out << "WT";
assert(node->getNumChildren() == 3);
Expand Down
5 changes: 5 additions & 0 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,11 @@ void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
Buffer << "Wt";
}

void Remangler::mangleDefaultAssociatedTypeMetadataAccessor(Node *node) {
mangleChildNodes(node); // protocol conformance, identifier
Buffer << "TM";
}

void Remangler::mangleAssociatedTypeWitnessTableAccessor(Node *node) {
mangleChildNodes(node); // protocol conformance, identifier, type
Buffer << "WT";
Expand Down
19 changes: 19 additions & 0 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3949,6 +3949,25 @@ IRGenModule::getAddrOfAssociatedTypeWitnessTableAccessFunction(
return entry;
}

llvm::Function *
IRGenModule::getAddrOfDefaultAssociatedTypeMetadataAccessFunction(
AssociatedType association) {
auto forDefinition = ForDefinition;

LinkEntity entity =
LinkEntity::forDefaultAssociatedTypeMetadataAccessFunction(association);
llvm::Function *&entry = GlobalFuncs[entity];
if (entry) {
if (forDefinition) updateLinkageForDefinition(*this, entry, entity);
return entry;
}

auto signature = getAssociatedTypeMetadataAccessFunctionSignature();
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
entry = createFunction(*this, link, signature);
return entry;
}

llvm::Function *
IRGenModule::getAddrOfContinuationPrototype(CanSILFunctionType fnType) {
LinkEntity entity = LinkEntity::forCoroutineContinuationPrototype(fnType);
Expand Down
Loading