diff options
Diffstat (limited to 'include/llvm/ExecutionEngine')
20 files changed, 1850 insertions, 194 deletions
diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index b9c0b61..17de5c7 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -138,10 +138,17 @@ protected: /// getMemoryforGV - Allocate memory for a global variable. virtual char *getMemoryForGV(const GlobalVariable *GV); - static ExecutionEngine *(*MCJITCtor)(std::unique_ptr<Module> M, - std::string *ErrorStr, - RTDyldMemoryManager *MCJMM, - std::unique_ptr<TargetMachine> TM); + static ExecutionEngine *(*MCJITCtor)( + std::unique_ptr<Module> M, + std::string *ErrorStr, + std::unique_ptr<RTDyldMemoryManager> MCJMM, + std::unique_ptr<TargetMachine> TM); + + static ExecutionEngine *(*OrcMCJITReplacementCtor)( + std::string *ErrorStr, + std::unique_ptr<RTDyldMemoryManager> OrcJMM, + std::unique_ptr<TargetMachine> TM); + static ExecutionEngine *(*InterpCtor)(std::unique_ptr<Module> M, std::string *ErrorStr); @@ -463,6 +470,7 @@ public: } protected: + ExecutionEngine() : EEState(*this) {} explicit ExecutionEngine(std::unique_ptr<Module> M); void emitGlobals(); @@ -492,7 +500,7 @@ private: EngineKind::Kind WhichEngine; std::string *ErrorStr; CodeGenOpt::Level OptLevel; - RTDyldMemoryManager *MCJMM; + std::unique_ptr<RTDyldMemoryManager> MCJMM; TargetOptions Options; Reloc::Model RelocModel; CodeModel::Model CMModel; @@ -500,15 +508,20 @@ private: std::string MCPU; SmallVector<std::string, 4> MAttrs; bool VerifyModules; + bool UseOrcMCJITReplacement; /// InitEngine - Does the common initialization of default options. void InitEngine(); public: + /// Default constructor for EngineBuilder. + EngineBuilder(); + /// Constructor for EngineBuilder. - EngineBuilder(std::unique_ptr<Module> M) : M(std::move(M)) { - InitEngine(); - } + EngineBuilder(std::unique_ptr<Module> M); + + // Out-of-line since we don't have the def'n of RTDyldMemoryManager here. + ~EngineBuilder(); /// setEngineKind - Controls whether the user wants the interpreter, the JIT, /// or whichever engine works. This option defaults to EngineKind::Either. @@ -523,10 +536,7 @@ public: /// to create anything other than MCJIT will cause a runtime error. If create() /// is called and is successful, the created engine takes ownership of the /// memory manager. This option defaults to NULL. - EngineBuilder &setMCJITMemoryManager(RTDyldMemoryManager *mcjmm) { - MCJMM = mcjmm; - return *this; - } + EngineBuilder &setMCJITMemoryManager(std::unique_ptr<RTDyldMemoryManager> mcjmm); /// setErrorStr - Set the error string to write to on error. This option /// defaults to NULL. @@ -591,6 +601,11 @@ public: return *this; } + // \brief Use OrcMCJITReplacement instead of MCJIT. Off by default. + void setUseOrcMCJITReplacement(bool UseOrcMCJITReplacement) { + this->UseOrcMCJITReplacement = UseOrcMCJITReplacement; + } + TargetMachine *selectTarget(); /// selectTarget - Pick a target either via -march or by guessing the native diff --git a/include/llvm/ExecutionEngine/JITEventListener.h b/include/llvm/ExecutionEngine/JITEventListener.h index cef3aa2..c3edec8 100644 --- a/include/llvm/ExecutionEngine/JITEventListener.h +++ b/include/llvm/ExecutionEngine/JITEventListener.h @@ -15,6 +15,7 @@ #ifndef LLVM_EXECUTIONENGINE_JITEVENTLISTENER_H #define LLVM_EXECUTIONENGINE_JITEVENTLISTENER_H +#include "RuntimeDyld.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/DebugLoc.h" #include "llvm/Support/DataTypes.h" @@ -25,7 +26,10 @@ class Function; class MachineFunction; class OProfileWrapper; class IntelJITEventsWrapper; -class ObjectImage; + +namespace object { + class ObjectFile; +} /// JITEvent_EmittedFunctionDetails - Helper struct for containing information /// about a generated machine code function. @@ -57,7 +61,7 @@ public: public: JITEventListener() {} - virtual ~JITEventListener(); + virtual ~JITEventListener() {} /// NotifyObjectEmitted - Called after an object has been successfully /// emitted to memory. NotifyFunctionEmitted will not be called for @@ -67,11 +71,15 @@ public: /// The ObjectImage contains the generated object image /// with section headers updated to reflect the address at which sections /// were loaded and with relocations performed in-place on debug sections. - virtual void NotifyObjectEmitted(const ObjectImage &Obj) {} + virtual void NotifyObjectEmitted(const object::ObjectFile &Obj, + const RuntimeDyld::LoadedObjectInfo &L) {} /// NotifyFreeingObject - Called just before the memory associated with /// a previously emitted object is released. - virtual void NotifyFreeingObject(const ObjectImage &Obj) {} + virtual void NotifyFreeingObject(const object::ObjectFile &Obj) {} + + // Get a pointe to the GDB debugger registration listener. + static JITEventListener *createGDBRegistrationListener(); #if LLVM_USE_INTEL_JITEVENTS // Construct an IntelJITEventListener @@ -105,7 +113,8 @@ public: return nullptr; } #endif // USE_OPROFILE - +private: + virtual void anchor(); }; } // end namespace llvm. diff --git a/include/llvm/ExecutionEngine/ObjectBuffer.h b/include/llvm/ExecutionEngine/ObjectBuffer.h deleted file mode 100644 index ee4820a..0000000 --- a/include/llvm/ExecutionEngine/ObjectBuffer.h +++ /dev/null @@ -1,76 +0,0 @@ -//===---- ObjectBuffer.h - Utility class to wrap object image memory -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares a wrapper class to hold the memory into which an -// object will be generated. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_OBJECTBUFFER_H -#define LLVM_EXECUTIONENGINE_OBJECTBUFFER_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" - -namespace llvm { - -/// This class acts as a container for the memory buffer used during generation -/// and loading of executable objects using MCJIT and RuntimeDyld. The -/// underlying memory for the object will be owned by the ObjectBuffer instance -/// throughout its lifetime. -class ObjectBuffer { - virtual void anchor(); -public: - ObjectBuffer() {} - ObjectBuffer(std::unique_ptr<MemoryBuffer> Buf) : Buffer(std::move(Buf)) {} - virtual ~ObjectBuffer() {} - - MemoryBufferRef getMemBuffer() const { return Buffer->getMemBufferRef(); } - - const char *getBufferStart() const { return Buffer->getBufferStart(); } - size_t getBufferSize() const { return Buffer->getBufferSize(); } - StringRef getBuffer() const { return Buffer->getBuffer(); } - StringRef getBufferIdentifier() const { - return Buffer->getBufferIdentifier(); - } - -protected: - // The memory contained in an ObjectBuffer - std::unique_ptr<MemoryBuffer> Buffer; -}; - -/// This class encapsulates the SmallVector and raw_svector_ostream needed to -/// generate an object using MC code emission while providing a common -/// ObjectBuffer interface for access to the memory once the object has been -/// generated. -class ObjectBufferStream : public ObjectBuffer { - void anchor() override; -public: - ObjectBufferStream() : OS(SV) {} - virtual ~ObjectBufferStream() {} - - raw_ostream &getOStream() { return OS; } - void flush() - { - OS.flush(); - - // Make the data accessible via the ObjectBuffer::Buffer - Buffer = - MemoryBuffer::getMemBuffer(StringRef(SV.data(), SV.size()), "", false); - } - -protected: - SmallVector<char, 4096> SV; // Working buffer into which we JIT. - raw_svector_ostream OS; // streaming wrapper -}; - -} // namespace llvm - -#endif diff --git a/include/llvm/ExecutionEngine/ObjectImage.h b/include/llvm/ExecutionEngine/ObjectImage.h deleted file mode 100644 index dc142bd..0000000 --- a/include/llvm/ExecutionEngine/ObjectImage.h +++ /dev/null @@ -1,76 +0,0 @@ -//===---- ObjectImage.h - Format independent executuable object image -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares a file format independent ObjectImage class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_OBJECTIMAGE_H -#define LLVM_EXECUTIONENGINE_OBJECTIMAGE_H - -#include "llvm/ExecutionEngine/ObjectBuffer.h" -#include "llvm/Object/ObjectFile.h" - -namespace llvm { - - -/// ObjectImage - A container class that represents an ObjectFile that has been -/// or is in the process of being loaded into memory for execution. -class ObjectImage { - ObjectImage() LLVM_DELETED_FUNCTION; - ObjectImage(const ObjectImage &other) LLVM_DELETED_FUNCTION; - virtual void anchor(); - -protected: - std::unique_ptr<ObjectBuffer> Buffer; - -public: - ObjectImage(std::unique_ptr<ObjectBuffer> Input) : Buffer(std::move(Input)) {} - virtual ~ObjectImage() {} - - virtual object::symbol_iterator begin_symbols() const = 0; - virtual object::symbol_iterator end_symbols() const = 0; - iterator_range<object::symbol_iterator> symbols() const { - return iterator_range<object::symbol_iterator>(begin_symbols(), - end_symbols()); - } - - virtual object::section_iterator begin_sections() const = 0; - virtual object::section_iterator end_sections() const = 0; - iterator_range<object::section_iterator> sections() const { - return iterator_range<object::section_iterator>(begin_sections(), - end_sections()); - } - - virtual /* Triple::ArchType */ unsigned getArch() const = 0; - - // Return the name associated with this ObjectImage. - // This is usually the name of the file or MemoryBuffer that the the - // ObjectBuffer was constructed from. - StringRef getImageName() const { return Buffer->getBufferIdentifier(); } - - // Subclasses can override these methods to update the image with loaded - // addresses for sections and common symbols - virtual void updateSectionAddress(const object::SectionRef &Sec, - uint64_t Addr) = 0; - virtual void updateSymbolAddress(const object::SymbolRef &Sym, - uint64_t Addr) = 0; - - virtual StringRef getData() const = 0; - - virtual object::ObjectFile* getObjectFile() const = 0; - - // Subclasses can override these methods to provide JIT debugging support - virtual void registerWithDebugger() = 0; - virtual void deregisterWithDebugger() = 0; -}; - -} // end namespace llvm - -#endif // LLVM_EXECUTIONENGINE_OBJECTIMAGE_H diff --git a/include/llvm/ExecutionEngine/ObjectMemoryBuffer.h b/include/llvm/ExecutionEngine/ObjectMemoryBuffer.h new file mode 100644 index 0000000..b075611 --- /dev/null +++ b/include/llvm/ExecutionEngine/ObjectMemoryBuffer.h @@ -0,0 +1,63 @@ +//===- ObjectMemoryBuffer.h - SmallVector-backed MemoryBuffrer -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares a wrapper class to hold the memory into which an +// object will be generated. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_OBJECTMEMORYBUFFER_H +#define LLVM_EXECUTIONENGINE_OBJECTMEMORYBUFFER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +/// \brief SmallVector-backed MemoryBuffer instance. +/// +/// This class enables efficient construction of MemoryBuffers from SmallVector +/// instances. This is useful for MCJIT and Orc, where object files are streamed +/// into SmallVectors, then inspected using ObjectFile (which takes a +/// MemoryBuffer). +class ObjectMemoryBuffer : public MemoryBuffer { +public: + + /// \brief Construct an ObjectMemoryBuffer from the given SmallVector r-value. + /// + /// FIXME: It'd be nice for this to be a non-templated constructor taking a + /// SmallVectorImpl here instead of a templated one taking a SmallVector<N>, + /// but SmallVector's move-construction/assignment currently only take + /// SmallVectors. If/when that is fixed we can simplify this constructor and + /// the following one. + ObjectMemoryBuffer(SmallVectorImpl<char> &&SV) + : SV(std::move(SV)), BufferName("<in-memory object>") { + init(this->SV.begin(), this->SV.end(), false); + } + + /// \brief Construct a named ObjectMemoryBuffer from the given SmallVector + /// r-value and StringRef. + ObjectMemoryBuffer(SmallVectorImpl<char> &&SV, StringRef Name) + : SV(std::move(SV)), BufferName(Name) { + init(this->SV.begin(), this->SV.end(), false); + } + + const char* getBufferIdentifier() const override { return BufferName.c_str(); } + + BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; } + +private: + SmallVector<char, 0> SV; + std::string BufferName; +}; + +} // namespace llvm + +#endif diff --git a/include/llvm/ExecutionEngine/Orc/CloneSubModule.h b/include/llvm/ExecutionEngine/Orc/CloneSubModule.h new file mode 100644 index 0000000..1bd3955 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/CloneSubModule.h @@ -0,0 +1,60 @@ +//===-- CloneSubModule.h - Utilities for extracting sub-modules -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Contains utilities for extracting sub-modules. Useful for breaking up modules +// for lazy jitting. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_CLONESUBMODULE_H +#define LLVM_EXECUTIONENGINE_ORC_CLONESUBMODULE_H + +#include "llvm/ADT/DenseSet.h" +#include "llvm/Transforms/Utils/ValueMapper.h" +#include <functional> + +namespace llvm { + +class Function; +class GlobalVariable; +class Module; + +namespace orc { + +/// @brief Functor type for describing how CloneSubModule should mutate a +/// GlobalVariable. +typedef std::function<void(GlobalVariable &, const GlobalVariable &, + ValueToValueMapTy &)> HandleGlobalVariableFtor; + +/// @brief Functor type for describing how CloneSubModule should mutate a +/// Function. +typedef std::function<void(Function &, const Function &, ValueToValueMapTy &)> + HandleFunctionFtor; + +/// @brief Copies the initializer from Orig to New. +/// +/// Type is suitable for implicit conversion to a HandleGlobalVariableFtor. +void copyGVInitializer(GlobalVariable &New, const GlobalVariable &Orig, + ValueToValueMapTy &VMap); + +/// @brief Copies the body of Orig to New. +/// +/// Type is suitable for implicit conversion to a HandleFunctionFtor. +void copyFunctionBody(Function &New, const Function &Orig, + ValueToValueMapTy &VMap); + +/// @brief Clone a subset of the module Src into Dst. +void CloneSubModule(Module &Dst, const Module &Src, + HandleGlobalVariableFtor HandleGlobalVariable, + HandleFunctionFtor HandleFunction, bool KeepInlineAsm); + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_CLONESUBMODULE_H diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h new file mode 100644 index 0000000..0e218e2 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -0,0 +1,355 @@ +//===- CompileOnDemandLayer.h - Compile each function on demand -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// JIT layer for breaking up modules and inserting callbacks to allow +// individual functions to be compiled on demand. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H +#define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H + +#include "IndirectionUtils.h" +#include "LookasideRTDyldMM.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include <list> + +namespace llvm { +namespace orc { + +/// @brief Compile-on-demand layer. +/// +/// Modules added to this layer have their calls indirected, and are then +/// broken up into a set of single-function modules, each of which is added +/// to the layer below in a singleton set. The lower layer can be any layer that +/// accepts IR module sets. +/// +/// It is expected that this layer will frequently be used on top of a +/// LazyEmittingLayer. The combination of the two ensures that each function is +/// compiled only when it is first called. +template <typename BaseLayerT, typename CompileCallbackMgrT> +class CompileOnDemandLayer { +public: + /// @brief Lookup helper that provides compatibility with the classic + /// static-compilation symbol resolution process. + /// + /// The CompileOnDemand (COD) layer splits modules up into multiple + /// sub-modules, each held in its own llvm::Module instance, in order to + /// support lazy compilation. When a module that contains private symbols is + /// broken up symbol linkage changes may be required to enable access to + /// "private" data that now resides in a different llvm::Module instance. To + /// retain expected symbol resolution behavior for clients of the COD layer, + /// the CODScopedLookup class uses a two-tiered lookup system to resolve + /// symbols. Lookup first scans sibling modules that were split from the same + /// original module (logical-module scoped lookup), then scans all other + /// modules that have been added to the lookup scope (logical-dylib scoped + /// lookup). + class CODScopedLookup { + private: + typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT; + typedef std::vector<BaseLayerModuleSetHandleT> SiblingHandlesList; + typedef std::list<SiblingHandlesList> PseudoDylibModuleSetHandlesList; + + public: + /// @brief Handle for a logical module. + typedef typename PseudoDylibModuleSetHandlesList::iterator LMHandle; + + /// @brief Construct a scoped lookup. + CODScopedLookup(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {} + + /// @brief Start a new context for a single logical module. + LMHandle createLogicalModule() { + Handles.push_back(SiblingHandlesList()); + return std::prev(Handles.end()); + } + + /// @brief Add a concrete Module's handle to the given logical Module's + /// lookup scope. + void addToLogicalModule(LMHandle LMH, BaseLayerModuleSetHandleT H) { + LMH->push_back(H); + } + + /// @brief Remove a logical Module from the CODScopedLookup entirely. + void removeLogicalModule(LMHandle LMH) { Handles.erase(LMH); } + + /// @brief Look up a symbol in this context. + JITSymbol findSymbol(LMHandle LMH, const std::string &Name) { + if (auto Symbol = findSymbolIn(LMH, Name)) + return Symbol; + + for (auto I = Handles.begin(), E = Handles.end(); I != E; ++I) + if (I != LMH) + if (auto Symbol = findSymbolIn(I, Name)) + return Symbol; + + return nullptr; + } + + private: + + JITSymbol findSymbolIn(LMHandle LMH, const std::string &Name) { + for (auto H : *LMH) + if (auto Symbol = BaseLayer.findSymbolIn(H, Name, false)) + return Symbol; + return nullptr; + } + + BaseLayerT &BaseLayer; + PseudoDylibModuleSetHandlesList Handles; + }; + +private: + typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT; + typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT; + + struct ModuleSetInfo { + // Symbol lookup - just one for the whole module set. + std::shared_ptr<CODScopedLookup> Lookup; + + // Logical module handles. + std::vector<typename CODScopedLookup::LMHandle> LMHandles; + + // List of vectors of module set handles: + // One vector per logical module - each vector holds the handles for the + // exploded modules for that logical module in the base layer. + BaseLayerModuleSetHandleListT BaseLayerModuleSetHandles; + + ModuleSetInfo(std::shared_ptr<CODScopedLookup> Lookup) + : Lookup(std::move(Lookup)) {} + + void releaseResources(BaseLayerT &BaseLayer) { + for (auto LMH : LMHandles) + Lookup->removeLogicalModule(LMH); + for (auto H : BaseLayerModuleSetHandles) + BaseLayer.removeModuleSet(H); + } + }; + + typedef std::list<ModuleSetInfo> ModuleSetInfoListT; + +public: + /// @brief Handle to a set of loaded modules. + typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT; + + // @brief Fallback lookup functor. + typedef std::function<uint64_t(const std::string &)> LookupFtor; + + /// @brief Construct a compile-on-demand layer instance. + CompileOnDemandLayer(BaseLayerT &BaseLayer, LLVMContext &Context) + : BaseLayer(BaseLayer), + CompileCallbackMgr(BaseLayer, Context, 0, 64) {} + + /// @brief Add a module to the compile-on-demand layer. + template <typename ModuleSetT> + ModuleSetHandleT addModuleSet(ModuleSetT Ms, + LookupFtor FallbackLookup = nullptr) { + + // If the user didn't supply a fallback lookup then just use + // getSymbolAddress. + if (!FallbackLookup) + FallbackLookup = [=](const std::string &Name) { + return findSymbol(Name, true).getAddress(); + }; + + // Create a lookup context and ModuleSetInfo for this module set. + // For the purposes of symbol resolution the set Ms will be treated as if + // the modules it contained had been linked together as a dylib. + auto DylibLookup = std::make_shared<CODScopedLookup>(BaseLayer); + ModuleSetHandleT H = + ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup)); + ModuleSetInfo &MSI = ModuleSetInfos.back(); + + // Process each of the modules in this module set. + for (auto &M : Ms) + partitionAndAdd(*M, MSI, FallbackLookup); + + return H; + } + + /// @brief Remove the module represented by the given handle. + /// + /// This will remove all modules in the layers below that were derived from + /// the module represented by H. + void removeModuleSet(ModuleSetHandleT H) { + H->releaseResources(BaseLayer); + ModuleSetInfos.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(StringRef Name, bool ExportedSymbolsOnly) { + return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); + } + + /// @brief Get the address of a symbol provided by this layer, or some layer + /// below this one. + JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, + bool ExportedSymbolsOnly) { + BaseLayerModuleSetHandleListT &BaseLayerHandles = H->second; + for (auto &BH : BaseLayerHandles) { + if (auto Symbol = BaseLayer.findSymbolIn(BH, Name, ExportedSymbolsOnly)) + return Symbol; + } + return nullptr; + } + +private: + + void partitionAndAdd(Module &M, ModuleSetInfo &MSI, + LookupFtor FallbackLookup) { + const char *AddrSuffix = "$orc_addr"; + const char *BodySuffix = "$orc_body"; + + // We're going to break M up into a bunch of sub-modules, but we want + // internal linkage symbols to still resolve sensibly. CODScopedLookup + // provides the "logical module" concept to make this work, so create a + // new logical module for M. + auto DylibLookup = MSI.Lookup; + auto LogicalModule = DylibLookup->createLogicalModule(); + MSI.LMHandles.push_back(LogicalModule); + + // Partition M into a "globals and stubs" module, a "common symbols" module, + // and a list of single-function modules. + auto PartitionedModule = fullyPartition(M); + auto StubsModule = std::move(PartitionedModule.GlobalVars); + auto CommonsModule = std::move(PartitionedModule.Commons); + auto FunctionModules = std::move(PartitionedModule.Functions); + + // Emit the commons stright away. + auto CommonHandle = addModule(std::move(CommonsModule), MSI, LogicalModule, + FallbackLookup); + BaseLayer.emitAndFinalize(CommonHandle); + + // Map of definition names to callback-info data structures. We'll use + // this to build the compile actions for the stubs below. + typedef std::map<std::string, + typename CompileCallbackMgrT::CompileCallbackInfo> + StubInfoMap; + StubInfoMap StubInfos; + + // Now we need to take each of the extracted Modules and add them to + // base layer. Each Module will be added individually to make sure they + // can be compiled separately, and each will get its own lookaside + // memory manager that will resolve within this logical module first. + for (auto &SubM : FunctionModules) { + + // Keep track of the stubs we create for this module so that we can set + // their compile actions. + std::vector<typename StubInfoMap::iterator> NewStubInfos; + + // Search for function definitions and insert stubs into the stubs + // module. + for (auto &F : *SubM) { + if (F.isDeclaration()) + continue; + + std::string Name = F.getName(); + Function *Proto = StubsModule->getFunction(Name); + assert(Proto && "Failed to clone function decl into stubs module."); + auto CallbackInfo = + CompileCallbackMgr.getCompileCallback(*Proto->getFunctionType()); + GlobalVariable *FunctionBodyPointer = + createImplPointer(*Proto, Name + AddrSuffix, + CallbackInfo.getAddress()); + makeStub(*Proto, *FunctionBodyPointer); + + F.setName(Name + BodySuffix); + F.setVisibility(GlobalValue::HiddenVisibility); + + auto KV = std::make_pair(std::move(Name), std::move(CallbackInfo)); + NewStubInfos.push_back(StubInfos.insert(StubInfos.begin(), KV)); + } + + auto H = addModule(std::move(SubM), MSI, LogicalModule, FallbackLookup); + + // Set the compile actions for this module: + for (auto &KVPair : NewStubInfos) { + std::string BodyName = Mangle(KVPair->first + BodySuffix, + *M.getDataLayout()); + auto &CCInfo = KVPair->second; + CCInfo.setCompileAction( + [=](){ + return BaseLayer.findSymbolIn(H, BodyName, false).getAddress(); + }); + } + + } + + // Ok - we've processed all the partitioned modules. Now add the + // stubs/globals module and set the update actions. + auto StubsH = + addModule(std::move(StubsModule), MSI, LogicalModule, FallbackLookup); + + for (auto &KVPair : StubInfos) { + std::string AddrName = Mangle(KVPair.first + AddrSuffix, + *M.getDataLayout()); + auto &CCInfo = KVPair.second; + CCInfo.setUpdateAction( + CompileCallbackMgr.getLocalFPUpdater(StubsH, AddrName)); + } + } + + // Add the given Module to the base layer using a memory manager that will + // perform the appropriate scoped lookup (i.e. will look first with in the + // module from which it was extracted, then into the set to which that module + // belonged, and finally externally). + BaseLayerModuleSetHandleT addModule( + std::unique_ptr<Module> M, + ModuleSetInfo &MSI, + typename CODScopedLookup::LMHandle LogicalModule, + LookupFtor FallbackLookup) { + + // Add this module to the JIT with a memory manager that uses the + // DylibLookup to resolve symbols. + std::vector<std::unique_ptr<Module>> MSet; + MSet.push_back(std::move(M)); + + auto DylibLookup = MSI.Lookup; + auto MM = + createLookasideRTDyldMM<SectionMemoryManager>( + [=](const std::string &Name) { + if (auto Symbol = DylibLookup->findSymbol(LogicalModule, Name)) + return Symbol.getAddress(); + return FallbackLookup(Name); + }, + [=](const std::string &Name) { + return DylibLookup->findSymbol(LogicalModule, Name).getAddress(); + }); + + BaseLayerModuleSetHandleT H = + BaseLayer.addModuleSet(std::move(MSet), std::move(MM)); + // Add this module to the logical module lookup. + DylibLookup->addToLogicalModule(LogicalModule, H); + MSI.BaseLayerModuleSetHandles.push_back(H); + + return H; + } + + static std::string Mangle(StringRef Name, const DataLayout &DL) { + Mangler M(&DL); + std::string MangledName; + { + raw_string_ostream MangledNameStream(MangledName); + M.getNameWithPrefix(MangledNameStream, Name); + } + return MangledName; + } + + BaseLayerT &BaseLayer; + CompileCallbackMgrT CompileCallbackMgr; + ModuleSetInfoListT ModuleSetInfos; +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H diff --git a/include/llvm/ExecutionEngine/Orc/CompileUtils.h b/include/llvm/ExecutionEngine/Orc/CompileUtils.h new file mode 100644 index 0000000..49a1fba --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/CompileUtils.h @@ -0,0 +1,62 @@ +//===-- CompileUtils.h - Utilities for compiling IR in the JIT --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Contains utilities for compiling IR to object files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H +#define LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H + +#include "llvm/ExecutionEngine/ObjectMemoryBuffer.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +namespace orc { + +/// @brief Simple compile functor: Takes a single IR module and returns an +/// ObjectFile. +class SimpleCompiler { +public: + /// @brief Construct a simple compile functor with the given target. + SimpleCompiler(TargetMachine &TM) : TM(TM) {} + + /// @brief Compile a Module to an ObjectFile. + object::OwningBinary<object::ObjectFile> operator()(Module &M) const { + SmallVector<char, 0> ObjBufferSV; + raw_svector_ostream ObjStream(ObjBufferSV); + + legacy::PassManager PM; + MCContext *Ctx; + if (TM.addPassesToEmitMC(PM, Ctx, ObjStream)) + llvm_unreachable("Target does not support MC emission."); + PM.run(M); + ObjStream.flush(); + std::unique_ptr<MemoryBuffer> ObjBuffer( + new ObjectMemoryBuffer(std::move(ObjBufferSV))); + ErrorOr<std::unique_ptr<object::ObjectFile>> Obj = + object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); + // TODO: Actually report errors helpfully. + typedef object::OwningBinary<object::ObjectFile> OwningObj; + if (Obj) + return OwningObj(std::move(*Obj), std::move(ObjBuffer)); + return OwningObj(nullptr, nullptr); + } + +private: + TargetMachine &TM; +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H diff --git a/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h new file mode 100644 index 0000000..6a47622 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h @@ -0,0 +1,146 @@ +//===------ IRCompileLayer.h -- Eagerly compile IR for JIT ------*- 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 basic, eagerly compiling layer of the JIT. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_IRCOMPILELAYER_H +#define LLVM_EXECUTIONENGINE_ORC_IRCOMPILELAYER_H + +#include "JITSymbol.h" +#include "llvm/ExecutionEngine/ObjectCache.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/Object/ObjectFile.h" +#include <memory> + +namespace llvm { +namespace orc { + +/// @brief Eager IR compiling layer. +/// +/// This layer accepts sets of LLVM IR Modules (via addModuleSet). It +/// immediately compiles each IR module to an object file (each IR Module is +/// compiled separately). The resulting set of object files is then added to +/// the layer below, which must implement the object layer concept. +template <typename BaseLayerT> class IRCompileLayer { +public: + typedef std::function<object::OwningBinary<object::ObjectFile>(Module &)> + CompileFtor; + +private: + typedef typename BaseLayerT::ObjSetHandleT ObjSetHandleT; + + typedef std::vector<std::unique_ptr<object::ObjectFile>> OwningObjectVec; + typedef std::vector<std::unique_ptr<MemoryBuffer>> OwningBufferVec; + +public: + /// @brief Handle to a set of compiled modules. + typedef ObjSetHandleT ModuleSetHandleT; + + /// @brief Construct an IRCompileLayer with the given BaseLayer, which must + /// implement the ObjectLayer concept. + IRCompileLayer(BaseLayerT &BaseLayer, CompileFtor Compile) + : BaseLayer(BaseLayer), Compile(std::move(Compile)), ObjCache(nullptr) {} + + /// @brief Set an ObjectCache to query before compiling. + void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; } + + /// @brief Compile each module in the given module set, then then add the + /// resulting set of objects to the base layer, along with the memory + // manager MM. + /// + /// @return A handle for the added modules. + template <typename ModuleSetT> + ModuleSetHandleT addModuleSet(ModuleSetT Ms, + std::unique_ptr<RTDyldMemoryManager> MM) { + OwningObjectVec Objects; + OwningBufferVec Buffers; + + for (const auto &M : Ms) { + std::unique_ptr<object::ObjectFile> Object; + std::unique_ptr<MemoryBuffer> Buffer; + + if (ObjCache) + std::tie(Object, Buffer) = tryToLoadFromObjectCache(*M).takeBinary(); + + if (!Object) { + std::tie(Object, Buffer) = Compile(*M).takeBinary(); + if (ObjCache) + ObjCache->notifyObjectCompiled(&*M, Buffer->getMemBufferRef()); + } + + Objects.push_back(std::move(Object)); + Buffers.push_back(std::move(Buffer)); + } + + ModuleSetHandleT H = + BaseLayer.addObjectSet(Objects, std::move(MM)); + + BaseLayer.takeOwnershipOfBuffers(H, std::move(Buffers)); + + return H; + } + + /// @brief Remove the module set associated with the handle H. + void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeObjectSet(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) { + return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); + } + + /// @brief Get the address of the given symbol in the context of the set of + /// compiled modules represented by the handle H. This call is + /// forwarded to the base layer's implementation. + /// @param H The handle for the module set to search in. + /// @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 is found in the + /// given module set. + JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, + bool ExportedSymbolsOnly) { + return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly); + } + + /// @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) { + BaseLayer.emitAndFinalize(H); + } + +private: + object::OwningBinary<object::ObjectFile> + tryToLoadFromObjectCache(const Module &M) { + std::unique_ptr<MemoryBuffer> ObjBuffer = ObjCache->getObject(&M); + if (!ObjBuffer) + return object::OwningBinary<object::ObjectFile>(); + + ErrorOr<std::unique_ptr<object::ObjectFile>> Obj = + object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); + if (!Obj) + return object::OwningBinary<object::ObjectFile>(); + + return object::OwningBinary<object::ObjectFile>(std::move(*Obj), + std::move(ObjBuffer)); + } + + BaseLayerT &BaseLayer; + CompileFtor Compile; + ObjectCache *ObjCache; +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_IRCOMPILINGLAYER_H diff --git a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h new file mode 100644 index 0000000..e9d3d34 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h @@ -0,0 +1,246 @@ +//===-- IndirectionUtils.h - Utilities for adding indirections --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Contains utilities for adding indirections and breaking up modules. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H +#define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H + +#include "JITSymbol.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include <sstream> + +namespace llvm { +namespace orc { + +/// @brief Base class for JITLayer independent aspects of +/// JITCompileCallbackManager. +template <typename TargetT> +class JITCompileCallbackManagerBase { +public: + + /// @brief Construct a JITCompileCallbackManagerBase. + /// @param ErrorHandlerAddress The address of an error handler in the target + /// process to be used if a compile callback fails. + /// @param NumTrampolinesPerBlock Number of trampolines to emit if there is no + /// available trampoline when getCompileCallback is + /// called. + JITCompileCallbackManagerBase(TargetAddress ErrorHandlerAddress, + unsigned NumTrampolinesPerBlock) + : ErrorHandlerAddress(ErrorHandlerAddress), + NumTrampolinesPerBlock(NumTrampolinesPerBlock) {} + + /// @brief Execute the callback for the given trampoline id. Called by the JIT + /// to compile functions on demand. + TargetAddress executeCompileCallback(TargetAddress TrampolineID) { + typename TrampolineMapT::iterator I = ActiveTrampolines.find(TrampolineID); + // FIXME: Also raise an error in the Orc error-handler when we finally have + // one. + if (I == ActiveTrampolines.end()) + return ErrorHandlerAddress; + + // Found a callback handler. Yank this trampoline out of the active list and + // put it back in the available trampolines list, then try to run the + // handler's compile and update actions. + // Moving the trampoline ID back to the available list first means there's at + // least one available trampoline if the compile action triggers a request for + // a new one. + AvailableTrampolines.push_back(I->first - TargetT::CallSize); + auto CallbackHandler = std::move(I->second); + ActiveTrampolines.erase(I); + + if (auto Addr = CallbackHandler.Compile()) { + CallbackHandler.Update(Addr); + return Addr; + } + return ErrorHandlerAddress; + } + +protected: + + typedef std::function<TargetAddress()> CompileFtorT; + typedef std::function<void(TargetAddress)> UpdateFtorT; + + struct CallbackHandler { + CompileFtorT Compile; + UpdateFtorT Update; + }; + + TargetAddress ErrorHandlerAddress; + unsigned NumTrampolinesPerBlock; + + typedef std::map<TargetAddress, CallbackHandler> TrampolineMapT; + TrampolineMapT ActiveTrampolines; + std::vector<TargetAddress> AvailableTrampolines; +}; + +/// @brief Manage compile callbacks. +template <typename JITLayerT, typename TargetT> +class JITCompileCallbackManager : + public JITCompileCallbackManagerBase<TargetT> { +public: + + typedef typename JITCompileCallbackManagerBase<TargetT>::CompileFtorT + CompileFtorT; + typedef typename JITCompileCallbackManagerBase<TargetT>::UpdateFtorT + UpdateFtorT; + + /// @brief Construct a JITCompileCallbackManager. + /// @param JIT JIT layer to emit callback trampolines, etc. into. + /// @param Context LLVMContext to use for trampoline & resolve block modules. + /// @param ErrorHandlerAddress The address of an error handler in the target + /// process to be used if a compile callback fails. + /// @param NumTrampolinesPerBlock Number of trampolines to allocate whenever + /// there is no existing callback trampoline. + /// (Trampolines are allocated in blocks for + /// efficiency.) + JITCompileCallbackManager(JITLayerT &JIT, LLVMContext &Context, + TargetAddress ErrorHandlerAddress, + unsigned NumTrampolinesPerBlock) + : JITCompileCallbackManagerBase<TargetT>(ErrorHandlerAddress, + NumTrampolinesPerBlock), + JIT(JIT) { + emitResolverBlock(Context); + } + + /// @brief Handle to a newly created compile callback. Can be used to get an + /// IR constant representing the address of the trampoline, and to set + /// the compile and update actions for the callback. + class CompileCallbackInfo { + public: + CompileCallbackInfo(Constant *Addr, CompileFtorT &Compile, + UpdateFtorT &Update) + : Addr(Addr), Compile(Compile), Update(Update) {} + + Constant* getAddress() const { return Addr; } + void setCompileAction(CompileFtorT Compile) { + this->Compile = std::move(Compile); + } + void setUpdateAction(UpdateFtorT Update) { + this->Update = std::move(Update); + } + private: + Constant *Addr; + CompileFtorT &Compile; + UpdateFtorT &Update; + }; + + /// @brief Get/create a compile callback with the given signature. + CompileCallbackInfo getCompileCallback(FunctionType &FT) { + TargetAddress TrampolineAddr = getAvailableTrampolineAddr(FT.getContext()); + auto &CallbackHandler = + this->ActiveTrampolines[TrampolineAddr + TargetT::CallSize]; + Constant *AddrIntVal = + ConstantInt::get(Type::getInt64Ty(FT.getContext()), TrampolineAddr); + Constant *AddrPtrVal = + ConstantExpr::getCast(Instruction::IntToPtr, AddrIntVal, + PointerType::get(&FT, 0)); + + return CompileCallbackInfo(AddrPtrVal, CallbackHandler.Compile, + CallbackHandler.Update); + } + + /// @brief Get a functor for updating the value of a named function pointer. + UpdateFtorT getLocalFPUpdater(typename JITLayerT::ModuleSetHandleT H, + std::string Name) { + // FIXME: Move-capture Name once we can use C++14. + return [=](TargetAddress Addr) { + auto FPSym = JIT.findSymbolIn(H, Name, true); + assert(FPSym && "Cannot find function pointer to update."); + void *FPAddr = reinterpret_cast<void*>( + static_cast<uintptr_t>(FPSym.getAddress())); + memcpy(FPAddr, &Addr, sizeof(uintptr_t)); + }; + } + +private: + + std::vector<std::unique_ptr<Module>> + SingletonSet(std::unique_ptr<Module> M) { + std::vector<std::unique_ptr<Module>> Ms; + Ms.push_back(std::move(M)); + return Ms; + } + + void emitResolverBlock(LLVMContext &Context) { + std::unique_ptr<Module> M(new Module("resolver_block_module", + Context)); + TargetT::insertResolverBlock(*M, *this); + auto H = JIT.addModuleSet(SingletonSet(std::move(M)), nullptr); + JIT.emitAndFinalize(H); + auto ResolverBlockSymbol = + JIT.findSymbolIn(H, TargetT::ResolverBlockName, false); + assert(ResolverBlockSymbol && "Failed to insert resolver block"); + ResolverBlockAddr = ResolverBlockSymbol.getAddress(); + } + + TargetAddress getAvailableTrampolineAddr(LLVMContext &Context) { + if (this->AvailableTrampolines.empty()) + grow(Context); + assert(!this->AvailableTrampolines.empty() && + "Failed to grow available trampolines."); + TargetAddress TrampolineAddr = this->AvailableTrampolines.back(); + this->AvailableTrampolines.pop_back(); + return TrampolineAddr; + } + + void grow(LLVMContext &Context) { + assert(this->AvailableTrampolines.empty() && "Growing prematurely?"); + std::unique_ptr<Module> M(new Module("trampoline_block", Context)); + auto GetLabelName = + TargetT::insertCompileCallbackTrampolines(*M, ResolverBlockAddr, + this->NumTrampolinesPerBlock, + this->ActiveTrampolines.size()); + auto H = JIT.addModuleSet(SingletonSet(std::move(M)), nullptr); + JIT.emitAndFinalize(H); + for (unsigned I = 0; I < this->NumTrampolinesPerBlock; ++I) { + std::string Name = GetLabelName(I); + auto TrampolineSymbol = JIT.findSymbolIn(H, Name, false); + assert(TrampolineSymbol && "Failed to emit trampoline."); + this->AvailableTrampolines.push_back(TrampolineSymbol.getAddress()); + } + } + + JITLayerT &JIT; + TargetAddress ResolverBlockAddr; +}; + +GlobalVariable* createImplPointer(Function &F, const Twine &Name, + Constant *Initializer); + +void makeStub(Function &F, GlobalVariable &ImplPointer); + +typedef std::map<Module*, DenseSet<const GlobalValue*>> ModulePartitionMap; + +void partition(Module &M, const ModulePartitionMap &PMap); + +/// @brief Struct for trivial "complete" partitioning of a module. +class FullyPartitionedModule { +public: + std::unique_ptr<Module> GlobalVars; + std::unique_ptr<Module> Commons; + std::vector<std::unique_ptr<Module>> Functions; + + FullyPartitionedModule() = default; + FullyPartitionedModule(FullyPartitionedModule &&S) + : GlobalVars(std::move(S.GlobalVars)), Commons(std::move(S.Commons)), + Functions(std::move(S.Functions)) {} +}; + +FullyPartitionedModule fullyPartition(Module &M); + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H diff --git a/include/llvm/ExecutionEngine/Orc/JITSymbol.h b/include/llvm/ExecutionEngine/Orc/JITSymbol.h new file mode 100644 index 0000000..a670222 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/JITSymbol.h @@ -0,0 +1,74 @@ +//===----------- JITSymbol.h - JIT symbol abstraction -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Abstraction for target process addresses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_JITSYMBOL_H +#define LLVM_EXECUTIONENGINE_ORC_JITSYMBOL_H + +#include "llvm/Support/DataTypes.h" +#include <cassert> +#include <functional> + +namespace llvm { +namespace orc { + +/// @brief Represents an address in the target process's address space. +typedef uint64_t TargetAddress; + +/// @brief Represents a symbol in the JIT. +class JITSymbol { +public: + typedef std::function<TargetAddress()> GetAddressFtor; + + /// @brief Create a 'null' symbol that represents failure to find a symbol + /// definition. + JITSymbol(std::nullptr_t) : CachedAddr(0) {} + + /// @brief Create a symbol for a definition with a known address. + JITSymbol(TargetAddress Addr) + : CachedAddr(Addr) {} + + /// @brief Create a symbol for a definition that doesn't have a known address + /// yet. + /// @param GetAddress A functor to materialize a definition (fixing the + /// address) on demand. + /// + /// This constructor allows a JIT layer to provide a reference to a symbol + /// definition without actually materializing the definition up front. The + /// user can materialize the definition at any time by calling the getAddress + /// method. + JITSymbol(GetAddressFtor GetAddress) + : CachedAddr(0), GetAddress(std::move(GetAddress)) {} + + /// @brief Returns true if the symbol exists, false otherwise. + explicit operator bool() const { return CachedAddr || GetAddress; } + + /// @brief Get the address of the symbol in the target address space. Returns + /// '0' if the symbol does not exist. + TargetAddress getAddress() { + if (GetAddress) { + CachedAddr = GetAddress(); + assert(CachedAddr && "Symbol could not be materialized."); + GetAddress = nullptr; + } + return CachedAddr; + } + +private: + TargetAddress CachedAddr; + GetAddressFtor GetAddress; +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_JITSYMBOL_H diff --git a/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h new file mode 100644 index 0000000..2a94abe --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h @@ -0,0 +1,283 @@ +//===- 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 "JITSymbol.h" +#include "LookasideRTDyldMM.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/ADT/StringMap.h" +#include <list> + +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() : EmitState(NotEmitted) {} + virtual ~EmissionDeferredSet() {} + + JITSymbol find(StringRef Name, bool ExportedSymbolsOnly, BaseLayerT &B) { + switch (EmitState) { + case NotEmitted: + if (provides(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; + return JITSymbol( + [this, ExportedSymbolsOnly, PName, &B]() -> TargetAddress { + if (this->EmitState == Emitting) + return 0; + else if (this->EmitState == NotEmitted) { + this->EmitState = Emitting; + Handle = this->emitToBaseLayer(B); + this->EmitState = Emitted; + } + return B.findSymbolIn(Handle, PName, ExportedSymbolsOnly) + .getAddress(); + }); + } else + return nullptr; + case Emitting: + // Calling "emit" can trigger external symbol lookup (e.g. to check for + // pre-existing definitions of common-symbol), but it will never find in + // this module that it would not have found already, so return null from + // 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> + static std::unique_ptr<EmissionDeferredSet> + create(BaseLayerT &B, ModuleSetT Ms, + std::unique_ptr<RTDyldMemoryManager> MM); + + protected: + virtual bool provides(StringRef Name, bool ExportedSymbolsOnly) const = 0; + virtual BaseLayerHandleT emitToBaseLayer(BaseLayerT &BaseLayer) = 0; + + private: + enum { NotEmitted, Emitting, Emitted } EmitState; + BaseLayerHandleT Handle; + }; + + template <typename ModuleSetT> + class EmissionDeferredSetImpl : public EmissionDeferredSet { + public: + EmissionDeferredSetImpl(ModuleSetT Ms, + std::unique_ptr<RTDyldMemoryManager> MM) + : Ms(std::move(Ms)), MM(std::move(MM)) {} + + protected: + + 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. + MangledNames.reset(); + return BaseLayer.addModuleSet(std::move(Ms), std::move(MM)); + } + + bool provides(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 (MangledNames) { + auto VI = MangledNames->find(Name); + if (VI == MangledNames->end()) + return false; + return !ExportedSymbolsOnly || VI->second; + } + + // 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. + buildMangledNames(Name, ExportedSymbolsOnly); + if (!MangledNames) + return true; + return false; + } + + private: + // If the mangled name of the given GlobalValue matches the given search + // name (and its visibility conforms to the ExportedSymbolsOnly flag) then + // just return 'true'. Otherwise, add the mangled name to the Names map and + // return 'false'. + bool addGlobalValue(StringMap<bool> &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 false; + + // 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 true; + + // Otherwise add this to the map for later. + Names[MangledName] = GV.hasDefaultVisibility(); + return false; + } + + // Build the MangledNames map. Bails out early (with MangledNames left set + // to nullptr) if the given SearchName is found while building the map. + void buildMangledNames(StringRef SearchName, + bool ExportedSymbolsOnly) const { + assert(!MangledNames && "Mangled names map already exists?"); + + auto Names = llvm::make_unique<StringMap<bool>>(); + + for (const auto &M : Ms) { + Mangler Mang(M->getDataLayout()); + + for (const auto &GV : M->globals()) + if (addGlobalValue(*Names, GV, Mang, SearchName, ExportedSymbolsOnly)) + return; + + for (const auto &F : *M) + if (addGlobalValue(*Names, F, Mang, SearchName, ExportedSymbolsOnly)) + return; + } + + MangledNames = std::move(Names); + } + + ModuleSetT Ms; + std::unique_ptr<RTDyldMemoryManager> MM; + mutable std::unique_ptr<StringMap<bool>> MangledNames; + }; + + 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> + ModuleSetHandleT addModuleSet(ModuleSetT Ms, + std::unique_ptr<RTDyldMemoryManager> MM) { + return ModuleSetList.insert( + ModuleSetList.end(), + EmissionDeferredSet::create(BaseLayer, std::move(Ms), std::move(MM))); + } + + /// @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> +std::unique_ptr<typename LazyEmittingLayer<BaseLayerT>::EmissionDeferredSet> +LazyEmittingLayer<BaseLayerT>::EmissionDeferredSet::create( + BaseLayerT &B, ModuleSetT Ms, std::unique_ptr<RTDyldMemoryManager> MM) { + return llvm::make_unique<EmissionDeferredSetImpl<ModuleSetT>>(std::move(Ms), + std::move(MM)); +} + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_LAZYEMITTINGLAYER_H diff --git a/include/llvm/ExecutionEngine/Orc/LookasideRTDyldMM.h b/include/llvm/ExecutionEngine/Orc/LookasideRTDyldMM.h new file mode 100644 index 0000000..4456404 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/LookasideRTDyldMM.h @@ -0,0 +1,92 @@ +//===- LookasideRTDyldMM - Redirect symbol lookup via a functor -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines an adapter for RuntimeDyldMM that allows lookups for external +// symbols to go via a functor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_LOOKASIDERTDYLDMM_H +#define LLVM_EXECUTIONENGINE_ORC_LOOKASIDERTDYLDMM_H + +#include "llvm/ADT/STLExtras.h" +#include <memory> +#include <vector> + +namespace llvm { +namespace orc { + +/// @brief Defines an adapter for RuntimeDyldMM that allows lookups for external +/// symbols to go via a functor, before falling back to the lookup logic +/// provided by the underlying RuntimeDyldMM instance. +/// +/// This class is useful for redirecting symbol lookup back to various layers +/// of a JIT component stack, e.g. to enable lazy module emission. +/// +template <typename BaseRTDyldMM, typename ExternalLookupFtor, + typename DylibLookupFtor> +class LookasideRTDyldMM : public BaseRTDyldMM { +public: + /// @brief Create a LookasideRTDyldMM intance. + LookasideRTDyldMM(ExternalLookupFtor ExternalLookup, + DylibLookupFtor DylibLookup) + : ExternalLookup(std::move(ExternalLookup)), + DylibLookup(std::move(DylibLookup)) {} + + /// @brief Look up the given symbol address, first via the functor this + /// instance was created with, then (if the symbol isn't found) + /// via the underlying RuntimeDyldMM. + uint64_t getSymbolAddress(const std::string &Name) override { + if (uint64_t Addr = ExternalLookup(Name)) + return Addr; + return BaseRTDyldMM::getSymbolAddress(Name); + } + + uint64_t getSymbolAddressInLogicalDylib(const std::string &Name) override { + if (uint64_t Addr = DylibLookup(Name)) + return Addr; + return BaseRTDyldMM::getSymbolAddressInLogicalDylib(Name); + }; + + /// @brief Get a reference to the ExternalLookup functor. + ExternalLookupFtor &getExternalLookup() { return ExternalLookup; } + + /// @brief Get a const-reference to the ExternalLookup functor. + const ExternalLookupFtor &getExternalLookup() const { return ExternalLookup; } + + /// @brief Get a reference to the DylibLookup functor. + DylibLookupFtor &getDylibLookup() { return DylibLookup; } + + /// @brief Get a const-reference to the DylibLookup functor. + const DylibLookupFtor &getDylibLookup() const { return DylibLookup; } + +private: + ExternalLookupFtor ExternalLookup; + DylibLookupFtor DylibLookup; +}; + +/// @brief Create a LookasideRTDyldMM from a base memory manager type, an +/// external lookup functor, and a dylib lookup functor. +template <typename BaseRTDyldMM, typename ExternalLookupFtor, + typename DylibLookupFtor> +std::unique_ptr< + LookasideRTDyldMM<BaseRTDyldMM, ExternalLookupFtor, DylibLookupFtor>> +createLookasideRTDyldMM(ExternalLookupFtor &&ExternalLookup, + DylibLookupFtor &&DylibLookup) { + typedef LookasideRTDyldMM<BaseRTDyldMM, ExternalLookupFtor, DylibLookupFtor> + ThisLookasideMM; + return llvm::make_unique<ThisLookasideMM>( + std::forward<ExternalLookupFtor>(ExternalLookup), + std::forward<DylibLookupFtor>(DylibLookup)); +} + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_LOOKASIDERTDYLDMM_H diff --git a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h new file mode 100644 index 0000000..36af0fe --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -0,0 +1,267 @@ +//===- ObjectLinkingLayer.h - Add object files to a JIT process -*- 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 the object layer of the JIT. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H +#define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H + +#include "JITSymbol.h" +#include "LookasideRTDyldMM.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include <list> +#include <memory> + +namespace llvm { +namespace orc { + +class ObjectLinkingLayerBase { +protected: + + /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT. + /// + /// An instance of this class will be created for each set of objects added + /// via JITObjectLayer::addObjectSet. Deleting the instance (via + /// removeObjectSet) frees its memory, removing all symbol definitions that + /// had been provided by this instance. Higher level layers are responsible + /// for taking any action required to handle the missing symbols. + class LinkedObjectSet { + LinkedObjectSet(const LinkedObjectSet&) = delete; + void operator=(const LinkedObjectSet&) = delete; + public: + LinkedObjectSet(std::unique_ptr<RTDyldMemoryManager> MM) + : MM(std::move(MM)), RTDyld(llvm::make_unique<RuntimeDyld>(&*this->MM)), + State(Raw) {} + + // MSVC 2012 cannot infer a move constructor, so write it out longhand. + LinkedObjectSet(LinkedObjectSet &&O) + : MM(std::move(O.MM)), RTDyld(std::move(O.RTDyld)), State(O.State) {} + + std::unique_ptr<RuntimeDyld::LoadedObjectInfo> + addObject(const object::ObjectFile &Obj) { + return RTDyld->loadObject(Obj); + } + + TargetAddress getSymbolAddress(StringRef Name, bool ExportedSymbolsOnly) { + if (ExportedSymbolsOnly) + return RTDyld->getExportedSymbolLoadAddress(Name); + return RTDyld->getSymbolLoadAddress(Name); + } + + bool NeedsFinalization() const { return (State == Raw); } + + void Finalize() { + State = Finalizing; + RTDyld->resolveRelocations(); + RTDyld->registerEHFrames(); + MM->finalizeMemory(); + OwnedBuffers.clear(); + State = Finalized; + } + + void mapSectionAddress(const void *LocalAddress, TargetAddress TargetAddr) { + assert((State != Finalized) && + "Attempting to remap sections for finalized objects."); + RTDyld->mapSectionAddress(LocalAddress, TargetAddr); + } + + void takeOwnershipOfBuffer(std::unique_ptr<MemoryBuffer> B) { + OwnedBuffers.push_back(std::move(B)); + } + + private: + std::unique_ptr<RTDyldMemoryManager> MM; + std::unique_ptr<RuntimeDyld> RTDyld; + enum { Raw, Finalizing, Finalized } State; + + // FIXME: This ownership hack only exists because RuntimeDyldELF still + // wants to be able to inspect the original object when resolving + // relocations. As soon as that can be fixed this should be removed. + std::vector<std::unique_ptr<MemoryBuffer>> OwnedBuffers; + }; + + typedef std::list<LinkedObjectSet> LinkedObjectSetListT; + +public: + /// @brief Handle to a set of loaded objects. + typedef LinkedObjectSetListT::iterator ObjSetHandleT; + + // Ownership hack. + // FIXME: Remove this as soon as RuntimeDyldELF can apply relocations without + // referencing the original object. + template <typename OwningMBSet> + void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) { + for (auto &MB : MBs) + H->takeOwnershipOfBuffer(std::move(MB)); + } + +}; + +/// @brief Default (no-op) action to perform when loading objects. +class DoNothingOnNotifyLoaded { +public: + template <typename ObjSetT, typename LoadResult> + void operator()(ObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &, + const LoadResult &) {} +}; + +/// @brief Bare bones object linking layer. +/// +/// This class is intended to be used as the base layer for a JIT. It allows +/// object files to be loaded into memory, linked, and the addresses of their +/// symbols queried. All objects added to this layer can see each other's +/// symbols. +template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded> +class ObjectLinkingLayer : public ObjectLinkingLayerBase { +public: + + /// @brief LoadedObjectInfo list. Contains a list of owning pointers to + /// RuntimeDyld::LoadedObjectInfo instances. + typedef std::vector<std::unique_ptr<RuntimeDyld::LoadedObjectInfo>> + LoadedObjInfoList; + + /// @brief Functor to create RTDyldMemoryManager instances. + typedef std::function<std::unique_ptr<RTDyldMemoryManager>()> CreateRTDyldMMFtor; + + /// @brief Functor for receiving finalization notifications. + typedef std::function<void(ObjSetHandleT)> NotifyFinalizedFtor; + + /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded, + /// NotifyFinalized and CreateMemoryManager functors. + ObjectLinkingLayer( + CreateRTDyldMMFtor CreateMemoryManager = CreateRTDyldMMFtor(), + NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), + NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor()) + : NotifyLoaded(std::move(NotifyLoaded)), + NotifyFinalized(std::move(NotifyFinalized)), + CreateMemoryManager(std::move(CreateMemoryManager)) {} + + /// @brief Add a set of objects (or archives) that will be treated as a unit + /// for the purposes of symbol lookup and memory management. + /// + /// @return A pair containing (1) A handle that can be used to free the memory + /// allocated for the objects, and (2) a LoadedObjInfoList containing + /// one LoadedObjInfo instance for each object at the corresponding + /// index in the Objects list. + /// + /// This version of this method allows the client to pass in an + /// RTDyldMemoryManager instance that will be used to allocate memory and look + /// up external symbol addresses for the given objects. + template <typename ObjSetT> + ObjSetHandleT addObjectSet(const ObjSetT &Objects, + std::unique_ptr<RTDyldMemoryManager> MM) { + + if (!MM) { + assert(CreateMemoryManager && + "No memory manager or memory manager creator provided."); + MM = CreateMemoryManager(); + } + + ObjSetHandleT Handle = LinkedObjSetList.insert( + LinkedObjSetList.end(), LinkedObjectSet(std::move(MM))); + LinkedObjectSet &LOS = *Handle; + LoadedObjInfoList LoadedObjInfos; + + for (auto &Obj : Objects) + LoadedObjInfos.push_back(LOS.addObject(*Obj)); + + NotifyLoaded(Handle, Objects, LoadedObjInfos); + + return Handle; + } + + /// @brief Remove the set of objects associated with handle H. + /// + /// All memory allocated for the objects will be freed, and the sections and + /// symbols they provided will no longer be available. No attempt is made to + /// re-emit the missing symbols, and any use of these symbols (directly or + /// indirectly) will result in undefined behavior. If dependence tracking is + /// required to detect or resolve such issues it should be added at a higher + /// layer. + void removeObjectSet(ObjSetHandleT H) { + // How do we invalidate the symbols in H? + LinkedObjSetList.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(StringRef Name, bool ExportedSymbolsOnly) { + for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E; + ++I) + if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly)) + return Symbol; + + return nullptr; + } + + /// @brief Search for the given named symbol in the context of the set of + /// loaded objects represented by the handle H. + /// @param H The handle for the object set to search in. + /// @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 is found in the + /// given object set. + JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name, + bool ExportedSymbolsOnly) { + if (auto Addr = H->getSymbolAddress(Name, ExportedSymbolsOnly)) { + if (!H->NeedsFinalization()) { + // If this instance has already been finalized then we can just return + // the address. + return JITSymbol(Addr); + } else { + // If this instance needs finalization return a functor that will do it. + // The functor still needs to double-check whether finalization is + // required, in case someone else finalizes this set before the functor + // is called. + return JITSymbol( + [this, Addr, H]() { + if (H->NeedsFinalization()) { + H->Finalize(); + if (NotifyFinalized) + NotifyFinalized(H); + } + return Addr; + }); + } + } + + return nullptr; + } + + /// @brief Map section addresses for the objects associated with the handle H. + void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress, + TargetAddress TargetAddr) { + H->mapSectionAddress(LocalAddress, TargetAddr); + } + + /// @brief Immediately emit and finalize the object set represented by the + /// given handle. + /// @param H Handle for object set to emit/finalize. + void emitAndFinalize(ObjSetHandleT H) { + H->Finalize(); + if (NotifyFinalized) + NotifyFinalized(H); + } + +private: + LinkedObjectSetListT LinkedObjSetList; + NotifyLoadedFtor NotifyLoaded; + NotifyFinalizedFtor NotifyFinalized; + CreateRTDyldMMFtor CreateMemoryManager; +}; + +} // End namespace orc. +} // End namespace llvm + +#endif // LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H diff --git a/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h b/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h new file mode 100644 index 0000000..c6f866a --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h @@ -0,0 +1,56 @@ +//===-- OrcTargetSupport.h - Code to support specific targets --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Target specific code for Orc, e.g. callback assembly. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H +#define LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H + +#include "IndirectionUtils.h" + +namespace llvm { +namespace orc { + +class OrcX86_64 { +public: + static const char *ResolverBlockName; + + /// @brief Insert module-level inline callback asm into module M for the + /// symbols managed by JITResolveCallbackHandler J. + static void insertResolverBlock( + Module &M, + JITCompileCallbackManagerBase<OrcX86_64> &JCBM); + + /// @brief Get a label name from the given index. + typedef std::function<std::string(unsigned)> LabelNameFtor; + + static const unsigned CallSize = 6; + + /// @brief Insert the requested number of trampolines into the given module. + /// @param M Module to insert the call block into. + /// @param NumCalls Number of calls to create in the call block. + /// @param StartIndex Optional argument specifying the index suffix to start + /// with. + /// @return A functor that provides the symbol name for each entry in the call + /// block. + /// + static LabelNameFtor insertCompileCallbackTrampolines( + Module &M, + TargetAddress TrampolineAddr, + unsigned NumCalls, + unsigned StartIndex = 0); + +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H diff --git a/include/llvm/ExecutionEngine/OrcMCJITReplacement.h b/include/llvm/ExecutionEngine/OrcMCJITReplacement.h new file mode 100644 index 0000000..4cd5648 --- /dev/null +++ b/include/llvm/ExecutionEngine/OrcMCJITReplacement.h @@ -0,0 +1,38 @@ +//===---- OrcMCJITReplacement.h - Orc-based MCJIT replacement ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file forces OrcMCJITReplacement to link in on certain operating systems. +// (Windows). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORCMCJITREPLACEMENT_H +#define LLVM_EXECUTIONENGINE_ORCMCJITREPLACEMENT_H + +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include <cstdlib> + +extern "C" void LLVMLinkInOrcMCJITReplacement(); + +namespace { + struct ForceOrcMCJITReplacementLinking { + ForceOrcMCJITReplacementLinking() { + // We must reference OrcMCJITReplacement in such a way that compilers will + // not delete it all as dead code, even with whole program optimization, + // yet is effectively a NO-OP. As the compiler isn't smart enough to know + // that getenv() never returns -1, this will do the job. + if (std::getenv("bar") != (char*) -1) + return; + + LLVMLinkInOrcMCJITReplacement(); + } + } ForceOrcMCJITReplacementLinking; +} + +#endif diff --git a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h index b941efc..792a499 100644 --- a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h +++ b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h @@ -22,7 +22,10 @@ namespace llvm { class ExecutionEngine; -class ObjectImage; + + namespace object { + class ObjectFile; + } // RuntimeDyld clients often want to handle the memory management of // what gets placed where. For JIT clients, this is the subset of @@ -31,8 +34,8 @@ class ObjectImage; // FIXME: As the RuntimeDyld fills out, additional routines will be needed // for the varying types of objects to be allocated. class RTDyldMemoryManager { - RTDyldMemoryManager(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION; - void operator=(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION; + RTDyldMemoryManager(const RTDyldMemoryManager&) = delete; + void operator=(const RTDyldMemoryManager&) = delete; public: RTDyldMemoryManager() {} virtual ~RTDyldMemoryManager(); @@ -86,6 +89,27 @@ public: return getSymbolAddressInProcess(Name); } + /// This method returns the address of the specified symbol if it exists + /// within the logical dynamic library represented by this + /// RTDyldMemoryManager. Unlike getSymbolAddress, queries through this + /// interface should return addresses for hidden symbols. + /// + /// This is of particular importance for the Orc JIT APIs, which support lazy + /// compilation by breaking up modules: Each of those broken out modules + /// must be able to resolve hidden symbols provided by the others. Clients + /// writing memory managers for MCJIT can usually ignore this method. + /// + /// This method will be queried by RuntimeDyld when checking for previous + /// definitions of common symbols. It will *not* be queried by default when + /// resolving external symbols (this minimises the link-time overhead for + /// MCJIT clients who don't care about Orc features). If you are writing a + /// RTDyldMemoryManager for Orc and want "external" symbol resolution to + /// search the logical dylib, you should override your getSymbolAddress + /// method call this method directly. + virtual uint64_t getSymbolAddressInLogicalDylib(const std::string &Name) { + return 0; + } + /// This method returns the address of the specified function. As such it is /// only useful for resolving library symbols, not code generated symbols. /// @@ -109,7 +133,7 @@ public: /// address space can use this call to remap the section addresses for the /// newly loaded object. virtual void notifyObjectLoaded(ExecutionEngine *EE, - const ObjectImage *) {} + const object::ObjectFile &) {} /// This method is called when object loading is complete and section page /// permissions can be applied. It is up to the memory manager implementation diff --git a/include/llvm/ExecutionEngine/RuntimeDyld.h b/include/llvm/ExecutionEngine/RuntimeDyld.h index 3605b9e..08cfa39 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyld.h +++ b/include/llvm/ExecutionEngine/RuntimeDyld.h @@ -15,25 +15,25 @@ #define LLVM_EXECUTIONENGINE_RUNTIMEDYLD_H #include "llvm/ADT/StringRef.h" -#include "llvm/ExecutionEngine/ObjectBuffer.h" #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include "llvm/Support/Memory.h" +#include <memory> namespace llvm { namespace object { class ObjectFile; + template <typename T> class OwningBinary; } class RuntimeDyldImpl; class RuntimeDyldCheckerImpl; -class ObjectImage; class RuntimeDyld { friend class RuntimeDyldCheckerImpl; - RuntimeDyld(const RuntimeDyld &) LLVM_DELETED_FUNCTION; - void operator=(const RuntimeDyld &) LLVM_DELETED_FUNCTION; + RuntimeDyld(const RuntimeDyld &) = delete; + void operator=(const RuntimeDyld &) = delete; // RuntimeDyldImpl is the actual class. RuntimeDyld is just the public // interface. @@ -46,32 +46,49 @@ protected: // Any relocations already associated with the symbol will be re-resolved. void reassignSectionAddress(unsigned SectionID, uint64_t Addr); public: + + /// \brief Information about the loaded object. + class LoadedObjectInfo { + friend class RuntimeDyldImpl; + public: + LoadedObjectInfo(RuntimeDyldImpl &RTDyld, unsigned BeginIdx, + unsigned EndIdx) + : RTDyld(RTDyld), BeginIdx(BeginIdx), EndIdx(EndIdx) { } + + virtual ~LoadedObjectInfo() {} + + virtual object::OwningBinary<object::ObjectFile> + getObjectForDebug(const object::ObjectFile &Obj) const = 0; + + uint64_t getSectionLoadAddress(StringRef Name) const; + + protected: + virtual void anchor(); + + RuntimeDyldImpl &RTDyld; + unsigned BeginIdx, EndIdx; + }; + RuntimeDyld(RTDyldMemoryManager *); ~RuntimeDyld(); - /// Prepare the object contained in the input buffer for execution. - /// Ownership of the input buffer is transferred to the ObjectImage - /// instance returned from this function if successful. In the case of load - /// failure, the input buffer will be deleted. - std::unique_ptr<ObjectImage> - loadObject(std::unique_ptr<ObjectBuffer> InputBuffer); - - /// Prepare the referenced object file for execution. - /// Ownership of the input object is transferred to the ObjectImage - /// instance returned from this function if successful. In the case of load - /// failure, the input object will be deleted. - std::unique_ptr<ObjectImage> - loadObject(std::unique_ptr<object::ObjectFile> InputObject); + /// Add the referenced object file to the list of objects to be loaded and + /// relocated. + std::unique_ptr<LoadedObjectInfo> loadObject(const object::ObjectFile &O); /// Get the address of our local copy of the symbol. This may or may not /// be the address used for relocation (clients can copy the data around /// and resolve relocatons based on where they put it). void *getSymbolAddress(StringRef Name) const; - /// Get the address of the target copy of the symbol. This is the address - /// used for relocation. + /// Get the address of the target copy of the symbol (works for both exported + /// and non-exported symbols). This is the address used for relocation. uint64_t getSymbolLoadAddress(StringRef Name) const; + /// Get the address of the target copy of the symbol (works for exported + /// symbols only). This is the address used for relocation. + uint64_t getExportedSymbolLoadAddress(StringRef Name) const; + /// Resolve the relocations for all symbols we currently know about. void resolveRelocations(); diff --git a/include/llvm/ExecutionEngine/RuntimeDyldChecker.h b/include/llvm/ExecutionEngine/RuntimeDyldChecker.h index 35ceba2..23936a6 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyldChecker.h +++ b/include/llvm/ExecutionEngine/RuntimeDyldChecker.h @@ -52,6 +52,7 @@ class raw_ostream; /// /// ident_expr = 'decode_operand' '(' symbol ',' operand-index ')' /// | 'next_pc' '(' symbol ')' +/// | 'stub_addr' '(' file-name ',' section-name ',' symbol ')' /// | symbol /// /// binary_expr = expr '+' expr diff --git a/include/llvm/ExecutionEngine/SectionMemoryManager.h b/include/llvm/ExecutionEngine/SectionMemoryManager.h index 1368563..b825aff 100644 --- a/include/llvm/ExecutionEngine/SectionMemoryManager.h +++ b/include/llvm/ExecutionEngine/SectionMemoryManager.h @@ -35,8 +35,8 @@ namespace llvm { /// MCJIT::finalizeObject or by calling SectionMemoryManager::finalizeMemory /// directly. Clients of MCJIT should call MCJIT::finalizeObject. class SectionMemoryManager : public RTDyldMemoryManager { - SectionMemoryManager(const SectionMemoryManager&) LLVM_DELETED_FUNCTION; - void operator=(const SectionMemoryManager&) LLVM_DELETED_FUNCTION; + SectionMemoryManager(const SectionMemoryManager&) = delete; + void operator=(const SectionMemoryManager&) = delete; public: SectionMemoryManager() { } |