| //===- 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 |