mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
160 lines
5.4 KiB
C++
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);
|
|
}
|