Files
swift-mirror/lib/SIL/SILWitnessTable.cpp
Slava Pestov bbbe307980 SIL: Introduce SILDefaultWitnessTable and start plumbing
This will be used to help IRGen record protocol requirements
with resilient default implementations in protocol metadata.

To enable testing before all the Sema support is in place, this
patch adds SIL parser, printer and verifier support for default
witness tables.

For now, SILGen emits empty default witness tables for protocol
declarations in resilient modules, and IRGen ignores them when
emitting protocol metadata.
2016-02-05 20:57:11 -08:00

160 lines
5.4 KiB
C++

//===--- SILWitnessTable.cpp - Defines the SILWitnessTable class ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the SILWitnessTable class, which is used to map a protocol
// conformance for a type to its implementing SILFunctions. This information is
// (FIXME will be) used by IRGen to create witness tables for protocol dispatch.
// It can also be used by generic specialization and existential
// devirtualization passes to promote witness_method and protocol_method
// instructions to static function_refs.
//
//===----------------------------------------------------------------------===//
#include "swift/SIL/SILWitnessTable.h"
#include "swift/AST/Mangle.h"
#include "swift/SIL/SILModule.h"
#include "llvm/ADT/SmallString.h"
using namespace swift;
static std::string mangleConstant(NormalProtocolConformance *C) {
using namespace Mangle;
Mangler mangler;
// mangled-name ::= '_T' global
// global ::= 'WP' protocol-conformance
mangler.append("_TWP");
mangler.mangleProtocolConformance(C);
return mangler.finalize();
}
void SILWitnessTable::addWitnessTable() {
// Make sure we have not seen this witness table yet.
assert(Mod.WitnessTableMap.find(Conformance) ==
Mod.WitnessTableMap.end() && "Attempting to create duplicate "
"witness table.");
Mod.WitnessTableMap[Conformance] = this;
Mod.witnessTables.push_back(this);
}
SILWitnessTable *
SILWitnessTable::create(SILModule &M, SILLinkage Linkage, bool IsFragile,
NormalProtocolConformance *Conformance,
ArrayRef<SILWitnessTable::Entry> entries) {
assert(Conformance && "Cannot create a witness table for a null "
"conformance.");
// Create the mangled name of our witness table...
Identifier Name = M.getASTContext().getIdentifier(mangleConstant(Conformance));
// Allocate the witness table and initialize it.
void *buf = M.allocate(sizeof(SILWitnessTable), alignof(SILWitnessTable));
SILWitnessTable *wt = ::new (buf) SILWitnessTable(M, Linkage, IsFragile,
Name.str(), Conformance, entries);
wt->addWitnessTable();
// Return the resulting witness table.
return wt;
}
SILWitnessTable *
SILWitnessTable::create(SILModule &M, SILLinkage Linkage,
NormalProtocolConformance *Conformance) {
assert(Conformance && "Cannot create a witness table for a null "
"conformance.");
// Create the mangled name of our witness table...
Identifier Name = M.getASTContext().getIdentifier(mangleConstant(Conformance));
// Allocate the witness table and initialize it.
void *buf = M.allocate(sizeof(SILWitnessTable), alignof(SILWitnessTable));
SILWitnessTable *wt = ::new (buf) SILWitnessTable(M, Linkage, Name.str(),
Conformance);
wt->addWitnessTable();
// Return the resulting witness table.
return wt;
}
SILWitnessTable::SILWitnessTable(SILModule &M, SILLinkage Linkage,
bool IsFragile, StringRef N,
NormalProtocolConformance *Conformance,
ArrayRef<Entry> entries)
: Mod(M), Name(N), Linkage(Linkage), Conformance(Conformance), Entries(),
IsDeclaration(true) {
convertToDefinition(entries, IsFragile);
}
SILWitnessTable::SILWitnessTable(SILModule &M, SILLinkage Linkage, StringRef N,
NormalProtocolConformance *Conformance)
: Mod(M), Name(N), Linkage(Linkage), Conformance(Conformance), Entries(),
IsDeclaration(true), IsFragile(false)
{}
SILWitnessTable::~SILWitnessTable() {
if (isDeclaration())
return;
// Drop the reference count of witness functions referenced by this table.
for (auto entry : getEntries()) {
switch (entry.getKind()) {
case Method:
if (entry.getMethodWitness().Witness) {
entry.getMethodWitness().Witness->decrementRefCount();
}
break;
case AssociatedType:
case AssociatedTypeProtocol:
case BaseProtocol:
case MissingOptional:
case Invalid:
break;
}
}
}
void SILWitnessTable::convertToDefinition(ArrayRef<Entry> entries,
bool isFragile) {
assert(isDeclaration() && "Definitions should never call this method.");
IsDeclaration = false;
IsFragile = isFragile;
void *buf = Mod.allocate(sizeof(Entry)*entries.size(), alignof(Entry));
memcpy(buf, entries.begin(), sizeof(Entry)*entries.size());
Entries = MutableArrayRef<Entry>(static_cast<Entry*>(buf), entries.size());
// Bump the reference count of witness functions referenced by this table.
for (auto entry : getEntries()) {
switch (entry.getKind()) {
case Method:
if (entry.getMethodWitness().Witness) {
entry.getMethodWitness().Witness->incrementRefCount();
}
break;
case AssociatedType:
case AssociatedTypeProtocol:
case BaseProtocol:
case MissingOptional:
case Invalid:
break;
}
}
}
Identifier SILWitnessTable::getIdentifier() const {
return Mod.getASTContext().getIdentifier(Name);
}