| //===- LazyEmittingLayer.h - Lazily emit IR to lower JIT layers -*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Contains the definition for a lazy-emitting layer for the JIT. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H |
| #define LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H |
| |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/StringMap.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ExecutionEngine/JITSymbol.h" |
| #include "llvm/IR/GlobalValue.h" |
| #include "llvm/IR/Mangler.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <algorithm> |
| #include <cassert> |
| #include <list> |
| #include <memory> |
| #include <string> |
| |
| namespace llvm { |
| namespace orc { |
| |
| /// @brief Lazy-emitting IR layer. |
| /// |
| /// This layer accepts sets of LLVM IR Modules (via addModuleSet), but does |
| /// not immediately emit them the layer below. Instead, emissing to the base |
| /// layer is deferred until the first time the client requests the address |
| /// (via JITSymbol::getAddress) for a symbol contained in this layer. |
| template <typename BaseLayerT> class LazyEmittingLayer { |
| public: |
| typedef typename BaseLayerT::ModuleSetHandleT BaseLayerHandleT; |
| |
| private: |
| class EmissionDeferredSet { |
| public: |
| EmissionDeferredSet() = default; |
| virtual ~EmissionDeferredSet() = default; |
| |
| JITSymbol find(StringRef Name, bool ExportedSymbolsOnly, BaseLayerT &B) { |
| switch (EmitState) { |
| case NotEmitted: |
| if (auto GV = searchGVs(Name, ExportedSymbolsOnly)) { |
| // Create a std::string version of Name to capture here - the argument |
| // (a StringRef) may go away before the lambda is executed. |
| // FIXME: Use capture-init when we move to C++14. |
| std::string PName = Name; |
| JITSymbolFlags Flags = JITSymbolFlags::fromGlobalValue(*GV); |
| auto GetAddress = |
| [this, ExportedSymbolsOnly, PName, &B]() -> JITTargetAddress { |
| if (this->EmitState == Emitting) |
| return 0; |
| else if (this->EmitState == NotEmitted) { |
| this->EmitState = Emitting; |
| Handle = this->emitToBaseLayer(B); |
| this->EmitState = Emitted; |
| } |
| auto Sym = B.findSymbolIn(Handle, PName, ExportedSymbolsOnly); |
| return Sym.getAddress(); |
| }; |
| return JITSymbol(std::move(GetAddress), Flags); |
| } else |
| return nullptr; |
| case Emitting: |
| // Calling "emit" can trigger a recursive call to 'find' (e.g. to check |
| // for pre-existing definitions of common-symbol), but any symbol in |
| // this module would already have been found internally (in the |
| // RuntimeDyld that did the lookup), so just return a nullptr here. |
| return nullptr; |
| case Emitted: |
| return B.findSymbolIn(Handle, Name, ExportedSymbolsOnly); |
| } |
| llvm_unreachable("Invalid emit-state."); |
| } |
| |
| void removeModulesFromBaseLayer(BaseLayerT &BaseLayer) { |
| if (EmitState != NotEmitted) |
| BaseLayer.removeModuleSet(Handle); |
| } |
| |
| void emitAndFinalize(BaseLayerT &BaseLayer) { |
| assert(EmitState != Emitting && |
| "Cannot emitAndFinalize while already emitting"); |
| if (EmitState == NotEmitted) { |
| EmitState = Emitting; |
| Handle = emitToBaseLayer(BaseLayer); |
| EmitState = Emitted; |
| } |
| BaseLayer.emitAndFinalize(Handle); |
| } |
| |
| template <typename ModuleSetT, typename MemoryManagerPtrT, |
| typename SymbolResolverPtrT> |
| static std::unique_ptr<EmissionDeferredSet> |
| create(BaseLayerT &B, ModuleSetT Ms, MemoryManagerPtrT MemMgr, |
| SymbolResolverPtrT Resolver); |
| |
| protected: |
| virtual const GlobalValue* searchGVs(StringRef Name, |
| bool ExportedSymbolsOnly) const = 0; |
| virtual BaseLayerHandleT emitToBaseLayer(BaseLayerT &BaseLayer) = 0; |
| |
| private: |
| enum { NotEmitted, Emitting, Emitted } EmitState = NotEmitted; |
| BaseLayerHandleT Handle; |
| }; |
| |
| template <typename ModuleSetT, typename MemoryManagerPtrT, |
| typename SymbolResolverPtrT> |
| class EmissionDeferredSetImpl : public EmissionDeferredSet { |
| public: |
| EmissionDeferredSetImpl(ModuleSetT Ms, |
| MemoryManagerPtrT MemMgr, |
| SymbolResolverPtrT Resolver) |
| : Ms(std::move(Ms)), MemMgr(std::move(MemMgr)), |
| Resolver(std::move(Resolver)) {} |
| |
| protected: |
| const GlobalValue* searchGVs(StringRef Name, |
| bool ExportedSymbolsOnly) const override { |
| // FIXME: We could clean all this up if we had a way to reliably demangle |
| // names: We could just demangle name and search, rather than |
| // mangling everything else. |
| |
| // If we have already built the mangled name set then just search it. |
| if (MangledSymbols) { |
| auto VI = MangledSymbols->find(Name); |
| if (VI == MangledSymbols->end()) |
| return nullptr; |
| auto GV = VI->second; |
| if (!ExportedSymbolsOnly || GV->hasDefaultVisibility()) |
| return GV; |
| return nullptr; |
| } |
| |
| // If we haven't built the mangled name set yet, try to build it. As an |
| // optimization this will leave MangledNames set to nullptr if we find |
| // Name in the process of building the set. |
| return buildMangledSymbols(Name, ExportedSymbolsOnly); |
| } |
| |
| BaseLayerHandleT emitToBaseLayer(BaseLayerT &BaseLayer) override { |
| // We don't need the mangled names set any more: Once we've emitted this |
| // to the base layer we'll just look for symbols there. |
| MangledSymbols.reset(); |
| return BaseLayer.addModuleSet(std::move(Ms), std::move(MemMgr), |
| std::move(Resolver)); |
| } |
| |
| private: |
| // If the mangled name of the given GlobalValue matches the given search |
| // name (and its visibility conforms to the ExportedSymbolsOnly flag) then |
| // return the symbol. Otherwise, add the mangled name to the Names map and |
| // return nullptr. |
| const GlobalValue* addGlobalValue(StringMap<const GlobalValue*> &Names, |
| const GlobalValue &GV, |
| const Mangler &Mang, StringRef SearchName, |
| bool ExportedSymbolsOnly) const { |
| // Modules don't "provide" decls or common symbols. |
| if (GV.isDeclaration() || GV.hasCommonLinkage()) |
| return nullptr; |
| |
| // Mangle the GV name. |
| std::string MangledName; |
| { |
| raw_string_ostream MangledNameStream(MangledName); |
| Mang.getNameWithPrefix(MangledNameStream, &GV, false); |
| } |
| |
| // Check whether this is the name we were searching for, and if it is then |
| // bail out early. |
| if (MangledName == SearchName) |
| if (!ExportedSymbolsOnly || GV.hasDefaultVisibility()) |
| return &GV; |
| |
| // Otherwise add this to the map for later. |
| Names[MangledName] = &GV; |
| return nullptr; |
| } |
| |
| // Build the MangledSymbols map. Bails out early (with MangledSymbols left set |
| // to nullptr) if the given SearchName is found while building the map. |
| const GlobalValue* buildMangledSymbols(StringRef SearchName, |
| bool ExportedSymbolsOnly) const { |
| assert(!MangledSymbols && "Mangled symbols map already exists?"); |
| |
| auto Symbols = llvm::make_unique<StringMap<const GlobalValue*>>(); |
| |
| for (const auto &M : Ms) { |
| Mangler Mang; |
| |
| for (const auto &GO : M->global_objects()) |
| if (auto GV = addGlobalValue(*Symbols, GO, Mang, SearchName, |
| ExportedSymbolsOnly)) |
| return GV; |
| } |
| |
| MangledSymbols = std::move(Symbols); |
| return nullptr; |
| } |
| |
| ModuleSetT Ms; |
| MemoryManagerPtrT MemMgr; |
| SymbolResolverPtrT Resolver; |
| mutable std::unique_ptr<StringMap<const GlobalValue*>> MangledSymbols; |
| }; |
| |
| typedef std::list<std::unique_ptr<EmissionDeferredSet>> ModuleSetListT; |
| |
| BaseLayerT &BaseLayer; |
| ModuleSetListT ModuleSetList; |
| |
| public: |
| /// @brief Handle to a set of loaded modules. |
| typedef typename ModuleSetListT::iterator ModuleSetHandleT; |
| |
| /// @brief Construct a lazy emitting layer. |
| LazyEmittingLayer(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {} |
| |
| /// @brief Add the given set of modules to the lazy emitting layer. |
| template <typename ModuleSetT, typename MemoryManagerPtrT, |
| typename SymbolResolverPtrT> |
| ModuleSetHandleT addModuleSet(ModuleSetT Ms, |
| MemoryManagerPtrT MemMgr, |
| SymbolResolverPtrT Resolver) { |
| return ModuleSetList.insert( |
| ModuleSetList.end(), |
| EmissionDeferredSet::create(BaseLayer, std::move(Ms), std::move(MemMgr), |
| std::move(Resolver))); |
| } |
| |
| /// @brief Remove the module set represented by the given handle. |
| /// |
| /// This method will free the memory associated with the given module set, |
| /// both in this layer, and the base layer. |
| void removeModuleSet(ModuleSetHandleT H) { |
| (*H)->removeModulesFromBaseLayer(BaseLayer); |
| ModuleSetList.erase(H); |
| } |
| |
| /// @brief Search for the given named symbol. |
| /// @param Name The name of the symbol to search for. |
| /// @param ExportedSymbolsOnly If true, search only for exported symbols. |
| /// @return A handle for the given named symbol, if it exists. |
| JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { |
| // Look for the symbol among existing definitions. |
| if (auto Symbol = BaseLayer.findSymbol(Name, ExportedSymbolsOnly)) |
| return Symbol; |
| |
| // If not found then search the deferred sets. If any of these contain a |
| // definition of 'Name' then they will return a JITSymbol that will emit |
| // the corresponding module when the symbol address is requested. |
| for (auto &DeferredSet : ModuleSetList) |
| if (auto Symbol = DeferredSet->find(Name, ExportedSymbolsOnly, BaseLayer)) |
| return Symbol; |
| |
| // If no definition found anywhere return a null symbol. |
| return nullptr; |
| } |
| |
| /// @brief Get the address of the given symbol in the context of the set of |
| /// compiled modules represented by the handle H. |
| JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, |
| bool ExportedSymbolsOnly) { |
| return (*H)->find(Name, ExportedSymbolsOnly, BaseLayer); |
| } |
| |
| /// @brief Immediately emit and finalize the moduleOB set represented by the |
| /// given handle. |
| /// @param H Handle for module set to emit/finalize. |
| void emitAndFinalize(ModuleSetHandleT H) { |
| (*H)->emitAndFinalize(BaseLayer); |
| } |
| }; |
| |
| template <typename BaseLayerT> |
| template <typename ModuleSetT, typename MemoryManagerPtrT, |
| typename SymbolResolverPtrT> |
| std::unique_ptr<typename LazyEmittingLayer<BaseLayerT>::EmissionDeferredSet> |
| LazyEmittingLayer<BaseLayerT>::EmissionDeferredSet::create( |
| BaseLayerT &B, ModuleSetT Ms, MemoryManagerPtrT MemMgr, |
| SymbolResolverPtrT Resolver) { |
| typedef EmissionDeferredSetImpl<ModuleSetT, MemoryManagerPtrT, SymbolResolverPtrT> |
| EDS; |
| return llvm::make_unique<EDS>(std::move(Ms), std::move(MemMgr), |
| std::move(Resolver)); |
| } |
| |
| } // end namespace orc |
| } // end namespace llvm |
| |
| #endif // LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H |