mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Language features like erasing concrete metatype values are also left for the future. Still, baby steps. The singleton ordinary metatype for existential types is still potentially useful; we allow it to be written as P.Protocol. I've been somewhat cavalier in making code accept AnyMetatypeType instead of a more specific type, and it's likely that a number of these places can and should be more restrictive. When T is an existential type, parse T.Type as an ExistentialMetatypeType instead of a MetatypeType. An existential metatype is the formal type \exists t:P . (t.Type) whereas the ordinary metatype is the formal type (\exists t:P . t).Type which is singleton. Our inability to express that difference was leading to an ever-increasing cascade of hacks where information is shadily passed behind the scenes in order to make various operations with static members of protocols work correctly. This patch takes the first step towards fixing that by splitting out existential metatypes and giving them a pointer representation. Eventually, we will need them to be able to carry protocol witness tables Swift SVN r15716
596 lines
19 KiB
C++
596 lines
19 KiB
C++
//===--- SILModule.cpp - SILModule implementation -------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/SIL/SILModule.h"
|
|
#include "swift/SIL/SILExternalSource.h"
|
|
#include "swift/SIL/SILVisitor.h"
|
|
#include "swift/Serialization/SerializedSILLoader.h"
|
|
#include "swift/SIL/SILValue.h"
|
|
#include "llvm/ADT/FoldingSet.h"
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/Support/Debug.h"
|
|
using namespace swift;
|
|
|
|
STATISTIC(NumFuncLinked, "Number of SIL functions linked");
|
|
|
|
namespace swift {
|
|
/// SILTypeList - The uniqued backing store for the SILValue type list. This
|
|
/// is only exposed out of SILValue as an ArrayRef of types, so it should
|
|
/// never be used outside of libSIL.
|
|
class SILTypeList : public llvm::FoldingSetNode {
|
|
public:
|
|
unsigned NumTypes;
|
|
SILType Types[1]; // Actually variable sized.
|
|
|
|
void Profile(llvm::FoldingSetNodeID &ID) const {
|
|
for (unsigned i = 0, e = NumTypes; i != e; ++i) {
|
|
ID.AddPointer(Types[i].getOpaqueValue());
|
|
}
|
|
}
|
|
};
|
|
} // end namespace swift.
|
|
|
|
void SILExternalSource::anchor() {
|
|
}
|
|
|
|
/// SILTypeListUniquingType - This is the type of the folding set maintained by
|
|
/// SILModule that these things are uniqued into.
|
|
typedef llvm::FoldingSet<SILTypeList> SILTypeListUniquingType;
|
|
|
|
class SILModule::SerializationCallback : public SerializedSILLoader::Callback {
|
|
void didDeserialize(Module *M, SILFunction *fn) override {
|
|
updateLinkage(fn);
|
|
}
|
|
|
|
void didDeserialize(Module *M, SILGlobalVariable *var) override {
|
|
updateLinkage(var);
|
|
}
|
|
|
|
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::Shared);
|
|
return;
|
|
case SILLinkage::Private: // ?
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::HiddenExternal:
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
SILModule::SILModule(Module *SwiftModule)
|
|
: TheSwiftModule(SwiftModule), Stage(SILStage::Raw),
|
|
Callback(new SILModule::SerializationCallback()), Types(*this) {
|
|
TypeListUniquing = new SILTypeListUniquingType();
|
|
}
|
|
|
|
SILModule::~SILModule() {
|
|
delete (SILTypeListUniquingType*)TypeListUniquing;
|
|
}
|
|
|
|
SILWitnessTable *
|
|
SILModule::createWitnessTableDeclaration(ProtocolConformance *C) {
|
|
// Walk down to the base NormalProtocolConformance.
|
|
ProtocolConformance *ParentC = C;
|
|
ArrayRef<Substitution> Subs;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
NormalProtocolConformance *NormalC
|
|
= cast<NormalProtocolConformance>(ParentC);
|
|
|
|
SILWitnessTable *WT = SILWitnessTable::create(*this,
|
|
SILLinkage::PublicExternal,
|
|
NormalC);
|
|
return WT;
|
|
}
|
|
|
|
std::pair<SILWitnessTable *, ArrayRef<Substitution>>
|
|
SILModule::lookUpWitnessTable(const ProtocolConformance *C) {
|
|
// Walk down to the base NormalProtocolConformance.
|
|
const ProtocolConformance *ParentC = C;
|
|
ArrayRef<Substitution> Subs;
|
|
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);
|
|
}
|
|
|
|
// Attempt to lookup the witness table from the table.
|
|
auto found = WitnessTableLookupCache.find(NormalC);
|
|
if (found == WitnessTableLookupCache.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, Subs};
|
|
}
|
|
|
|
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, Subs};
|
|
|
|
// 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 (auto deserializedTable = getSILLoader()->lookupWitnessTable(wT))
|
|
return {deserializedTable, Subs};
|
|
|
|
// If we fail, just return the declaration.
|
|
return {wT, Subs};
|
|
}
|
|
|
|
SILFunction *SILModule::getOrCreateSharedFunction(SILLocation loc,
|
|
StringRef name,
|
|
CanSILFunctionType type,
|
|
IsBare_t isBareSILFunction,
|
|
IsTransparent_t isTransparent) {
|
|
auto linkage = SILLinkage::Shared;
|
|
|
|
if (auto fn = lookUpFunction(name)) {
|
|
assert(fn->getLoweredFunctionType() == type);
|
|
assert(fn->getLinkage() == linkage);
|
|
return fn;
|
|
}
|
|
|
|
return SILFunction::create(*this, linkage, name, type, nullptr,
|
|
loc, isBareSILFunction, isTransparent);
|
|
}
|
|
|
|
ArrayRef<SILType> ValueBase::getTypes() const {
|
|
// No results.
|
|
if (TypeOrTypeList.isNull())
|
|
return ArrayRef<SILType>();
|
|
// Arbitrary list of results.
|
|
if (auto *TypeList = TypeOrTypeList.dyn_cast<SILTypeList*>())
|
|
return ArrayRef<SILType>(TypeList->Types, TypeList->NumTypes);
|
|
// Single result.
|
|
return TypeOrTypeList.get<SILType>();
|
|
}
|
|
|
|
|
|
|
|
/// getSILTypeList - Get a uniqued pointer to a SIL type list. This can only
|
|
/// be used by SILValue.
|
|
SILTypeList *SILModule::getSILTypeList(ArrayRef<SILType> Types) const {
|
|
assert(Types.size() > 1 && "Shouldn't use type list for 0 or 1 types");
|
|
auto UniqueMap = (SILTypeListUniquingType*)TypeListUniquing;
|
|
|
|
llvm::FoldingSetNodeID ID;
|
|
for (auto T : Types) {
|
|
ID.AddPointer(T.getOpaqueValue());
|
|
}
|
|
|
|
// If we already have this type list, just return it.
|
|
void *InsertPoint = 0;
|
|
if (SILTypeList *TypeList = UniqueMap->FindNodeOrInsertPos(ID, InsertPoint))
|
|
return TypeList;
|
|
|
|
// Otherwise, allocate a new one.
|
|
void *NewListP = BPA.Allocate(sizeof(SILTypeList)+
|
|
sizeof(SILType)*(Types.size()-1),
|
|
alignof(SILTypeList));
|
|
SILTypeList *NewList = new (NewListP) SILTypeList();
|
|
NewList->NumTypes = Types.size();
|
|
std::copy(Types.begin(), Types.end(), NewList->Types);
|
|
|
|
UniqueMap->InsertNode(NewList, InsertPoint);
|
|
return NewList;
|
|
}
|
|
|
|
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 {
|
|
// 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;
|
|
}
|
|
|
|
namespace {
|
|
|
|
/// Visitor that knows how to link in dependencies of SILInstructions.
|
|
class SILLinkerVisitor : public SILInstructionVisitor<SILLinkerVisitor, bool> {
|
|
using LinkingMode = SILModule::LinkingMode;
|
|
|
|
/// The SILModule that we are loading from.
|
|
SILModule &Mod;
|
|
|
|
/// The SILLoader that this visitor is using to link.
|
|
SerializedSILLoader *Loader;
|
|
|
|
/// The external SIL source to use when linking this module.
|
|
SILExternalSource *ExternalSource = nullptr;
|
|
|
|
/// Worklist of SILFunctions we are processing.
|
|
llvm::SmallVector<SILFunction *, 128> Worklist;
|
|
|
|
/// A list of callees of the current instruction being visited. cleared after
|
|
/// every instruction is visited.
|
|
llvm::SmallVector<SILFunction *, 4> FunctionDeserializationWorklist;
|
|
|
|
/// The current linking mode.
|
|
LinkingMode Mode;
|
|
public:
|
|
|
|
SILLinkerVisitor(SILModule &M, SerializedSILLoader *L,
|
|
SILModule::LinkingMode LinkingMode,
|
|
SILExternalSource *E = nullptr)
|
|
: Mod(M), Loader(L), ExternalSource(E), Worklist(),
|
|
FunctionDeserializationWorklist(), Mode(LinkingMode) { }
|
|
|
|
/// Process F, recursively deserializing any thing F may reference.
|
|
bool processFunction(SILFunction *F) {
|
|
if (Mode == LinkingMode::LinkNone)
|
|
return false;
|
|
|
|
// If F is a declaration, first deserialize it.
|
|
auto NewFn = F->isExternalDeclaration() ? Loader->lookupSILFunction(F) : F;
|
|
if (!NewFn || NewFn->empty())
|
|
return false;
|
|
|
|
++NumFuncLinked;
|
|
|
|
// Try to transitively deserialize everything referenced by NewFn.
|
|
Worklist.push_back(NewFn);
|
|
process();
|
|
|
|
// Since we successfully processed at least one function, return true.
|
|
return true;
|
|
}
|
|
|
|
/// Deserialize the VTable mapped to C if it exists and all SIL the VTable
|
|
/// transitively references.
|
|
///
|
|
/// This method assumes that the caller made sure that no vtable existed in
|
|
/// Mod.
|
|
SILVTable *processClassDecl(const ClassDecl *C) {
|
|
// If we are not linking anything, bail.
|
|
if (Mode == LinkingMode::LinkNone)
|
|
return nullptr;
|
|
|
|
// Attempt to load the VTable from the SerializedSILLoader. If we
|
|
// fail... bail...
|
|
SILVTable *Vtbl = Loader->lookupVTable(C);
|
|
if (!Vtbl)
|
|
return nullptr;
|
|
|
|
// Otherwise, add all the vtable functions in Vtbl to the function
|
|
// processing list...
|
|
for (auto &E : Vtbl->getEntries())
|
|
Worklist.push_back(E.second);
|
|
|
|
// And then transitively deserialize all SIL referenced by those functions.
|
|
process();
|
|
|
|
// Return the deserialized Vtbl.
|
|
return Vtbl;
|
|
}
|
|
|
|
/// We do not want to visit callee functions if we just have a value base.
|
|
bool visitValueBase(ValueBase *V) { return false; }
|
|
|
|
bool visitApplyInst(ApplyInst *AI) {
|
|
// If we don't have a function ref inst, just return false. We do not have
|
|
// interesting callees.
|
|
auto *FRI = dyn_cast<FunctionRefInst>(AI->getCallee().getDef());
|
|
if (!FRI)
|
|
return false;
|
|
|
|
// Ok we have a function ref inst, grab the callee.
|
|
SILFunction *Callee = FRI->getReferencedFunction();
|
|
|
|
// If the linking mode is not link all, AI is not transparent, and the
|
|
// callee is not shared, we don't want to perform any linking.
|
|
if (!isLinkAll() && !AI->isTransparent() &&
|
|
Callee->getLinkage() != SILLinkage::Shared)
|
|
return false;
|
|
|
|
// Otherwise we want to try and link in the callee... Add it to the callee
|
|
// list and return true.
|
|
addFunctionToWorklist(Callee);
|
|
return true;
|
|
}
|
|
|
|
bool visitPartialApplyInst(PartialApplyInst *PAI) {
|
|
auto *FRI = dyn_cast<FunctionRefInst>(PAI->getCallee().getDef());
|
|
if (!FRI)
|
|
return false;
|
|
|
|
SILFunction *Callee = FRI->getReferencedFunction();
|
|
if (!isLinkAll() && !Callee->isTransparent() &&
|
|
Callee->getLinkage() != SILLinkage::Shared)
|
|
return false;
|
|
|
|
addFunctionToWorklist(Callee);
|
|
return true;
|
|
}
|
|
|
|
bool visitFunctionRefInst(FunctionRefInst *FRI) {
|
|
if (!isLinkAll())
|
|
return false;
|
|
|
|
addFunctionToWorklist(FRI->getReferencedFunction());
|
|
return true;
|
|
}
|
|
|
|
bool visitWitnessMethodInst(WitnessMethodInst *WMI) {
|
|
ProtocolConformance *C = WMI->getConformance();
|
|
if (!C)
|
|
return false;
|
|
|
|
SILWitnessTable *WT = WMI->getModule().lookUpWitnessTable(C).first;
|
|
if (!WT || WT->isDeclaration())
|
|
return false;
|
|
|
|
SILDeclRef Member = WMI->getMember();
|
|
for (auto &E : WT->getEntries()) {
|
|
if (E.getKind() == SILWitnessTable::WitnessKind::Method &&
|
|
E.getMethodWitness().Requirement == Member) {
|
|
addFunctionToWorklist(E.getMethodWitness().Witness);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool visitAllocRefInst(AllocRefInst *ARI) {
|
|
// Grab the class decl from the alloc ref inst.
|
|
ClassDecl *D = ARI->getType().getClassOrBoundGenericClass();
|
|
if (!D)
|
|
return false;
|
|
|
|
return linkInVTable(D);
|
|
}
|
|
|
|
bool visitMetatypeInst(MetatypeInst *MI) {
|
|
CanType instTy = MI->getType().castTo<MetatypeType>().getInstanceType();
|
|
ClassDecl *C = instTy.getClassOrBoundGenericClass();
|
|
if (!C)
|
|
return false;
|
|
|
|
return linkInVTable(C);
|
|
}
|
|
|
|
private:
|
|
/// Add a function to our function worklist for processing.
|
|
void addFunctionToWorklist(SILFunction *F) {
|
|
FunctionDeserializationWorklist.push_back(F);
|
|
}
|
|
|
|
/// Is the current mode link all? Link all implies we should try and link
|
|
/// everything, not just transparent/shared functions.
|
|
bool isLinkAll() const { return Mode == LinkingMode::LinkAll; }
|
|
|
|
bool linkInVTable(ClassDecl *D) {
|
|
// Attempt to lookup the Vtbl from the SILModule.
|
|
SILVTable *Vtbl = Mod.lookUpVTable(D);
|
|
|
|
// If the SILModule does not have the VTable, attempt to deserialize the
|
|
// VTable. If we fail to do that as well, bail.
|
|
if (!Vtbl || !(Vtbl = Loader->lookupVTable(D->getName())))
|
|
return false;
|
|
|
|
// Ok we found our VTable. Visit each function referenced by the VTable. If
|
|
// any of the functions are external declarations, add them to the worklist
|
|
// for processing.
|
|
bool Result = false;
|
|
for (auto P : Vtbl->getEntries()) {
|
|
if (P.second->isExternalDeclaration()) {
|
|
Result = true;
|
|
addFunctionToWorklist(P.second);
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
// Main loop of the visitor. Called by one of the other *visit* methods.
|
|
bool process() {
|
|
// Process everything transitively referenced by one of the functions in the
|
|
// worklist.
|
|
bool Result = false;
|
|
while (!Worklist.empty()) {
|
|
auto Fn = Worklist.pop_back_val();
|
|
for (auto &BB : *Fn) {
|
|
for (auto &I : BB) {
|
|
// Should we try linking?
|
|
if (visit(&I)) {
|
|
for (auto F : FunctionDeserializationWorklist) {
|
|
// The ExternalSource may wish to rewrite non-empty bodies.
|
|
if (!F->empty() && ExternalSource)
|
|
if (auto NewFn = ExternalSource->lookupSILFunction(F)) {
|
|
NewFn->verify();
|
|
Worklist.push_back(NewFn);
|
|
++NumFuncLinked;
|
|
Result = true;
|
|
continue;
|
|
}
|
|
|
|
F->setBare(IsBare);
|
|
|
|
if (F->empty())
|
|
if (auto NewFn = Loader->lookupSILFunction(F)) {
|
|
NewFn->verify();
|
|
Worklist.push_back(NewFn);
|
|
Result = true;
|
|
++NumFuncLinked;
|
|
}
|
|
}
|
|
FunctionDeserializationWorklist.clear();
|
|
} else {
|
|
assert(FunctionDeserializationWorklist.empty() && "Worklist should "
|
|
"always be empty if visit does not return true.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we return true, we deserialized at least one function.
|
|
return Result;
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace.
|
|
|
|
bool SILModule::linkFunction(SILFunction *Fun, SILModule::LinkingMode Mode) {
|
|
return SILLinkerVisitor(*this, getSILLoader(), Mode,
|
|
ExternalSource).processFunction(Fun);
|
|
}
|
|
|
|
void SILModule::linkAllWitnessTables() {
|
|
getSILLoader()->getAllWitnessTables();
|
|
}
|
|
|
|
void SILModule::linkAllVTables() {
|
|
getSILLoader()->getAllVTables();
|
|
}
|
|
|
|
SILVTable *SILModule::lookUpVTable(const ClassDecl *C) {
|
|
if (!C)
|
|
return nullptr;
|
|
|
|
// First try to look up R from the lookup table.
|
|
auto R = VTableLookupTable.find(C);
|
|
if (R != VTableLookupTable.end())
|
|
return R->second;
|
|
|
|
// If that fails, try to deserialize it. If that fails, return nullptr.
|
|
SILVTable *Vtbl = SILLinkerVisitor(*this, getSILLoader(),
|
|
SILModule::LinkingMode::LinkAll,
|
|
ExternalSource).processClassDecl(C);
|
|
if (!Vtbl)
|
|
return nullptr;
|
|
|
|
// If we succeeded, map C -> VTbl in the table and return VTbl.
|
|
VTableLookupTable[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();
|
|
}
|