mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This reinstates commit 4187959e66.
It was reverted because of a bug in ValueLifetimeAnalysis which is now fixed.
702 lines
24 KiB
C++
702 lines
24 KiB
C++
//===--- SILModule.cpp - SILModule implementation -------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "sil-module"
|
|
#include "swift/Serialization/SerializedSILLoader.h"
|
|
#include "swift/SIL/SILDebugScope.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
#include "Linker.h"
|
|
#include "swift/SIL/SILVisitor.h"
|
|
#include "swift/SIL/SILValue.h"
|
|
#include "llvm/ADT/FoldingSet.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include <functional>
|
|
using namespace swift;
|
|
using namespace Lowering;
|
|
|
|
class SILModule::SerializationCallback : public SerializedSILLoader::Callback {
|
|
void didDeserialize(Module *M, SILFunction *fn) override {
|
|
updateLinkage(fn);
|
|
}
|
|
|
|
void didDeserialize(Module *M, SILGlobalVariable *var) override {
|
|
updateLinkage(var);
|
|
|
|
// For globals we currently do not support available_externally.
|
|
// In the interpreter it would result in two instances for a single global:
|
|
// one in the imported module and one in the main module.
|
|
var->setDeclaration(true);
|
|
}
|
|
|
|
void didDeserialize(Module *M, SILVTable *vtable) override {
|
|
// TODO: should vtables get linkage?
|
|
//updateLinkage(vtable);
|
|
}
|
|
|
|
void didDeserialize(Module *M, SILWitnessTable *wt) override {
|
|
updateLinkage(wt);
|
|
}
|
|
|
|
template <class T> void updateLinkage(T *decl) {
|
|
switch (decl->getLinkage()) {
|
|
case SILLinkage::Public:
|
|
decl->setLinkage(SILLinkage::PublicExternal);
|
|
return;
|
|
case SILLinkage::Hidden:
|
|
decl->setLinkage(SILLinkage::HiddenExternal);
|
|
return;
|
|
case SILLinkage::Shared:
|
|
decl->setLinkage(SILLinkage::SharedExternal);
|
|
return;
|
|
case SILLinkage::Private:
|
|
decl->setLinkage(SILLinkage::PrivateExternal);
|
|
return;
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::HiddenExternal:
|
|
case SILLinkage::SharedExternal:
|
|
case SILLinkage::PrivateExternal:
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
SILModule::SILModule(Module *SwiftModule, SILOptions &Options,
|
|
const DeclContext *associatedDC,
|
|
bool wholeModule)
|
|
: TheSwiftModule(SwiftModule), AssociatedDeclContext(associatedDC),
|
|
Stage(SILStage::Raw), Callback(new SILModule::SerializationCallback()),
|
|
wholeModule(wholeModule), Options(Options), Types(*this) {
|
|
}
|
|
|
|
SILModule::~SILModule() {
|
|
// Decrement ref count for each SILGlobalVariable with static initializers.
|
|
for (SILGlobalVariable &v : silGlobals)
|
|
if (v.getInitializer())
|
|
v.getInitializer()->decrementRefCount();
|
|
|
|
// Drop everything functions in this module reference.
|
|
//
|
|
// This is necessary since the functions may reference each other. We don't
|
|
// need to worry about sil_witness_tables since witness tables reference each
|
|
// other via protocol conformances and sil_vtables don't reference each other
|
|
// at all.
|
|
for (SILFunction &F : *this)
|
|
F.dropAllReferences();
|
|
}
|
|
|
|
void *SILModule::allocate(unsigned Size, unsigned Align) const {
|
|
if (getASTContext().LangOpts.UseMalloc)
|
|
return AlignedAlloc(Size, Align);
|
|
|
|
return BPA.Allocate(Size, Align);
|
|
}
|
|
|
|
void *SILModule::allocateInst(unsigned Size, unsigned Align) const {
|
|
return AlignedAlloc(Size, Align);
|
|
}
|
|
|
|
void SILModule::deallocateInst(SILInstruction *I) {
|
|
AlignedFree(I);
|
|
}
|
|
|
|
SILWitnessTable *
|
|
SILModule::createWitnessTableDeclaration(ProtocolConformance *C,
|
|
SILLinkage linkage) {
|
|
// If we are passed in a null conformance (a valid value), just return nullptr
|
|
// since we cannot map a witness table to it.
|
|
if (!C)
|
|
return nullptr;
|
|
|
|
// Extract the base NormalProtocolConformance.
|
|
NormalProtocolConformance *NormalC = C->getRootNormalConformance();
|
|
|
|
return SILWitnessTable::create(*this, linkage, NormalC);
|
|
}
|
|
|
|
SILWitnessTable *
|
|
SILModule::lookUpWitnessTable(ProtocolConformanceRef C, bool deserializeLazily){
|
|
// If we have an abstract conformance passed in (a legal value), just return
|
|
// nullptr.
|
|
if (!C.isConcrete())
|
|
return nullptr;
|
|
|
|
return lookUpWitnessTable(C.getConcrete());
|
|
}
|
|
|
|
SILWitnessTable *
|
|
SILModule::lookUpWitnessTable(const ProtocolConformance *C,
|
|
bool deserializeLazily) {
|
|
assert(C && "null conformance passed to lookUpWitnessTable");
|
|
|
|
const NormalProtocolConformance *NormalC = C->getRootNormalConformance();
|
|
// Attempt to lookup the witness table from the table.
|
|
auto found = WitnessTableMap.find(NormalC);
|
|
if (found == WitnessTableMap.end()) {
|
|
#ifndef NDEBUG
|
|
// Make sure that all witness tables are in the witness table lookup
|
|
// cache.
|
|
//
|
|
// This code should not be hit normally since we add witness tables to the
|
|
// lookup cache when we create them. We don't just assert here since there
|
|
// is the potential for a conformance without a witness table to be passed
|
|
// to this function.
|
|
for (SILWitnessTable &WT : witnessTables)
|
|
assert(WT.getConformance() != NormalC &&
|
|
"Found witness table that is not"
|
|
" in the witness table lookup cache.");
|
|
#endif
|
|
return nullptr;
|
|
}
|
|
|
|
SILWitnessTable *wT = found->second;
|
|
assert(wT != nullptr && "Should never map a conformance to a null witness"
|
|
" table.");
|
|
|
|
// If we have a definition, return it.
|
|
if (wT->isDefinition())
|
|
return wT;
|
|
|
|
// Otherwise try to deserialize it. If we succeed return the deserialized
|
|
// function.
|
|
//
|
|
// *NOTE* In practice, wT will be deserializedTable, but I do not want to rely
|
|
// on that behavior for now.
|
|
if (deserializeLazily)
|
|
if (auto deserializedTable = getSILLoader()->lookupWitnessTable(wT))
|
|
return deserializedTable;
|
|
|
|
// If we fail, just return the declaration.
|
|
return wT;
|
|
}
|
|
|
|
SILDefaultWitnessTable *
|
|
SILModule::lookUpDefaultWitnessTable(const ProtocolDecl *Protocol) {
|
|
// Note: we only ever look up default witness tables in the translation unit
|
|
// that is currently being compiled, since they SILGen generates them when it
|
|
// visits the protocol declaration, and IRGen emits them when emitting the
|
|
// protocol descriptor metadata for the protocol.
|
|
|
|
auto found = DefaultWitnessTableMap.find(Protocol);
|
|
if (found == DefaultWitnessTableMap.end()) {
|
|
assert(Protocol->hasFixedLayout() &&
|
|
"Resilient protocol must have a default witness table");
|
|
return nullptr;
|
|
}
|
|
|
|
assert(!Protocol->hasFixedLayout() &&
|
|
"Fixed-layout protocol cannot have a default witness table");
|
|
|
|
return found->second;
|
|
}
|
|
|
|
SILDefaultWitnessTable *
|
|
SILModule::createDefaultWitnessTableDeclaration(const ProtocolDecl *Protocol) {
|
|
assert(!Protocol->hasFixedLayout() &&
|
|
"Fixed-layout protocol cannot have a default witness table");
|
|
|
|
return SILDefaultWitnessTable::create(*this, Protocol);
|
|
}
|
|
|
|
SILFunction *SILModule::getOrCreateFunction(SILLocation loc,
|
|
StringRef name,
|
|
SILLinkage linkage,
|
|
CanSILFunctionType type,
|
|
IsBare_t isBareSILFunction,
|
|
IsTransparent_t isTransparent,
|
|
IsFragile_t isFragile,
|
|
IsThunk_t isThunk,
|
|
SILFunction::ClassVisibility_t CV) {
|
|
if (auto fn = lookUpFunction(name)) {
|
|
assert(fn->getLoweredFunctionType() == type);
|
|
assert(fn->getLinkage() == linkage ||
|
|
stripExternalFromLinkage(fn->getLinkage()) == linkage);
|
|
return fn;
|
|
}
|
|
|
|
auto fn = SILFunction::create(*this, linkage, name, type, nullptr,
|
|
loc, isBareSILFunction, isTransparent,
|
|
isFragile, isThunk, CV);
|
|
fn->setDebugScope(new (*this) SILDebugScope(loc, fn));
|
|
return fn;
|
|
}
|
|
|
|
static SILFunction::ClassVisibility_t getClassVisibility(SILDeclRef constant) {
|
|
if (!constant.hasDecl())
|
|
return SILFunction::NotRelevant;
|
|
|
|
// If this declaration is a function which goes into a vtable, then it's
|
|
// symbol must be as visible as its class. Derived classes even have to put
|
|
// all less visible methods of the base class into their vtables.
|
|
|
|
auto *FD = dyn_cast<AbstractFunctionDecl>(constant.getDecl());
|
|
if (!FD)
|
|
return SILFunction::NotRelevant;
|
|
|
|
DeclContext *context = FD->getDeclContext();
|
|
|
|
// Methods from extensions don't go into vtables (yet).
|
|
if (context->isExtensionContext())
|
|
return SILFunction::NotRelevant;
|
|
|
|
auto *classType = context->getAsClassOrClassExtensionContext();
|
|
if (!classType || classType->isFinal())
|
|
return SILFunction::NotRelevant;
|
|
|
|
if (FD->isFinal() && !FD->getOverriddenDecl())
|
|
return SILFunction::NotRelevant;
|
|
|
|
assert(FD->getEffectiveAccess() <= classType->getEffectiveAccess() &&
|
|
"class must be as visible as its members");
|
|
|
|
switch (classType->getEffectiveAccess()) {
|
|
case Accessibility::Private:
|
|
return SILFunction::NotRelevant;
|
|
case Accessibility::Internal:
|
|
return SILFunction::InternalClass;
|
|
case Accessibility::Public:
|
|
return SILFunction::PublicClass;
|
|
}
|
|
}
|
|
|
|
static bool verifySILSelfParameterType(SILDeclRef DeclRef,
|
|
SILFunction *F, CanSILFunctionType FTy) {
|
|
SILModule &M = F->getModule();
|
|
SILParameterInfo PInfo = FTy->getSelfParameter();
|
|
CanType CTy = PInfo.getType();
|
|
SILType Ty = SILType::getPrimitiveObjectType(CTy);
|
|
|
|
// We do not care about trivial parameters (for now). There seem to be
|
|
// cases where we lower them as unowned.
|
|
//
|
|
// *NOTE* We do not run this check when we have a generic type since
|
|
// *generic types do not have type lowering and are always treated as
|
|
// *non-trivial since we do not know the type.
|
|
if (CTy->hasArchetype() || CTy->hasTypeParameter() ||
|
|
M.getTypeLowering(Ty).isTrivial())
|
|
return true;
|
|
|
|
// If this function is a constructor or destructor, bail. These have @owned
|
|
// parameters.
|
|
if (DeclRef.isConstructor() || DeclRef.isDestructor())
|
|
return true;
|
|
|
|
// Otherwise, if this function type has a guaranteed self parameter type,
|
|
// make sure that we have a +0 self param.
|
|
return !FTy->getExtInfo().hasGuaranteedSelfParam() ||
|
|
PInfo.isGuaranteed() || PInfo.isIndirectMutating();
|
|
}
|
|
|
|
SILFunction *SILModule::getOrCreateFunction(SILLocation loc,
|
|
SILDeclRef constant,
|
|
ForDefinition_t forDefinition) {
|
|
|
|
auto name = constant.mangle();
|
|
auto constantType = Types.getConstantType(constant).castTo<SILFunctionType>();
|
|
SILLinkage linkage = constant.getLinkage(forDefinition);
|
|
|
|
if (auto fn = lookUpFunction(name)) {
|
|
assert(fn->getLoweredFunctionType() == constantType);
|
|
assert(fn->getLinkage() == linkage);
|
|
if (forDefinition) {
|
|
// In all the cases where getConstantLinkage returns something
|
|
// different for ForDefinition, it returns an available-externally
|
|
// linkage.
|
|
if (isAvailableExternally(fn->getLinkage())) {
|
|
fn->setLinkage(constant.getLinkage(ForDefinition));
|
|
}
|
|
}
|
|
return fn;
|
|
}
|
|
|
|
IsTransparent_t IsTrans = constant.isTransparent()?
|
|
IsTransparent : IsNotTransparent;
|
|
IsFragile_t IsFrag = IsNotFragile;
|
|
if (IsTrans == IsTransparent && (linkage == SILLinkage::Public
|
|
|| linkage == SILLinkage::PublicExternal)) {
|
|
IsFrag = IsFragile;
|
|
}
|
|
|
|
EffectsKind EK = constant.hasEffectsAttribute() ?
|
|
constant.getEffectsAttribute() : EffectsKind::Unspecified;
|
|
|
|
Inline_t inlineStrategy = InlineDefault;
|
|
if (constant.isNoinline())
|
|
inlineStrategy = NoInline;
|
|
else if (constant.isAlwaysInline())
|
|
inlineStrategy = AlwaysInline;
|
|
|
|
auto *F = SILFunction::create(*this, linkage, name,
|
|
constantType, nullptr,
|
|
None, IsNotBare, IsTrans, IsFrag, IsNotThunk,
|
|
getClassVisibility(constant),
|
|
inlineStrategy, EK);
|
|
|
|
if (forDefinition == ForDefinition_t::ForDefinition)
|
|
F->setDebugScope(new (*this) SILDebugScope(loc, F));
|
|
|
|
F->setGlobalInit(constant.isGlobal());
|
|
if (constant.hasDecl()) {
|
|
if (constant.isForeign && constant.isClangGenerated())
|
|
F->setForeignBody(HasForeignBody);
|
|
|
|
auto Attrs = constant.getDecl()->getAttrs();
|
|
for (auto A : Attrs.getAttributes<SemanticsAttr, false /*AllowInvalid*/>())
|
|
F->addSemanticsAttr(cast<SemanticsAttr>(A)->Value);
|
|
}
|
|
|
|
F->setDeclContext(constant.hasDecl() ? constant.getDecl() : nullptr);
|
|
|
|
// If this function has a self parameter, make sure that it has a +0 calling
|
|
// convention. This cannot be done for general function types, since
|
|
// function_ref's SILFunctionTypes do not have archetypes associated with
|
|
// it.
|
|
CanSILFunctionType FTy = F->getLoweredFunctionType();
|
|
if (FTy->hasSelfParam()) {
|
|
(void)verifySILSelfParameterType;
|
|
assert(verifySILSelfParameterType(constant, F, FTy) &&
|
|
"Invalid signature for SIL Self parameter type");
|
|
}
|
|
|
|
|
|
return F;
|
|
}
|
|
|
|
|
|
SILFunction *SILModule::getOrCreateSharedFunction(SILLocation loc,
|
|
StringRef name,
|
|
CanSILFunctionType type,
|
|
IsBare_t isBareSILFunction,
|
|
IsTransparent_t isTransparent,
|
|
IsFragile_t isFragile,
|
|
IsThunk_t isThunk) {
|
|
return getOrCreateFunction(loc, name, SILLinkage::Shared,
|
|
type, isBareSILFunction, isTransparent, isFragile,
|
|
isThunk, SILFunction::NotRelevant);
|
|
}
|
|
|
|
SILFunction *SILModule::getOrCreateFunction(
|
|
SILLinkage linkage, StringRef name, CanSILFunctionType loweredType,
|
|
GenericParamList *contextGenericParams, Optional<SILLocation> loc,
|
|
IsBare_t isBareSILFunction, IsTransparent_t isTrans, IsFragile_t isFragile,
|
|
IsThunk_t isThunk, SILFunction::ClassVisibility_t classVisibility,
|
|
Inline_t inlineStrategy, EffectsKind EK, SILFunction *InsertBefore,
|
|
const SILDebugScope *DebugScope, DeclContext *DC) {
|
|
return SILFunction::create(*this, linkage, name, loweredType,
|
|
contextGenericParams, loc, isBareSILFunction,
|
|
isTrans, isFragile, isThunk, classVisibility,
|
|
inlineStrategy, EK, InsertBefore, DebugScope, DC);
|
|
}
|
|
|
|
const IntrinsicInfo &SILModule::getIntrinsicInfo(Identifier ID) {
|
|
unsigned OldSize = IntrinsicIDCache.size();
|
|
IntrinsicInfo &Info = IntrinsicIDCache[ID];
|
|
|
|
// If the element was is in the cache, return it.
|
|
if (OldSize == IntrinsicIDCache.size())
|
|
return Info;
|
|
|
|
// Otherwise, lookup the ID and Type and store them in the map.
|
|
StringRef NameRef = getBuiltinBaseName(getASTContext(), ID.str(), Info.Types);
|
|
Info.ID =
|
|
(llvm::Intrinsic::ID)getLLVMIntrinsicID(NameRef, !Info.Types.empty());
|
|
|
|
return Info;
|
|
}
|
|
|
|
const BuiltinInfo &SILModule::getBuiltinInfo(Identifier ID) {
|
|
unsigned OldSize = BuiltinIDCache.size();
|
|
BuiltinInfo &Info = BuiltinIDCache[ID];
|
|
|
|
// If the element was is in the cache, return it.
|
|
if (OldSize == BuiltinIDCache.size())
|
|
return Info;
|
|
|
|
// Otherwise, lookup the ID and Type and store them in the map.
|
|
// Find the matching ID.
|
|
StringRef OperationName =
|
|
getBuiltinBaseName(getASTContext(), ID.str(), Info.Types);
|
|
|
|
// Several operation names have suffixes and don't match the name from
|
|
// Builtins.def, so handle those first.
|
|
if (OperationName.startswith("fence_"))
|
|
Info.ID = BuiltinValueKind::Fence;
|
|
else if (OperationName.startswith("cmpxchg_"))
|
|
Info.ID = BuiltinValueKind::CmpXChg;
|
|
else if (OperationName.startswith("atomicrmw_"))
|
|
Info.ID = BuiltinValueKind::AtomicRMW;
|
|
else if (OperationName.startswith("atomicload_"))
|
|
Info.ID = BuiltinValueKind::AtomicLoad;
|
|
else if (OperationName.startswith("atomicstore_"))
|
|
Info.ID = BuiltinValueKind::AtomicStore;
|
|
else {
|
|
// Switch through the rest of builtins.
|
|
Info.ID = llvm::StringSwitch<BuiltinValueKind>(OperationName)
|
|
#define BUILTIN(ID, Name, Attrs) \
|
|
.Case(Name, BuiltinValueKind::ID)
|
|
#include "swift/AST/Builtins.def"
|
|
.Default(BuiltinValueKind::None);
|
|
}
|
|
|
|
return Info;
|
|
}
|
|
|
|
SILFunction *SILModule::lookUpFunction(SILDeclRef fnRef) {
|
|
auto name = fnRef.mangle();
|
|
return lookUpFunction(name);
|
|
}
|
|
|
|
bool SILModule::linkFunction(SILFunction *Fun, SILModule::LinkingMode Mode) {
|
|
return SILLinkerVisitor(*this, getSILLoader(), Mode).processFunction(Fun);
|
|
}
|
|
|
|
bool SILModule::linkFunction(SILDeclRef Decl, SILModule::LinkingMode Mode) {
|
|
return SILLinkerVisitor(*this, getSILLoader(), Mode).processDeclRef(Decl);
|
|
}
|
|
|
|
bool SILModule::linkFunction(StringRef Name, SILModule::LinkingMode Mode) {
|
|
return SILLinkerVisitor(*this, getSILLoader(), Mode).processFunction(Name);
|
|
}
|
|
|
|
SILFunction *SILModule::hasFunction(StringRef Name, SILLinkage Linkage) {
|
|
assert(!lookUpFunction(Name) && "hasFunction should be only called for "
|
|
"functions that are not contained in the "
|
|
"SILModule yet");
|
|
return SILLinkerVisitor(*this, getSILLoader(),
|
|
SILModule::LinkingMode::LinkNormal)
|
|
.lookupFunction(Name, Linkage);
|
|
}
|
|
|
|
void SILModule::linkAllWitnessTables() {
|
|
getSILLoader()->getAllWitnessTables();
|
|
}
|
|
|
|
void SILModule::linkAllVTables() {
|
|
getSILLoader()->getAllVTables();
|
|
}
|
|
|
|
void SILModule::invalidateSILLoaderCaches() {
|
|
getSILLoader()->invalidateCaches();
|
|
}
|
|
|
|
void SILModule::removeFromZombieList(StringRef Name) {
|
|
if (auto *Zombie = ZombieFunctionTable.lookup(Name)) {
|
|
ZombieFunctionTable.erase(Name);
|
|
zombieFunctions.remove(Zombie);
|
|
}
|
|
}
|
|
|
|
/// Erase a function from the module.
|
|
void SILModule::eraseFunction(SILFunction *F) {
|
|
|
|
assert(! F->isZombie() && "zombie function is in list of alive functions");
|
|
if (F->isInlined() || F->isExternallyUsedSymbol()) {
|
|
|
|
// The owner of the function's Name is the FunctionTable key. As we remove
|
|
// the function from the table we have to store the name string elsewhere:
|
|
// in zombieFunctionNames.
|
|
StringRef copiedName = F->getName().copy(zombieFunctionNames);
|
|
FunctionTable.erase(F->getName());
|
|
F->Name = copiedName;
|
|
|
|
// The function is dead, but we need it later (at IRGen) for debug info
|
|
// or vtable stub generation. So we move it into the zombie list.
|
|
getFunctionList().remove(F);
|
|
zombieFunctions.push_back(F);
|
|
ZombieFunctionTable[copiedName] = F;
|
|
F->setZombie();
|
|
|
|
// This opens dead-function-removal opportunities for called functions.
|
|
// (References are not needed anymore.)
|
|
F->dropAllReferences();
|
|
} else {
|
|
FunctionTable.erase(F->getName());
|
|
getFunctionList().erase(F);
|
|
}
|
|
}
|
|
|
|
void SILModule::invalidateFunctionInSILCache(SILFunction *F) {
|
|
getSILLoader()->invalidateFunction(F);
|
|
}
|
|
|
|
/// Erase a global SIL variable from the module.
|
|
void SILModule::eraseGlobalVariable(SILGlobalVariable *G) {
|
|
GlobalVariableMap.erase(G->getName());
|
|
getSILGlobalList().erase(G);
|
|
}
|
|
|
|
SILVTable *SILModule::lookUpVTable(const ClassDecl *C) {
|
|
if (!C)
|
|
return nullptr;
|
|
|
|
// First try to look up R from the lookup table.
|
|
auto R = VTableMap.find(C);
|
|
if (R != VTableMap.end())
|
|
return R->second;
|
|
|
|
// If that fails, try to deserialize it. If that fails, return nullptr.
|
|
SILVTable *Vtbl =
|
|
SILLinkerVisitor(*this, getSILLoader(), SILModule::LinkingMode::LinkAll)
|
|
.processClassDecl(C);
|
|
if (!Vtbl)
|
|
return nullptr;
|
|
|
|
// If we succeeded, map C -> VTbl in the table and return VTbl.
|
|
VTableMap[C] = Vtbl;
|
|
return Vtbl;
|
|
}
|
|
|
|
SerializedSILLoader *SILModule::getSILLoader() {
|
|
// If the SILLoader is null, create it.
|
|
if (!SILLoader)
|
|
SILLoader = SerializedSILLoader::create(getASTContext(), this,
|
|
Callback.get());
|
|
// Return the SerializedSILLoader.
|
|
return SILLoader.get();
|
|
}
|
|
|
|
static ArrayRef<Substitution>
|
|
getSubstitutionsForProtocolConformance(ProtocolConformanceRef CRef) {
|
|
if (CRef.isAbstract())
|
|
return {};
|
|
|
|
auto C = CRef.getConcrete();
|
|
|
|
// Walk down to the base NormalProtocolConformance.
|
|
ArrayRef<Substitution> Subs;
|
|
const ProtocolConformance *ParentC = C;
|
|
while (!isa<NormalProtocolConformance>(ParentC)) {
|
|
switch (ParentC->getKind()) {
|
|
case ProtocolConformanceKind::Normal:
|
|
llvm_unreachable("should have exited the loop?!");
|
|
case ProtocolConformanceKind::Inherited:
|
|
ParentC = cast<InheritedProtocolConformance>(ParentC)
|
|
->getInheritedConformance();
|
|
break;
|
|
case ProtocolConformanceKind::Specialized: {
|
|
auto SC = cast<SpecializedProtocolConformance>(ParentC);
|
|
ParentC = SC->getGenericConformance();
|
|
assert(Subs.empty() && "multiple conformance specializations?!");
|
|
Subs = SC->getGenericSubstitutions();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
const NormalProtocolConformance *NormalC
|
|
= cast<NormalProtocolConformance>(ParentC);
|
|
|
|
// If the normal conformance is for a generic type, and we didn't hit a
|
|
// specialized conformance, collect the substitutions from the generic type.
|
|
// FIXME: The AST should do this for us.
|
|
if (NormalC->getType()->isSpecialized() && Subs.empty()) {
|
|
Subs = NormalC->getType()
|
|
->gatherAllSubstitutions(NormalC->getDeclContext()->getParentModule(),
|
|
nullptr);
|
|
}
|
|
|
|
return Subs;
|
|
}
|
|
|
|
/// \brief Given a protocol \p Proto, a member method \p Member and a concrete
|
|
/// class type \p ConcreteTy, search the witness tables and return the static
|
|
/// function that matches the member with any specializations may be
|
|
/// required. Notice that we do not scan the class hierarchy, just the concrete
|
|
/// class type.
|
|
std::tuple<SILFunction *, SILWitnessTable *, ArrayRef<Substitution>>
|
|
SILModule::lookUpFunctionInWitnessTable(ProtocolConformanceRef C,
|
|
SILDeclRef Member) {
|
|
// Look up the witness table associated with our protocol conformance from the
|
|
// SILModule.
|
|
auto Ret = lookUpWitnessTable(C);
|
|
|
|
// If no witness table was found, bail.
|
|
if (!Ret) {
|
|
DEBUG(llvm::dbgs() << " Failed speculative lookup of witness for: ";
|
|
C.dump(); Member.dump());
|
|
return std::make_tuple(nullptr, nullptr, ArrayRef<Substitution>());
|
|
}
|
|
|
|
// Okay, we found the correct witness table. Now look for the method.
|
|
for (auto &Entry : Ret->getEntries()) {
|
|
// Look at method entries only.
|
|
if (Entry.getKind() != SILWitnessTable::WitnessKind::Method)
|
|
continue;
|
|
|
|
SILWitnessTable::MethodWitness MethodEntry = Entry.getMethodWitness();
|
|
// Check if this is the member we were looking for.
|
|
if (MethodEntry.Requirement != Member)
|
|
continue;
|
|
|
|
return std::make_tuple(MethodEntry.Witness, Ret,
|
|
getSubstitutionsForProtocolConformance(C));
|
|
}
|
|
|
|
return std::make_tuple(nullptr, nullptr, ArrayRef<Substitution>());
|
|
}
|
|
|
|
static ClassDecl *getClassDeclSuperClass(ClassDecl *Class) {
|
|
Type T = Class->getSuperclass();
|
|
if (!T)
|
|
return nullptr;
|
|
return T->getCanonicalType()->getClassOrBoundGenericClass();
|
|
}
|
|
|
|
SILFunction *
|
|
SILModule::
|
|
lookUpFunctionInVTable(ClassDecl *Class, SILDeclRef Member) {
|
|
// Until we reach the top of the class hierarchy...
|
|
while (Class) {
|
|
// Try to lookup a VTable for Class from the module...
|
|
auto *Vtbl = lookUpVTable(Class);
|
|
|
|
// Bail, if the lookup of VTable fails.
|
|
if (!Vtbl) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Ok, we have a VTable. Try to lookup the SILFunction implementation from
|
|
// the VTable.
|
|
if (SILFunction *F = Vtbl->getImplementation(*this, Member))
|
|
return F;
|
|
|
|
// If we fail to lookup the SILFunction, again skip Class and attempt to
|
|
// resolve the method in the VTable of the super class of Class if such a
|
|
// super class exists.
|
|
Class = getClassDeclSuperClass(Class);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
void SILModule::
|
|
registerDeleteNotificationHandler(DeleteNotificationHandler* Handler) {
|
|
// Ask the handler (that can be an analysis, a pass, or some other data
|
|
// structure) if it wants to receive delete notifications.
|
|
if (Handler->needsNotifications()) {
|
|
NotificationHandlers.insert(Handler);
|
|
}
|
|
}
|
|
|
|
void SILModule::
|
|
removeDeleteNotificationHandler(DeleteNotificationHandler* Handler) {
|
|
NotificationHandlers.remove(Handler);
|
|
}
|
|
|
|
void SILModule::notifyDeleteHandlers(ValueBase *V) {
|
|
for (auto *Handler : NotificationHandlers) {
|
|
Handler->handleDeleteNotification(V);
|
|
}
|
|
}
|