diff options
Diffstat (limited to 'llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h')
-rw-r--r-- | llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h new file mode 100644 index 000000000000..e0af3df9d010 --- /dev/null +++ b/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h @@ -0,0 +1,534 @@ +//===- 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(*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->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 |