llvm-project/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h

535 lines
18 KiB
C++

//===- OrcCBindingsStack.h - Orc JIT stack for C bindings -----*- C++ -*---===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#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::LegacyRTDyldObjectLinkingLayer> : public GenericLayer {
private:
using LayerT = orc::LegacyRTDyldObjectLinkingLayer;
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 std::make_unique<GenericLayerImpl<LayerT>>(Layer);
}
} // end namespace detail
class OrcCBindingsStack {
public:
using CompileCallbackMgr = orc::JITCompileCallbackManager;
using ObjLayerT = orc::LegacyRTDyldObjectLinkingLayer;
using CompileLayerT = orc::LegacyIRCompileLayer<ObjLayerT, orc::SimpleCompiler>;
using CODLayerT =
orc::LegacyCompileOnDemandLayer<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(std::string(*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(std::string(*S))) {
if (auto Addr = Sym.getAddress()) {
Query->notifySymbolMetRequiredState(
S, JITEvaluatedSymbol(*Addr, Sym.getFlags()));
} 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->isComplete())
Query->handleComplete();
return UnresolvedSymbols;
}
private:
JITSymbol findSymbol(const std::string &Name) {
// Search order:
// 1. JIT'd symbols.
// 2. Runtime overrides.
// 3. External resolver (if present).
if (Stack.CODLayer) {
if (auto Sym = Stack.CODLayer->findSymbol(Name, true))
return Sym;
else if (auto Err = Sym.takeError())
return Sym.takeError();
} else {
if (auto Sym = Stack.CompileLayer.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(createCompileCallbackManager(TM, ES)), DL(TM.createDataLayout()),
IndirectStubsMgr(IndirectStubsMgrBuilder()),
ObjectLayer(
AcknowledgeORCv1Deprecation, 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(AcknowledgeORCv1Deprecation, ObjectLayer,
orc::SimpleCompiler(TM)),
CODLayer(createCODLayer(ES, CompileLayer, CCMgr.get(),
std::move(IndirectStubsMgrBuilder), Resolvers)),
CXXRuntimeOverrides(
AcknowledgeORCv1Deprecation,
[this](const std::string &S) { return mangle(S); }) {}
Error 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 Err;
return Error::success();
}
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));
}
Expected<JITTargetAddress>
createLazyCompileCallback(LLVMOrcLazyCompileCallbackFn Callback,
void *CallbackCtx) {
auto WrappedCallback = [=]() -> JITTargetAddress {
return Callback(wrap(this), CallbackCtx);
};
return CCMgr->getCompileCallback(std::move(WrappedCallback));
}
Error createIndirectStub(StringRef StubName, JITTargetAddress Addr) {
return IndirectStubsMgr->createStub(StubName, Addr,
JITSymbolFlags::Exported);
}
Error setIndirectStubPointer(StringRef Name, JITTargetAddress Addr) {
return IndirectStubsMgr->updatePointer(Name, Addr);
}
template <typename LayerT>
Expected<orc::VModuleKey>
addIRModule(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.
auto K = ES.allocateVModule();
Resolvers[K] = std::make_shared<CBindingsResolver>(*this, ExternalResolver,
ExternalResolverCtx);
if (auto Err = Layer.addModule(K, std::move(M)))
return std::move(Err);
KeyLayers[K] = detail::createGenericLayer(Layer);
// Run the static constructors, and save the static destructor runner for
// execution when the JIT is torn down.
orc::LegacyCtorDtorRunner<OrcCBindingsStack> CtorRunner(
AcknowledgeORCv1Deprecation, std::move(CtorNames), K);
if (auto Err = CtorRunner.runViaLayer(*this))
return std::move(Err);
IRStaticDestructorRunners.emplace_back(AcknowledgeORCv1Deprecation,
std::move(DtorNames), K);
return K;
}
Expected<orc::VModuleKey>
addIRModuleEager(std::unique_ptr<Module> M,
LLVMOrcSymbolResolverFn ExternalResolver,
void *ExternalResolverCtx) {
return addIRModule(CompileLayer, std::move(M),
std::make_unique<SectionMemoryManager>(),
std::move(ExternalResolver), ExternalResolverCtx);
}
Expected<orc::VModuleKey>
addIRModuleLazy(std::unique_ptr<Module> M,
LLVMOrcSymbolResolverFn ExternalResolver,
void *ExternalResolverCtx) {
if (!CODLayer)
return make_error<StringError>("Can not add lazy module: No compile "
"callback manager available",
inconvertibleErrorCode());
return addIRModule(*CODLayer, std::move(M),
std::make_unique<SectionMemoryManager>(),
std::move(ExternalResolver), ExternalResolverCtx);
}
Error removeModule(orc::VModuleKey K) {
// FIXME: Should error release the module key?
if (auto Err = KeyLayers[K]->removeModule(K))
return Err;
ES.releaseVModule(K);
KeyLayers.erase(K);
return Error::success();
}
Expected<orc::VModuleKey> addObject(std::unique_ptr<MemoryBuffer> ObjBuffer,
LLVMOrcSymbolResolverFn ExternalResolver,
void *ExternalResolverCtx) {
if (auto Obj = object::ObjectFile::createObjectFile(
ObjBuffer->getMemBufferRef())) {
auto K = ES.allocateVModule();
Resolvers[K] = std::make_shared<CBindingsResolver>(
*this, ExternalResolver, ExternalResolverCtx);
if (auto Err = ObjectLayer.addObject(K, std::move(ObjBuffer)))
return std::move(Err);
KeyLayers[K] = detail::createGenericLayer(ObjectLayer);
return K;
} else
return Obj.takeError();
}
JITSymbol findSymbol(const std::string &Name,
bool ExportedSymbolsOnly) {
if (auto Sym = IndirectStubsMgr->findStub(Name, ExportedSymbolsOnly))
return Sym;
if (CODLayer)
return CODLayer->findSymbol(mangle(Name), ExportedSymbolsOnly);
return CompileLayer.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);
}
Expected<JITTargetAddress> findSymbolAddress(const std::string &Name,
bool ExportedSymbolsOnly) {
if (auto Sym = findSymbol(Name, ExportedSymbolsOnly)) {
// Successful lookup, non-null symbol:
if (auto AddrOrErr = Sym.getAddress())
return *AddrOrErr;
else
return AddrOrErr.takeError();
} else if (auto Err = Sym.takeError()) {
// Lookup failure - report error.
return std::move(Err);
}
// No symbol not found. Return 0.
return 0;
}
Expected<JITTargetAddress> findSymbolAddressIn(orc::VModuleKey K,
const std::string &Name,
bool ExportedSymbolsOnly) {
if (auto Sym = findSymbolIn(K, Name, ExportedSymbolsOnly)) {
// Successful lookup, non-null symbol:
if (auto AddrOrErr = Sym.getAddress())
return *AddrOrErr;
else
return AddrOrErr.takeError();
} else if (auto Err = Sym.takeError()) {
// Lookup failure - report error.
return std::move(Err);
}
// Symbol not found. Return 0.
return 0;
}
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:
using ResolverMap =
std::map<orc::VModuleKey, std::shared_ptr<orc::SymbolResolver>>;
static std::unique_ptr<CompileCallbackMgr>
createCompileCallbackManager(TargetMachine &TM, orc::ExecutionSession &ES) {
auto CCMgr = createLocalCompileCallbackManager(TM.getTargetTriple(), ES, 0);
if (!CCMgr) {
// FIXME: It would be good if we could report this somewhere, but we do
// have an instance yet.
logAllUnhandledErrors(CCMgr.takeError(), errs(), "ORC error: ");
return nullptr;
}
return std::move(*CCMgr);
}
static std::unique_ptr<CODLayerT>
createCODLayer(orc::ExecutionSession &ES, CompileLayerT &CompileLayer,
CompileCallbackMgr *CCMgr,
IndirectStubsManagerBuilder IndirectStubsMgrBuilder,
ResolverMap &Resolvers) {
// If there is no compile callback manager available we can not create a
// compile on demand layer.
if (!CCMgr)
return nullptr;
return std::make_unique<CODLayerT>(
AcknowledgeORCv1Deprecation, ES, CompileLayer,
[&Resolvers](orc::VModuleKey K) {
auto ResolverI = Resolvers.find(K);
assert(ResolverI != Resolvers.end() && "No resolver for module K");
return ResolverI->second;
},
[&Resolvers](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}); }, *CCMgr,
std::move(IndirectStubsMgrBuilder), false);
}
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) {
uint64_t Key = static_cast<uint64_t>(
reinterpret_cast<uintptr_t>(Obj.getData().data()));
for (auto &Listener : EventListeners)
Listener->notifyObjectLoaded(Key, Obj, LoadedObjInfo);
}
void notifyFreed(orc::VModuleKey K, const object::ObjectFile &Obj) {
uint64_t Key = static_cast<uint64_t>(
reinterpret_cast<uintptr_t>(Obj.getData().data()));
for (auto &Listener : EventListeners)
Listener->notifyFreeingObject(Key);
}
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;
std::unique_ptr<CODLayerT> CODLayer;
std::map<orc::VModuleKey, std::unique_ptr<detail::GenericLayer>> KeyLayers;
orc::LegacyLocalCXXRuntimeOverrides CXXRuntimeOverrides;
std::vector<orc::LegacyCtorDtorRunner<OrcCBindingsStack>> IRStaticDestructorRunners;
std::string ErrMsg;
ResolverMap Resolvers;
};
} // end namespace llvm
#endif // LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H