| //===- 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::SymbolFlagsMap | |
| lookupFlags(const orc::SymbolNameSet &Symbols) override { | |
| orc::SymbolFlagsMap SymbolFlags; | |
| for (auto &S : Symbols) { | |
| if (auto Sym = findSymbol(*S)) | |
| SymbolFlags[S] = Sym.getFlags(); | |
| else if (auto Err = Sym.takeError()) { | |
| Stack.reportError(std::move(Err)); | |
| return orc::SymbolFlagsMap(); | |
| } | |
| } | |
| return SymbolFlags; | |
| } | |
| 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 |