The new method name/behavior more closely models the way it was being used. It also fixes an assertion that can occur when using the new ORC Core APIs, where flags alone don't necessarily provide enough context to decide whether the caller is responsible for materializing a given symbol (which was always the reason this API existed). The default implementation of getResponsibilitySet uses lookupFlags to determine responsibility as before, so existing JITSymbolResolvers should continue to work. llvm-svn: 340874
515 lines
18 KiB
C++
515 lines
18 KiB
C++
//===- OrcCBindingsStack.h - Orc JIT stack for C bindings -----*- C++ -*---===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H
|
|
#define LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H
|
|
|
|
#include "llvm-c/OrcBindings.h"
|
|
#include "llvm-c/TargetMachine.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ExecutionEngine/JITSymbol.h"
|
|
#include "llvm/ExecutionEngine/JITEventListener.h"
|
|
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
|
|
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
|
|
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
|
|
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
|
|
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
|
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
#include "llvm/IR/Mangler.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/Support/CBindingWrapping.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace llvm {
|
|
|
|
class OrcCBindingsStack;
|
|
|
|
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcCBindingsStack, LLVMOrcJITStackRef)
|
|
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
|
|
|
|
namespace detail {
|
|
|
|
// FIXME: Kill this off once the Layer concept becomes an interface.
|
|
class GenericLayer {
|
|
public:
|
|
virtual ~GenericLayer() = default;
|
|
|
|
virtual JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name,
|
|
bool ExportedSymbolsOnly) = 0;
|
|
virtual Error removeModule(orc::VModuleKey K) = 0;
|
|
};
|
|
|
|
template <typename LayerT> class GenericLayerImpl : public GenericLayer {
|
|
public:
|
|
GenericLayerImpl(LayerT &Layer) : Layer(Layer) {}
|
|
|
|
JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name,
|
|
bool ExportedSymbolsOnly) override {
|
|
return Layer.findSymbolIn(K, Name, ExportedSymbolsOnly);
|
|
}
|
|
|
|
Error removeModule(orc::VModuleKey K) override {
|
|
return Layer.removeModule(K);
|
|
}
|
|
|
|
private:
|
|
LayerT &Layer;
|
|
};
|
|
|
|
template <>
|
|
class GenericLayerImpl<orc::RTDyldObjectLinkingLayer> : public GenericLayer {
|
|
private:
|
|
using LayerT = orc::RTDyldObjectLinkingLayer;
|
|
public:
|
|
GenericLayerImpl(LayerT &Layer) : Layer(Layer) {}
|
|
|
|
JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name,
|
|
bool ExportedSymbolsOnly) override {
|
|
return Layer.findSymbolIn(K, Name, ExportedSymbolsOnly);
|
|
}
|
|
|
|
Error removeModule(orc::VModuleKey K) override {
|
|
return Layer.removeObject(K);
|
|
}
|
|
|
|
private:
|
|
LayerT &Layer;
|
|
};
|
|
|
|
template <typename LayerT>
|
|
std::unique_ptr<GenericLayerImpl<LayerT>> createGenericLayer(LayerT &Layer) {
|
|
return llvm::make_unique<GenericLayerImpl<LayerT>>(Layer);
|
|
}
|
|
|
|
} // end namespace detail
|
|
|
|
class OrcCBindingsStack {
|
|
public:
|
|
|
|
using CompileCallbackMgr = orc::JITCompileCallbackManager;
|
|
using ObjLayerT = orc::RTDyldObjectLinkingLayer;
|
|
using CompileLayerT = orc::IRCompileLayer<ObjLayerT, orc::SimpleCompiler>;
|
|
using CODLayerT =
|
|
orc::CompileOnDemandLayer<CompileLayerT, CompileCallbackMgr>;
|
|
|
|
using CallbackManagerBuilder =
|
|
std::function<std::unique_ptr<CompileCallbackMgr>()>;
|
|
|
|
using IndirectStubsManagerBuilder = CODLayerT::IndirectStubsManagerBuilderT;
|
|
|
|
private:
|
|
|
|
using OwningObject = object::OwningBinary<object::ObjectFile>;
|
|
|
|
class CBindingsResolver : public orc::SymbolResolver {
|
|
public:
|
|
CBindingsResolver(OrcCBindingsStack &Stack,
|
|
LLVMOrcSymbolResolverFn ExternalResolver,
|
|
void *ExternalResolverCtx)
|
|
: Stack(Stack), ExternalResolver(std::move(ExternalResolver)),
|
|
ExternalResolverCtx(std::move(ExternalResolverCtx)) {}
|
|
|
|
orc::SymbolNameSet
|
|
getResponsibilitySet(const orc::SymbolNameSet &Symbols) override {
|
|
orc::SymbolNameSet Result;
|
|
|
|
for (auto &S : Symbols) {
|
|
if (auto Sym = findSymbol(*S)) {
|
|
if (!Sym.getFlags().isStrong())
|
|
Result.insert(S);
|
|
} else if (auto Err = Sym.takeError()) {
|
|
Stack.reportError(std::move(Err));
|
|
return orc::SymbolNameSet();
|
|
}
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
orc::SymbolNameSet
|
|
lookup(std::shared_ptr<orc::AsynchronousSymbolQuery> Query,
|
|
orc::SymbolNameSet Symbols) override {
|
|
orc::SymbolNameSet UnresolvedSymbols;
|
|
|
|
for (auto &S : Symbols) {
|
|
if (auto Sym = findSymbol(*S)) {
|
|
if (auto Addr = Sym.getAddress()) {
|
|
Query->resolve(S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
|
|
Query->notifySymbolReady();
|
|
} else {
|
|
Stack.ES.legacyFailQuery(*Query, Addr.takeError());
|
|
return orc::SymbolNameSet();
|
|
}
|
|
} else if (auto Err = Sym.takeError()) {
|
|
Stack.ES.legacyFailQuery(*Query, std::move(Err));
|
|
return orc::SymbolNameSet();
|
|
} else
|
|
UnresolvedSymbols.insert(S);
|
|
}
|
|
|
|
if (Query->isFullyResolved())
|
|
Query->handleFullyResolved();
|
|
|
|
if (Query->isFullyReady())
|
|
Query->handleFullyReady();
|
|
|
|
return UnresolvedSymbols;
|
|
}
|
|
|
|
private:
|
|
JITSymbol findSymbol(const std::string &Name) {
|
|
// Search order:
|
|
// 1. JIT'd symbols.
|
|
// 2. Runtime overrides.
|
|
// 3. External resolver (if present).
|
|
|
|
if (auto Sym = Stack.CODLayer.findSymbol(Name, true))
|
|
return Sym;
|
|
else if (auto Err = Sym.takeError())
|
|
return Sym.takeError();
|
|
|
|
if (auto Sym = Stack.CXXRuntimeOverrides.searchOverrides(Name))
|
|
return Sym;
|
|
|
|
if (ExternalResolver)
|
|
return JITSymbol(ExternalResolver(Name.c_str(), ExternalResolverCtx),
|
|
JITSymbolFlags::Exported);
|
|
|
|
return JITSymbol(nullptr);
|
|
}
|
|
|
|
OrcCBindingsStack &Stack;
|
|
LLVMOrcSymbolResolverFn ExternalResolver;
|
|
void *ExternalResolverCtx = nullptr;
|
|
};
|
|
|
|
public:
|
|
OrcCBindingsStack(TargetMachine &TM,
|
|
IndirectStubsManagerBuilder IndirectStubsMgrBuilder)
|
|
: CCMgr(createLocalCompileCallbackManager(TM.getTargetTriple(), ES, 0)),
|
|
DL(TM.createDataLayout()), IndirectStubsMgr(IndirectStubsMgrBuilder()),
|
|
ObjectLayer(ES,
|
|
[this](orc::VModuleKey K) {
|
|
auto ResolverI = Resolvers.find(K);
|
|
assert(ResolverI != Resolvers.end() &&
|
|
"No resolver for module K");
|
|
auto Resolver = std::move(ResolverI->second);
|
|
Resolvers.erase(ResolverI);
|
|
return ObjLayerT::Resources{
|
|
std::make_shared<SectionMemoryManager>(), Resolver};
|
|
},
|
|
nullptr,
|
|
[this](orc::VModuleKey K, const object::ObjectFile &Obj,
|
|
const RuntimeDyld::LoadedObjectInfo &LoadedObjInfo) {
|
|
this->notifyFinalized(K, Obj, LoadedObjInfo);
|
|
},
|
|
[this](orc::VModuleKey K, const object::ObjectFile &Obj) {
|
|
this->notifyFreed(K, Obj);
|
|
}),
|
|
CompileLayer(ObjectLayer, orc::SimpleCompiler(TM)),
|
|
CODLayer(ES, CompileLayer,
|
|
[this](orc::VModuleKey K) {
|
|
auto ResolverI = Resolvers.find(K);
|
|
assert(ResolverI != Resolvers.end() &&
|
|
"No resolver for module K");
|
|
return ResolverI->second;
|
|
},
|
|
[this](orc::VModuleKey K,
|
|
std::shared_ptr<orc::SymbolResolver> Resolver) {
|
|
assert(!Resolvers.count(K) && "Resolver already present");
|
|
Resolvers[K] = std::move(Resolver);
|
|
},
|
|
[](Function &F) { return std::set<Function *>({&F}); },
|
|
*this->CCMgr, std::move(IndirectStubsMgrBuilder), false),
|
|
CXXRuntimeOverrides(
|
|
[this](const std::string &S) { return mangle(S); }) {}
|
|
|
|
LLVMOrcErrorCode shutdown() {
|
|
// Run any destructors registered with __cxa_atexit.
|
|
CXXRuntimeOverrides.runDestructors();
|
|
// Run any IR destructors.
|
|
for (auto &DtorRunner : IRStaticDestructorRunners)
|
|
if (auto Err = DtorRunner.runViaLayer(*this))
|
|
return mapError(std::move(Err));
|
|
return LLVMOrcErrSuccess;
|
|
}
|
|
|
|
std::string mangle(StringRef Name) {
|
|
std::string MangledName;
|
|
{
|
|
raw_string_ostream MangledNameStream(MangledName);
|
|
Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
|
|
}
|
|
return MangledName;
|
|
}
|
|
|
|
template <typename PtrTy>
|
|
static PtrTy fromTargetAddress(JITTargetAddress Addr) {
|
|
return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr));
|
|
}
|
|
|
|
|
|
LLVMOrcErrorCode
|
|
createLazyCompileCallback(JITTargetAddress &RetAddr,
|
|
LLVMOrcLazyCompileCallbackFn Callback,
|
|
void *CallbackCtx) {
|
|
auto WrappedCallback = [=]() -> JITTargetAddress {
|
|
return Callback(wrap(this), CallbackCtx);
|
|
};
|
|
|
|
if (auto CCAddr = CCMgr->getCompileCallback(std::move(WrappedCallback))) {
|
|
RetAddr = *CCAddr;
|
|
return LLVMOrcErrSuccess;
|
|
} else
|
|
return mapError(CCAddr.takeError());
|
|
}
|
|
|
|
LLVMOrcErrorCode createIndirectStub(StringRef StubName,
|
|
JITTargetAddress Addr) {
|
|
return mapError(
|
|
IndirectStubsMgr->createStub(StubName, Addr, JITSymbolFlags::Exported));
|
|
}
|
|
|
|
LLVMOrcErrorCode setIndirectStubPointer(StringRef Name,
|
|
JITTargetAddress Addr) {
|
|
return mapError(IndirectStubsMgr->updatePointer(Name, Addr));
|
|
}
|
|
template <typename LayerT>
|
|
LLVMOrcErrorCode
|
|
addIRModule(orc::VModuleKey &RetKey, LayerT &Layer, std::unique_ptr<Module> M,
|
|
std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr,
|
|
LLVMOrcSymbolResolverFn ExternalResolver,
|
|
void *ExternalResolverCtx) {
|
|
|
|
// Attach a data-layout if one isn't already present.
|
|
if (M->getDataLayout().isDefault())
|
|
M->setDataLayout(DL);
|
|
|
|
// Record the static constructors and destructors. We have to do this before
|
|
// we hand over ownership of the module to the JIT.
|
|
std::vector<std::string> CtorNames, DtorNames;
|
|
for (auto Ctor : orc::getConstructors(*M))
|
|
CtorNames.push_back(mangle(Ctor.Func->getName()));
|
|
for (auto Dtor : orc::getDestructors(*M))
|
|
DtorNames.push_back(mangle(Dtor.Func->getName()));
|
|
|
|
// Add the module to the JIT.
|
|
RetKey = ES.allocateVModule();
|
|
Resolvers[RetKey] = std::make_shared<CBindingsResolver>(
|
|
*this, ExternalResolver, ExternalResolverCtx);
|
|
if (auto Err = Layer.addModule(RetKey, std::move(M)))
|
|
return mapError(std::move(Err));
|
|
|
|
KeyLayers[RetKey] = detail::createGenericLayer(Layer);
|
|
|
|
// Run the static constructors, and save the static destructor runner for
|
|
// execution when the JIT is torn down.
|
|
orc::CtorDtorRunner<OrcCBindingsStack> CtorRunner(std::move(CtorNames),
|
|
RetKey);
|
|
if (auto Err = CtorRunner.runViaLayer(*this))
|
|
return mapError(std::move(Err));
|
|
|
|
IRStaticDestructorRunners.emplace_back(std::move(DtorNames), RetKey);
|
|
|
|
return LLVMOrcErrSuccess;
|
|
}
|
|
|
|
LLVMOrcErrorCode addIRModuleEager(orc::VModuleKey &RetKey,
|
|
std::unique_ptr<Module> M,
|
|
LLVMOrcSymbolResolverFn ExternalResolver,
|
|
void *ExternalResolverCtx) {
|
|
return addIRModule(RetKey, CompileLayer, std::move(M),
|
|
llvm::make_unique<SectionMemoryManager>(),
|
|
std::move(ExternalResolver), ExternalResolverCtx);
|
|
}
|
|
|
|
LLVMOrcErrorCode addIRModuleLazy(orc::VModuleKey &RetKey,
|
|
std::unique_ptr<Module> M,
|
|
LLVMOrcSymbolResolverFn ExternalResolver,
|
|
void *ExternalResolverCtx) {
|
|
return addIRModule(RetKey, CODLayer, std::move(M),
|
|
llvm::make_unique<SectionMemoryManager>(),
|
|
std::move(ExternalResolver), ExternalResolverCtx);
|
|
}
|
|
|
|
LLVMOrcErrorCode removeModule(orc::VModuleKey K) {
|
|
// FIXME: Should error release the module key?
|
|
if (auto Err = KeyLayers[K]->removeModule(K))
|
|
return mapError(std::move(Err));
|
|
ES.releaseVModule(K);
|
|
KeyLayers.erase(K);
|
|
return LLVMOrcErrSuccess;
|
|
}
|
|
|
|
LLVMOrcErrorCode addObject(orc::VModuleKey &RetKey,
|
|
std::unique_ptr<MemoryBuffer> ObjBuffer,
|
|
LLVMOrcSymbolResolverFn ExternalResolver,
|
|
void *ExternalResolverCtx) {
|
|
if (auto Obj = object::ObjectFile::createObjectFile(
|
|
ObjBuffer->getMemBufferRef())) {
|
|
|
|
RetKey = ES.allocateVModule();
|
|
Resolvers[RetKey] = std::make_shared<CBindingsResolver>(
|
|
*this, ExternalResolver, ExternalResolverCtx);
|
|
|
|
if (auto Err = ObjectLayer.addObject(RetKey, std::move(ObjBuffer)))
|
|
return mapError(std::move(Err));
|
|
|
|
KeyLayers[RetKey] = detail::createGenericLayer(ObjectLayer);
|
|
|
|
return LLVMOrcErrSuccess;
|
|
} else
|
|
return mapError(Obj.takeError());
|
|
}
|
|
|
|
JITSymbol findSymbol(const std::string &Name,
|
|
bool ExportedSymbolsOnly) {
|
|
if (auto Sym = IndirectStubsMgr->findStub(Name, ExportedSymbolsOnly))
|
|
return Sym;
|
|
return CODLayer.findSymbol(mangle(Name), ExportedSymbolsOnly);
|
|
}
|
|
|
|
JITSymbol findSymbolIn(orc::VModuleKey K, const std::string &Name,
|
|
bool ExportedSymbolsOnly) {
|
|
assert(KeyLayers.count(K) && "looking up symbol in unknown module");
|
|
return KeyLayers[K]->findSymbolIn(K, mangle(Name), ExportedSymbolsOnly);
|
|
}
|
|
|
|
LLVMOrcErrorCode findSymbolAddress(JITTargetAddress &RetAddr,
|
|
const std::string &Name,
|
|
bool ExportedSymbolsOnly) {
|
|
RetAddr = 0;
|
|
if (auto Sym = findSymbol(Name, ExportedSymbolsOnly)) {
|
|
// Successful lookup, non-null symbol:
|
|
if (auto AddrOrErr = Sym.getAddress()) {
|
|
RetAddr = *AddrOrErr;
|
|
return LLVMOrcErrSuccess;
|
|
} else
|
|
return mapError(AddrOrErr.takeError());
|
|
} else if (auto Err = Sym.takeError()) {
|
|
// Lookup failure - report error.
|
|
return mapError(std::move(Err));
|
|
}
|
|
// Otherwise we had a successful lookup but got a null result. We already
|
|
// set RetAddr to '0' above, so just return success.
|
|
return LLVMOrcErrSuccess;
|
|
}
|
|
|
|
LLVMOrcErrorCode findSymbolAddressIn(JITTargetAddress &RetAddr,
|
|
orc::VModuleKey K,
|
|
const std::string &Name,
|
|
bool ExportedSymbolsOnly) {
|
|
RetAddr = 0;
|
|
if (auto Sym = findSymbolIn(K, Name, ExportedSymbolsOnly)) {
|
|
// Successful lookup, non-null symbol:
|
|
if (auto AddrOrErr = Sym.getAddress()) {
|
|
RetAddr = *AddrOrErr;
|
|
return LLVMOrcErrSuccess;
|
|
} else
|
|
return mapError(AddrOrErr.takeError());
|
|
} else if (auto Err = Sym.takeError()) {
|
|
// Lookup failure - report error.
|
|
return mapError(std::move(Err));
|
|
}
|
|
// Otherwise we had a successful lookup but got a null result. We already
|
|
// set RetAddr to '0' above, so just return success.
|
|
return LLVMOrcErrSuccess;
|
|
}
|
|
|
|
const std::string &getErrorMessage() const { return ErrMsg; }
|
|
|
|
void RegisterJITEventListener(JITEventListener *L) {
|
|
if (!L)
|
|
return;
|
|
EventListeners.push_back(L);
|
|
}
|
|
|
|
void UnregisterJITEventListener(JITEventListener *L) {
|
|
if (!L)
|
|
return;
|
|
|
|
auto I = find(reverse(EventListeners), L);
|
|
if (I != EventListeners.rend()) {
|
|
std::swap(*I, EventListeners.back());
|
|
EventListeners.pop_back();
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
LLVMOrcErrorCode mapError(Error Err) {
|
|
LLVMOrcErrorCode Result = LLVMOrcErrSuccess;
|
|
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
|
|
// Handler of last resort.
|
|
Result = LLVMOrcErrGeneric;
|
|
ErrMsg = "";
|
|
raw_string_ostream ErrStream(ErrMsg);
|
|
EIB.log(ErrStream);
|
|
});
|
|
return Result;
|
|
}
|
|
|
|
void reportError(Error Err) {
|
|
// FIXME: Report errors on the execution session.
|
|
logAllUnhandledErrors(std::move(Err), errs(), "ORC error: ");
|
|
};
|
|
|
|
void notifyFinalized(orc::VModuleKey K,
|
|
const object::ObjectFile &Obj,
|
|
const RuntimeDyld::LoadedObjectInfo &LoadedObjInfo) {
|
|
for (auto &Listener : EventListeners)
|
|
Listener->NotifyObjectEmitted(Obj, LoadedObjInfo);
|
|
}
|
|
|
|
void notifyFreed(orc::VModuleKey K, const object::ObjectFile &Obj) {
|
|
for (auto &Listener : EventListeners)
|
|
Listener->NotifyFreeingObject(Obj);
|
|
}
|
|
|
|
orc::ExecutionSession ES;
|
|
std::unique_ptr<CompileCallbackMgr> CCMgr;
|
|
|
|
std::vector<JITEventListener *> EventListeners;
|
|
|
|
DataLayout DL;
|
|
SectionMemoryManager CCMgrMemMgr;
|
|
|
|
std::unique_ptr<orc::IndirectStubsManager> IndirectStubsMgr;
|
|
|
|
ObjLayerT ObjectLayer;
|
|
CompileLayerT CompileLayer;
|
|
CODLayerT CODLayer;
|
|
|
|
std::map<orc::VModuleKey, std::unique_ptr<detail::GenericLayer>> KeyLayers;
|
|
|
|
orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides;
|
|
std::vector<orc::CtorDtorRunner<OrcCBindingsStack>> IRStaticDestructorRunners;
|
|
std::string ErrMsg;
|
|
|
|
std::map<orc::VModuleKey, std::shared_ptr<orc::SymbolResolver>> Resolvers;
|
|
};
|
|
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H
|