diff options
author | Pirama Arumuga Nainar <pirama@google.com> | 2015-05-06 11:46:36 -0700 |
---|---|---|
committer | Pirama Arumuga Nainar <pirama@google.com> | 2015-05-18 10:52:30 -0700 |
commit | 2c3e0051c31c3f5b2328b447eadf1cf9c4427442 (patch) | |
tree | c0104029af14e9f47c2ef58ca60e6137691f3c9b /include/llvm/ExecutionEngine | |
parent | e1bc145815f4334641be19f1c45ecf85d25b6e5a (diff) | |
download | external_llvm-2c3e0051c31c3f5b2328b447eadf1cf9c4427442.zip external_llvm-2c3e0051c31c3f5b2328b447eadf1cf9c4427442.tar.gz external_llvm-2c3e0051c31c3f5b2328b447eadf1cf9c4427442.tar.bz2 |
Update aosp/master LLVM for rebase to r235153
Change-Id: I9bf53792f9fc30570e81a8d80d296c681d005ea7
(cherry picked from commit 0c7f116bb6950ef819323d855415b2f2b0aad987)
Diffstat (limited to 'include/llvm/ExecutionEngine')
-rw-r--r-- | include/llvm/ExecutionEngine/ExecutionEngine.h | 71 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h | 96 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/ExecutionUtils.h | 182 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/IRCompileLayer.h | 14 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/IRTransformLayer.h | 101 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/IndirectionUtils.h | 54 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/JITSymbol.h | 2 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/LambdaResolver.h | 62 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h | 45 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/LookasideRTDyldMM.h | 92 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h | 105 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/RTDyldMemoryManager.h | 138 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/RuntimeDyld.h | 114 | ||||
-rw-r--r-- | include/llvm/ExecutionEngine/SectionMemoryManager.h | 4 |
14 files changed, 745 insertions, 335 deletions
diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index abdaa0c..4b2add8 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -15,6 +15,7 @@ #ifndef LLVM_EXECUTIONENGINE_EXECUTIONENGINE_H #define LLVM_EXECUTIONENGINE_EXECUTIONENGINE_H +#include "RuntimeDyld.h" #include "llvm-c/ExecutionEngine.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -42,6 +43,7 @@ class GlobalVariable; class GlobalValue; class JITEventListener; class MachineCodeInfo; +class MCJITMemoryManager; class MutexGuard; class ObjectCache; class RTDyldMemoryManager; @@ -57,46 +59,34 @@ namespace object { /// table. Access to this class should be serialized under a mutex. class ExecutionEngineState { public: - struct AddressMapConfig : public ValueMapConfig<const GlobalValue*> { - typedef ExecutionEngineState *ExtraData; - static sys::Mutex *getMutex(ExecutionEngineState *EES); - static void onDelete(ExecutionEngineState *EES, const GlobalValue *Old); - static void onRAUW(ExecutionEngineState *, const GlobalValue *, - const GlobalValue *); - }; - - typedef ValueMap<const GlobalValue *, void *, AddressMapConfig> - GlobalAddressMapTy; + typedef StringMap<uint64_t> GlobalAddressMapTy; private: - ExecutionEngine &EE; - /// GlobalAddressMap - A mapping between LLVM global values and their - /// actualized version... + /// GlobalAddressMap - A mapping between LLVM global symbol names values and + /// their actualized version... GlobalAddressMapTy GlobalAddressMap; /// GlobalAddressReverseMap - This is the reverse mapping of GlobalAddressMap, /// used to convert raw addresses into the LLVM global value that is emitted /// at the address. This map is not computed unless getGlobalValueAtAddress /// is called at some point. - std::map<void *, AssertingVH<const GlobalValue> > GlobalAddressReverseMap; + std::map<uint64_t, std::string> GlobalAddressReverseMap; public: - ExecutionEngineState(ExecutionEngine &EE); GlobalAddressMapTy &getGlobalAddressMap() { return GlobalAddressMap; } - std::map<void*, AssertingVH<const GlobalValue> > & - getGlobalAddressReverseMap() { + std::map<uint64_t, std::string> &getGlobalAddressReverseMap() { return GlobalAddressReverseMap; } /// \brief Erase an entry from the mapping table. /// /// \returns The address that \p ToUnmap was happed to. - void *RemoveMapping(const GlobalValue *ToUnmap); + uint64_t RemoveMapping(StringRef Name); }; /// \brief Abstract interface for implementation execution of LLVM modules, @@ -139,15 +129,17 @@ protected: virtual char *getMemoryForGV(const GlobalVariable *GV); static ExecutionEngine *(*MCJITCtor)( - std::unique_ptr<Module> M, - std::string *ErrorStr, - std::unique_ptr<RTDyldMemoryManager> MCJMM, - std::unique_ptr<TargetMachine> TM); + std::unique_ptr<Module> M, + std::string *ErrorStr, + std::shared_ptr<MCJITMemoryManager> MM, + std::shared_ptr<RuntimeDyld::SymbolResolver> SR, + std::unique_ptr<TargetMachine> TM); static ExecutionEngine *(*OrcMCJITReplacementCtor)( - std::string *ErrorStr, - std::unique_ptr<RTDyldMemoryManager> OrcJMM, - std::unique_ptr<TargetMachine> TM); + std::string *ErrorStr, + std::shared_ptr<MCJITMemoryManager> MM, + std::shared_ptr<RuntimeDyld::SymbolResolver> SR, + std::unique_ptr<TargetMachine> TM); static ExecutionEngine *(*InterpCtor)(std::unique_ptr<Module> M, std::string *ErrorStr); @@ -157,6 +149,9 @@ protected: /// abort. void *(*LazyFunctionCreator)(const std::string &); + /// getMangledName - Get mangled name. + std::string getMangledName(const GlobalValue *GV); + public: /// lock - This lock protects the ExecutionEngine and MCJIT classes. It must /// be held while changing the internal state of any of those classes. @@ -228,7 +223,8 @@ public: /// Map the address of a JIT section as returned from the memory manager /// to the address in the target process as the running code will see it. /// This is the address which will be used for relocation resolution. - virtual void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress) { + virtual void mapSectionAddress(const void *LocalAddress, + uint64_t TargetAddress) { llvm_unreachable("Re-mapping of section addresses not supported with this " "EE!"); } @@ -286,6 +282,7 @@ public: /// existing data in memory. Mappings are automatically removed when their /// GlobalValue is destroyed. void addGlobalMapping(const GlobalValue *GV, void *Addr); + void addGlobalMapping(StringRef Name, uint64_t Addr); /// clearAllGlobalMappings - Clear all global mappings and start over again, /// for use in dynamic compilation scenarios to move globals. @@ -299,14 +296,17 @@ public: /// address. This updates both maps as required. If "Addr" is null, the /// entry for the global is removed from the mappings. This returns the old /// value of the pointer, or null if it was not in the map. - void *updateGlobalMapping(const GlobalValue *GV, void *Addr); + uint64_t updateGlobalMapping(const GlobalValue *GV, void *Addr); + uint64_t updateGlobalMapping(StringRef Name, uint64_t Addr); + + /// getAddressToGlobalIfAvailable - This returns the address of the specified + /// global symbol. + uint64_t getAddressToGlobalIfAvailable(StringRef S); /// getPointerToGlobalIfAvailable - This returns the address of the specified /// global value if it is has already been codegen'd, otherwise it returns /// null. - /// - /// This function is deprecated for the MCJIT execution engine. It doesn't - /// seem to be needed in that case, but an equivalent can be added if it is. + void *getPointerToGlobalIfAvailable(StringRef S); void *getPointerToGlobalIfAvailable(const GlobalValue *GV); /// getPointerToGlobal - This returns the address of the specified global @@ -470,7 +470,7 @@ public: } protected: - ExecutionEngine() : EEState(*this) {} + ExecutionEngine() {} explicit ExecutionEngine(std::unique_ptr<Module> M); void emitGlobals(); @@ -500,7 +500,8 @@ private: EngineKind::Kind WhichEngine; std::string *ErrorStr; CodeGenOpt::Level OptLevel; - std::unique_ptr<RTDyldMemoryManager> MCJMM; + std::shared_ptr<MCJITMemoryManager> MemMgr; + std::shared_ptr<RuntimeDyld::SymbolResolver> Resolver; TargetOptions Options; Reloc::Model RelocModel; CodeModel::Model CMModel; @@ -535,6 +536,12 @@ public: /// memory manager. This option defaults to NULL. EngineBuilder &setMCJITMemoryManager(std::unique_ptr<RTDyldMemoryManager> mcjmm); + EngineBuilder& + setMemoryManager(std::unique_ptr<MCJITMemoryManager> MM); + + EngineBuilder& + setSymbolResolver(std::unique_ptr<RuntimeDyld::SymbolResolver> SR); + /// setErrorStr - Set the error string to write to on error. This option /// defaults to NULL. EngineBuilder &setErrorStr(std::string *e) { diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 77b0c48..30f7f1c 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -16,7 +16,7 @@ #define LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H #include "IndirectionUtils.h" -#include "LookasideRTDyldMM.h" +#include "LambdaResolver.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include <list> @@ -36,7 +36,7 @@ namespace orc { /// compiled only when it is first called. template <typename BaseLayerT, typename CompileCallbackMgrT> class CompileOnDemandLayer { -public: +private: /// @brief Lookup helper that provides compatibility with the classic /// static-compilation symbol resolution process. /// @@ -64,6 +64,8 @@ public: /// @brief Construct a scoped lookup. CODScopedLookup(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {} + virtual ~CODScopedLookup() {} + /// @brief Start a new context for a single logical module. LMHandle createLogicalModule() { Handles.push_back(SiblingHandlesList()); @@ -92,6 +94,10 @@ public: return nullptr; } + /// @brief Find an external symbol (via the user supplied SymbolResolver). + virtual RuntimeDyld::SymbolInfo + externalLookup(const std::string &Name) const = 0; + private: JITSymbol findSymbolIn(LMHandle LMH, const std::string &Name) { @@ -105,7 +111,29 @@ public: PseudoDylibModuleSetHandlesList Handles; }; -private: + template <typename ResolverPtrT> + class CODScopedLookupImpl : public CODScopedLookup { + public: + CODScopedLookupImpl(BaseLayerT &BaseLayer, ResolverPtrT Resolver) + : CODScopedLookup(BaseLayer), Resolver(std::move(Resolver)) {} + + RuntimeDyld::SymbolInfo + externalLookup(const std::string &Name) const override { + return Resolver->findSymbol(Name); + } + + private: + ResolverPtrT Resolver; + }; + + template <typename ResolverPtrT> + static std::shared_ptr<CODScopedLookup> + createCODScopedLookup(BaseLayerT &BaseLayer, + ResolverPtrT Resolver) { + typedef CODScopedLookupImpl<ResolverPtrT> Impl; + return std::make_shared<Impl>(BaseLayer, std::move(Resolver)); + } + typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT; typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerModuleSetHandleListT; @@ -138,36 +166,31 @@ 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, CompileCallbackMgrT &CallbackMgr) : BaseLayer(BaseLayer), CompileCallbackMgr(CallbackMgr) {} /// @brief Add a module to the compile-on-demand layer. - template <typename ModuleSetT> + template <typename ModuleSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT> ModuleSetHandleT addModuleSet(ModuleSetT Ms, - LookupFtor FallbackLookup = nullptr) { + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { - // 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(); - }; + assert(MemMgr == nullptr && + "User supplied memory managers not supported with COD yet."); // 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); + auto DylibLookup = createCODScopedLookup(BaseLayer, std::move(Resolver)); 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); + partitionAndAdd(*M, MSI); return H; } @@ -203,8 +226,7 @@ public: private: - void partitionAndAdd(Module &M, ModuleSetInfo &MSI, - LookupFtor FallbackLookup) { + void partitionAndAdd(Module &M, ModuleSetInfo &MSI) { const char *AddrSuffix = "$orc_addr"; const char *BodySuffix = "$orc_body"; @@ -224,8 +246,7 @@ private: auto FunctionModules = std::move(PartitionedModule.Functions); // Emit the commons stright away. - auto CommonHandle = addModule(std::move(CommonsModule), MSI, LogicalModule, - FallbackLookup); + auto CommonHandle = addModule(std::move(CommonsModule), MSI, LogicalModule); BaseLayer.emitAndFinalize(CommonHandle); // Map of definition names to callback-info data structures. We'll use @@ -255,10 +276,12 @@ private: Function *Proto = StubsModule->getFunction(Name); assert(Proto && "Failed to clone function decl into stubs module."); auto CallbackInfo = - CompileCallbackMgr.getCompileCallback(*Proto->getFunctionType()); + CompileCallbackMgr.getCompileCallback(Proto->getContext()); GlobalVariable *FunctionBodyPointer = - createImplPointer(*Proto, Name + AddrSuffix, - CallbackInfo.getAddress()); + createImplPointer(*Proto->getType(), *Proto->getParent(), + Name + AddrSuffix, + createIRTypedAddress(*Proto->getFunctionType(), + CallbackInfo.getAddress())); makeStub(*Proto, *FunctionBodyPointer); F.setName(Name + BodySuffix); @@ -268,7 +291,7 @@ private: NewStubInfos.push_back(StubInfos.insert(StubInfos.begin(), KV)); } - auto H = addModule(std::move(SubM), MSI, LogicalModule, FallbackLookup); + auto H = addModule(std::move(SubM), MSI, LogicalModule); // Set the compile actions for this module: for (auto &KVPair : NewStubInfos) { @@ -286,7 +309,7 @@ private: // 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); + addModule(std::move(StubsModule), MSI, LogicalModule); for (auto &KVPair : StubInfos) { std::string AddrName = Mangle(KVPair.first + AddrSuffix, @@ -304,8 +327,7 @@ private: BaseLayerModuleSetHandleT addModule( std::unique_ptr<Module> M, ModuleSetInfo &MSI, - typename CODScopedLookup::LMHandle LogicalModule, - LookupFtor FallbackLookup) { + typename CODScopedLookup::LMHandle LogicalModule) { // Add this module to the JIT with a memory manager that uses the // DylibLookup to resolve symbols. @@ -313,19 +335,25 @@ private: MSet.push_back(std::move(M)); auto DylibLookup = MSI.Lookup; - auto MM = - createLookasideRTDyldMM<SectionMemoryManager>( + auto Resolver = + createLambdaResolver( [=](const std::string &Name) { if (auto Symbol = DylibLookup->findSymbol(LogicalModule, Name)) - return Symbol.getAddress(); - return FallbackLookup(Name); + return RuntimeDyld::SymbolInfo(Symbol.getAddress(), + Symbol.getFlags()); + return DylibLookup->externalLookup(Name); }, - [=](const std::string &Name) { - return DylibLookup->findSymbol(LogicalModule, Name).getAddress(); + [=](const std::string &Name) -> RuntimeDyld::SymbolInfo { + if (auto Symbol = DylibLookup->findSymbol(LogicalModule, Name)) + return RuntimeDyld::SymbolInfo(Symbol.getAddress(), + Symbol.getFlags()); + return nullptr; }); BaseLayerModuleSetHandleT H = - BaseLayer.addModuleSet(std::move(MSet), std::move(MM)); + BaseLayer.addModuleSet(std::move(MSet), + make_unique<SectionMemoryManager>(), + std::move(Resolver)); // Add this module to the logical module lookup. DylibLookup->addToLogicalModule(LogicalModule, H); MSI.BaseLayerModuleSetHandles.push_back(H); diff --git a/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h b/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h new file mode 100644 index 0000000..c10508c --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h @@ -0,0 +1,182 @@ +//===-- ExecutionUtils.h - Utilities for executing code in Orc --*- 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 executing code in Orc. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H +#define LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H + +#include "JITSymbol.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include <vector> + +namespace llvm { + +class ConstantArray; +class GlobalVariable; +class Function; +class Module; +class Value; + +namespace orc { + +/// @brief This iterator provides a convenient way to iterate over the elements +/// of an llvm.global_ctors/llvm.global_dtors instance. +/// +/// The easiest way to get hold of instances of this class is to use the +/// getConstructors/getDestructors functions. +class CtorDtorIterator { +public: + + /// @brief Accessor for an element of the global_ctors/global_dtors array. + /// + /// This class provides a read-only view of the element with any casts on + /// the function stripped away. + struct Element { + Element(unsigned Priority, const Function *Func, const Value *Data) + : Priority(Priority), Func(Func), Data(Data) {} + + unsigned Priority; + const Function *Func; + const Value *Data; + }; + + /// @brief Construct an iterator instance. If End is true then this iterator + /// acts as the end of the range, otherwise it is the beginning. + CtorDtorIterator(const GlobalVariable *GV, bool End); + + /// @brief Test iterators for equality. + bool operator==(const CtorDtorIterator &Other) const; + + /// @brief Test iterators for inequality. + bool operator!=(const CtorDtorIterator &Other) const; + + /// @brief Pre-increment iterator. + CtorDtorIterator& operator++(); + + /// @brief Post-increment iterator. + CtorDtorIterator operator++(int); + + /// @brief Dereference iterator. The resulting value provides a read-only view + /// of this element of the global_ctors/global_dtors list. + Element operator*() const; + +private: + const ConstantArray *InitList; + unsigned I; +}; + +/// @brief Create an iterator range over the entries of the llvm.global_ctors +/// array. +iterator_range<CtorDtorIterator> getConstructors(const Module &M); + +/// @brief Create an iterator range over the entries of the llvm.global_ctors +/// array. +iterator_range<CtorDtorIterator> getDestructors(const Module &M); + +/// @brief Convenience class for recording constructor/destructor names for +/// later execution. +template <typename JITLayerT> +class CtorDtorRunner { +public: + + /// @brief Construct a CtorDtorRunner for the given range using the given + /// name mangling function. + CtorDtorRunner(std::vector<std::string> CtorDtorNames, + typename JITLayerT::ModuleSetHandleT H) + : CtorDtorNames(std::move(CtorDtorNames)), H(H) {} + + /// @brief Run the recorded constructors/destructors through the given JIT + /// layer. + bool runViaLayer(JITLayerT &JITLayer) const { + typedef void (*CtorDtorTy)(); + + bool Error = false; + for (const auto &CtorDtorName : CtorDtorNames) + if (auto CtorDtorSym = JITLayer.findSymbolIn(H, CtorDtorName, false)) { + CtorDtorTy CtorDtor = + reinterpret_cast<CtorDtorTy>( + static_cast<uintptr_t>(CtorDtorSym.getAddress())); + CtorDtor(); + } else + Error = true; + return !Error; + } + +private: + std::vector<std::string> CtorDtorNames; + typename JITLayerT::ModuleSetHandleT H; +}; + +/// @brief Support class for static dtor execution. For hosted (in-process) JITs +/// only! +/// +/// If a __cxa_atexit function isn't found C++ programs that use static +/// destructors will fail to link. However, we don't want to use the host +/// process's __cxa_atexit, because it will schedule JIT'd destructors to run +/// after the JIT has been torn down, which is no good. This class makes it easy +/// to override __cxa_atexit (and the related __dso_handle). +/// +/// To use, clients should manually call searchOverrides from their symbol +/// resolver. This should generally be done after attempting symbol resolution +/// inside the JIT, but before searching the host process's symbol table. When +/// the client determines that destructors should be run (generally at JIT +/// teardown or after a return from main), the runDestructors method should be +/// called. +class LocalCXXRuntimeOverrides { +public: + + /// Create a runtime-overrides class. + template <typename MangleFtorT> + LocalCXXRuntimeOverrides(const MangleFtorT &Mangle) { + addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride)); + addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride)); + } + + /// Search overrided symbols. + RuntimeDyld::SymbolInfo searchOverrides(const std::string &Name) { + auto I = CXXRuntimeOverrides.find(Name); + if (I != CXXRuntimeOverrides.end()) + return RuntimeDyld::SymbolInfo(I->second, JITSymbolFlags::Exported); + return nullptr; + } + + /// Run any destructors recorded by the overriden __cxa_atexit function + /// (CXAAtExitOverride). + void runDestructors(); + +private: + + template <typename PtrTy> + TargetAddress toTargetAddress(PtrTy* P) { + return static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(P)); + } + + void addOverride(const std::string &Name, TargetAddress Addr) { + CXXRuntimeOverrides.insert(std::make_pair(Name, Addr)); + } + + StringMap<TargetAddress> CXXRuntimeOverrides; + + typedef void (*DestructorPtr)(void*); + typedef std::pair<DestructorPtr, void*> CXXDestructorDataPair; + typedef std::vector<CXXDestructorDataPair> CXXDestructorDataPairList; + CXXDestructorDataPairList DSOHandleOverride; + static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg, + void *DSOHandle); +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H diff --git a/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h index 6a47622..6379022 100644 --- a/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h +++ b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h @@ -52,14 +52,16 @@ public: /// @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. + /// @brief Compile each module in the given module set, then add the resulting + /// set of objects to the base layer along with the memory manager and + /// symbol resolver. /// /// @return A handle for the added modules. - template <typename ModuleSetT> + template <typename ModuleSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT> ModuleSetHandleT addModuleSet(ModuleSetT Ms, - std::unique_ptr<RTDyldMemoryManager> MM) { + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { OwningObjectVec Objects; OwningBufferVec Buffers; @@ -81,7 +83,7 @@ public: } ModuleSetHandleT H = - BaseLayer.addObjectSet(Objects, std::move(MM)); + BaseLayer.addObjectSet(Objects, std::move(MemMgr), std::move(Resolver)); BaseLayer.takeOwnershipOfBuffers(H, std::move(Buffers)); diff --git a/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h b/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h new file mode 100644 index 0000000..4dabb9a --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h @@ -0,0 +1,101 @@ +//===----- IRTransformLayer.h - Run all IR through a functor ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Run all IR passed in through a user supplied functor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H +#define LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H + +#include "JITSymbol.h" + +namespace llvm { +namespace orc { + +/// @brief IR mutating layer. +/// +/// This layer accepts sets of LLVM IR Modules (via addModuleSet). It +/// immediately applies the user supplied functor to each module, then adds +/// the set of transformed modules to the layer below. +template <typename BaseLayerT, typename TransformFtor> +class IRTransformLayer { +public: + /// @brief Handle to a set of added modules. + typedef typename BaseLayerT::ModuleSetHandleT ModuleSetHandleT; + + /// @brief Construct an IRTransformLayer with the given BaseLayer + IRTransformLayer(BaseLayerT &BaseLayer, + TransformFtor Transform = TransformFtor()) + : BaseLayer(BaseLayer), Transform(std::move(Transform)) {} + + /// @brief Apply the transform functor to each module in the module set, then + /// add the resulting set of modules to the base layer, along with the + /// memory manager and symbol resolver. + /// + /// @return A handle for the added modules. + template <typename ModuleSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT> + ModuleSetHandleT addModuleSet(ModuleSetT Ms, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + + for (auto I = Ms.begin(), E = Ms.end(); I != E; ++I) + *I = Transform(std::move(*I)); + + return BaseLayer.addModuleSet(std::move(Ms), std::move(MemMgr), + std::move(Resolver)); + } + + /// @brief Remove the module set associated with the handle H. + void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeModuleSet(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 + /// 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 module set represented by the + /// given handle. + /// @param H Handle for module set to emit/finalize. + void emitAndFinalize(ModuleSetHandleT H) { + BaseLayer.emitAndFinalize(H); + } + + /// @brief Access the transform functor directly. + TransformFtor& getTransform() { return Transform; } + + /// @brief Access the mumate functor directly. + const TransformFtor& getTransform() const { return Transform; } + +private: + BaseLayerT &BaseLayer; + TransformFtor Transform; +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H diff --git a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h index 8ce1d4d..7b4f611 100644 --- a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h +++ b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h @@ -16,6 +16,7 @@ #include "JITSymbol.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" @@ -37,11 +38,11 @@ public: /// the compile and update actions for the callback. class CompileCallbackInfo { public: - CompileCallbackInfo(Constant *Addr, CompileFtor &Compile, + CompileCallbackInfo(TargetAddress Addr, CompileFtor &Compile, UpdateFtor &Update) : Addr(Addr), Compile(Compile), Update(Update) {} - Constant* getAddress() const { return Addr; } + TargetAddress getAddress() const { return Addr; } void setCompileAction(CompileFtor Compile) { this->Compile = std::move(Compile); } @@ -49,7 +50,7 @@ public: this->Update = std::move(Update); } private: - Constant *Addr; + TargetAddress Addr; CompileFtor &Compile; UpdateFtor &Update; }; @@ -94,7 +95,7 @@ public: } /// @brief Get/create a compile callback with the given signature. - virtual CompileCallbackInfo getCompileCallback(FunctionType &FT) = 0; + virtual CompileCallbackInfo getCompileCallback(LLVMContext &Context) = 0; protected: @@ -125,27 +126,23 @@ public: /// there is no existing callback trampoline. /// (Trampolines are allocated in blocks for /// efficiency.) - JITCompileCallbackManager(JITLayerT &JIT, LLVMContext &Context, + JITCompileCallbackManager(JITLayerT &JIT, RuntimeDyld::MemoryManager &MemMgr, + LLVMContext &Context, TargetAddress ErrorHandlerAddress, unsigned NumTrampolinesPerBlock) : JITCompileCallbackManagerBase(ErrorHandlerAddress, NumTrampolinesPerBlock), - JIT(JIT) { + JIT(JIT), MemMgr(MemMgr) { emitResolverBlock(Context); } /// @brief Get/create a compile callback with the given signature. - CompileCallbackInfo getCompileCallback(FunctionType &FT) final { - TargetAddress TrampolineAddr = getAvailableTrampolineAddr(FT.getContext()); + CompileCallbackInfo getCompileCallback(LLVMContext &Context) final { + TargetAddress TrampolineAddr = getAvailableTrampolineAddr(Context); auto &CallbackHandler = this->ActiveTrampolines[TrampolineAddr]; - 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, + return CompileCallbackInfo(TrampolineAddr, CallbackHandler.Compile, CallbackHandler.Update); } @@ -162,7 +159,9 @@ private: std::unique_ptr<Module> M(new Module("resolver_block_module", Context)); TargetT::insertResolverBlock(*M, *this); - auto H = JIT.addModuleSet(SingletonSet(std::move(M)), nullptr); + auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr, + static_cast<RuntimeDyld::SymbolResolver*>( + nullptr)); JIT.emitAndFinalize(H); auto ResolverBlockSymbol = JIT.findSymbolIn(H, TargetT::ResolverBlockName, false); @@ -187,7 +186,9 @@ private: TargetT::insertCompileCallbackTrampolines(*M, ResolverBlockAddr, this->NumTrampolinesPerBlock, this->ActiveTrampolines.size()); - auto H = JIT.addModuleSet(SingletonSet(std::move(M)), nullptr); + auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr, + static_cast<RuntimeDyld::SymbolResolver*>( + nullptr)); JIT.emitAndFinalize(H); for (unsigned I = 0; I < this->NumTrampolinesPerBlock; ++I) { std::string Name = GetLabelName(I); @@ -198,10 +199,11 @@ private: } JITLayerT &JIT; + RuntimeDyld::MemoryManager &MemMgr; TargetAddress ResolverBlockAddr; }; -/// @brief Get an update functor for updating the value of a named function +/// @brief Get an update functor that updates the value of a named function /// pointer. template <typename JITLayerT> JITCompileCallbackManagerBase::UpdateFtor @@ -217,13 +219,26 @@ getLocalFPUpdater(JITLayerT &JIT, typename JITLayerT::ModuleSetHandleT H, }; } -GlobalVariable* createImplPointer(Function &F, const Twine &Name, - Constant *Initializer); +/// @brief Build a function pointer of FunctionType with the given constant +/// address. +/// +/// Usage example: Turn a trampoline address into a function pointer constant +/// for use in a stub. +Constant* createIRTypedAddress(FunctionType &FT, TargetAddress Addr); +/// @brief Create a function pointer with the given type, name, and initializer +/// in the given Module. +GlobalVariable* createImplPointer(PointerType &PT, Module &M, + const Twine &Name, Constant *Initializer); + +/// @brief Turn a function declaration into a stub function that makes an +/// indirect call using the given function pointer. void makeStub(Function &F, GlobalVariable &ImplPointer); typedef std::map<Module*, DenseSet<const GlobalValue*>> ModulePartitionMap; +/// @brief Extract subsections of a Module into the given Module according to +/// the given ModulePartitionMap. void partition(Module &M, const ModulePartitionMap &PMap); /// @brief Struct for trivial "complete" partitioning of a module. @@ -239,6 +254,7 @@ public: Functions(std::move(S.Functions)) {} }; +/// @brief Extract every function in M into a separate module. FullyPartitionedModule fullyPartition(Module &M); } // End namespace orc. diff --git a/include/llvm/ExecutionEngine/Orc/JITSymbol.h b/include/llvm/ExecutionEngine/Orc/JITSymbol.h index 7c3ad56..422a376 100644 --- a/include/llvm/ExecutionEngine/Orc/JITSymbol.h +++ b/include/llvm/ExecutionEngine/Orc/JITSymbol.h @@ -27,7 +27,7 @@ typedef uint64_t TargetAddress; /// @brief Represents a symbol in the JIT. class JITSymbol : public JITSymbolBase { -public: +public: typedef std::function<TargetAddress()> GetAddressFtor; diff --git a/include/llvm/ExecutionEngine/Orc/LambdaResolver.h b/include/llvm/ExecutionEngine/Orc/LambdaResolver.h new file mode 100644 index 0000000..faa2365 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/LambdaResolver.h @@ -0,0 +1,62 @@ +//===-- LambdaResolverMM - 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 a RuntimeDyld::SymbolResolver subclass that uses a user-supplied +// functor for symbol resolution. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H +#define LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include <memory> +#include <vector> + +namespace llvm { +namespace orc { + +template <typename ExternalLookupFtorT, typename DylibLookupFtorT> +class LambdaResolver : public RuntimeDyld::SymbolResolver { +public: + + LambdaResolver(ExternalLookupFtorT ExternalLookupFtor, + DylibLookupFtorT DylibLookupFtor) + : ExternalLookupFtor(ExternalLookupFtor), + DylibLookupFtor(DylibLookupFtor) {} + + RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) final { + return ExternalLookupFtor(Name); + } + + RuntimeDyld::SymbolInfo + findSymbolInLogicalDylib(const std::string &Name) final { + return DylibLookupFtor(Name); + } + +private: + ExternalLookupFtorT ExternalLookupFtor; + DylibLookupFtorT DylibLookupFtor; +}; + +template <typename ExternalLookupFtorT, + typename DylibLookupFtorT> +std::unique_ptr<LambdaResolver<ExternalLookupFtorT, DylibLookupFtorT>> +createLambdaResolver(ExternalLookupFtorT ExternalLookupFtor, + DylibLookupFtorT DylibLookupFtor) { + typedef LambdaResolver<ExternalLookupFtorT, DylibLookupFtorT> LR; + return make_unique<LR>(std::move(ExternalLookupFtor), + std::move(DylibLookupFtor)); +} + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H diff --git a/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h index ac5fccf..71c83f7 100644 --- a/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h @@ -15,11 +15,11 @@ #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/STLExtras.h" #include "llvm/ADT/StringMap.h" #include <list> @@ -94,10 +94,11 @@ private: BaseLayer.emitAndFinalize(Handle); } - template <typename ModuleSetT> + template <typename ModuleSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT> static std::unique_ptr<EmissionDeferredSet> - create(BaseLayerT &B, ModuleSetT Ms, - std::unique_ptr<RTDyldMemoryManager> MM); + create(BaseLayerT &B, ModuleSetT Ms, MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver); protected: virtual const GlobalValue* searchGVs(StringRef Name, @@ -109,12 +110,15 @@ private: BaseLayerHandleT Handle; }; - template <typename ModuleSetT> + template <typename ModuleSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT> class EmissionDeferredSetImpl : public EmissionDeferredSet { public: EmissionDeferredSetImpl(ModuleSetT Ms, - std::unique_ptr<RTDyldMemoryManager> MM) - : Ms(std::move(Ms)), MM(std::move(MM)) {} + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) + : Ms(std::move(Ms)), MemMgr(std::move(MemMgr)), + Resolver(std::move(Resolver)) {} protected: @@ -145,7 +149,8 @@ private: // 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(MM)); + return BaseLayer.addModuleSet(std::move(Ms), std::move(MemMgr), + std::move(Resolver)); } private: @@ -206,7 +211,8 @@ private: } ModuleSetT Ms; - std::unique_ptr<RTDyldMemoryManager> MM; + MemoryManagerPtrT MemMgr; + SymbolResolverPtrT Resolver; mutable std::unique_ptr<StringMap<const GlobalValue*>> MangledSymbols; }; @@ -223,12 +229,15 @@ public: LazyEmittingLayer(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {} /// @brief Add the given set of modules to the lazy emitting layer. - template <typename ModuleSetT> + template <typename ModuleSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT> ModuleSetHandleT addModuleSet(ModuleSetT Ms, - std::unique_ptr<RTDyldMemoryManager> MM) { + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { return ModuleSetList.insert( ModuleSetList.end(), - EmissionDeferredSet::create(BaseLayer, std::move(Ms), std::move(MM))); + EmissionDeferredSet::create(BaseLayer, std::move(Ms), std::move(MemMgr), + std::move(Resolver))); } /// @brief Remove the module set represented by the given handle. @@ -277,12 +286,16 @@ public: }; template <typename BaseLayerT> -template <typename ModuleSetT> +template <typename ModuleSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT> 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)); + 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. diff --git a/include/llvm/ExecutionEngine/Orc/LookasideRTDyldMM.h b/include/llvm/ExecutionEngine/Orc/LookasideRTDyldMM.h deleted file mode 100644 index 4456404..0000000 --- a/include/llvm/ExecutionEngine/Orc/LookasideRTDyldMM.h +++ /dev/null @@ -1,92 +0,0 @@ -//===- 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 index 9838991..f3094da 100644 --- a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -15,7 +15,7 @@ #define LLVM_EXECUTIONENGINE_ORC_OBJECTLINKINGLAYER_H #include "JITSymbol.h" -#include "LookasideRTDyldMM.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include <list> @@ -38,13 +38,12 @@ protected: 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)), + LinkedObjectSet(RuntimeDyld::MemoryManager &MemMgr, + RuntimeDyld::SymbolResolver &Resolver) + : RTDyld(llvm::make_unique<RuntimeDyld>(MemMgr, Resolver)), 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) {} + virtual ~LinkedObjectSet() {} std::unique_ptr<RuntimeDyld::LoadedObjectInfo> addObject(const object::ObjectFile &Obj) { @@ -57,14 +56,7 @@ protected: bool NeedsFinalization() const { return (State == Raw); } - void Finalize() { - State = Finalizing; - RTDyld->resolveRelocations(); - RTDyld->registerEHFrames(); - MM->finalizeMemory(); - OwnedBuffers.clear(); - State = Finalized; - } + virtual void Finalize() = 0; void mapSectionAddress(const void *LocalAddress, TargetAddress TargetAddr) { assert((State != Finalized) && @@ -76,8 +68,7 @@ protected: OwnedBuffers.push_back(std::move(B)); } - private: - std::unique_ptr<RTDyldMemoryManager> MM; + protected: std::unique_ptr<RuntimeDyld> RTDyld; enum { Raw, Finalizing, Finalized } State; @@ -87,7 +78,7 @@ protected: std::vector<std::unique_ptr<MemoryBuffer>> OwnedBuffers; }; - typedef std::list<LinkedObjectSet> LinkedObjectSetListT; + typedef std::list<std::unique_ptr<LinkedObjectSet>> LinkedObjectSetListT; public: /// @brief Handle to a set of loaded objects. @@ -99,7 +90,7 @@ public: template <typename OwningMBSet> void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) { for (auto &MB : MBs) - H->takeOwnershipOfBuffer(std::move(MB)); + (*H)->takeOwnershipOfBuffer(std::move(MB)); } }; @@ -120,6 +111,37 @@ public: /// symbols. template <typename NotifyLoadedFtor = DoNothingOnNotifyLoaded> class ObjectLinkingLayer : public ObjectLinkingLayerBase { +private: + + template <typename MemoryManagerPtrT, typename SymbolResolverPtrT> + class ConcreteLinkedObjectSet : public LinkedObjectSet { + public: + ConcreteLinkedObjectSet(MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) + : LinkedObjectSet(*MemMgr, *Resolver), MemMgr(std::move(MemMgr)), + Resolver(std::move(Resolver)) { } + + void Finalize() override { + State = Finalizing; + RTDyld->resolveRelocations(); + RTDyld->registerEHFrames(); + MemMgr->finalizeMemory(); + OwnedBuffers.clear(); + State = Finalized; + } + + private: + MemoryManagerPtrT MemMgr; + SymbolResolverPtrT Resolver; + }; + + template <typename MemoryManagerPtrT, typename SymbolResolverPtrT> + std::unique_ptr<LinkedObjectSet> + createLinkedObjectSet(MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver) { + typedef ConcreteLinkedObjectSet<MemoryManagerPtrT, SymbolResolverPtrT> LOS; + return llvm::make_unique<LOS>(std::move(MemMgr), std::move(Resolver)); + } + public: /// @brief LoadedObjectInfo list. Contains a list of owning pointers to @@ -127,21 +149,16 @@ public: 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. + /// and NotifyFinalized functors. ObjectLinkingLayer( - CreateRTDyldMMFtor CreateMemoryManager = CreateRTDyldMMFtor(), NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor()) : NotifyLoaded(std::move(NotifyLoaded)), - NotifyFinalized(std::move(NotifyFinalized)), - CreateMemoryManager(std::move(CreateMemoryManager)) {} + NotifyFinalized(std::move(NotifyFinalized)) {} /// @brief Add a set of objects (or archives) that will be treated as a unit /// for the purposes of symbol lookup and memory management. @@ -154,19 +171,18 @@ public: /// 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> + template <typename ObjSetT, + typename MemoryManagerPtrT, + typename SymbolResolverPtrT> 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; + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + ObjSetHandleT Handle = + LinkedObjSetList.insert( + LinkedObjSetList.end(), + createLinkedObjectSet(std::move(MemMgr), std::move(Resolver))); + + LinkedObjectSet &LOS = **Handle; LoadedObjInfoList LoadedObjInfos; for (auto &Obj : Objects) @@ -212,11 +228,11 @@ public: /// given object set. JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name, bool ExportedSymbolsOnly) { - if (auto Sym = H->getSymbol(Name)) { + if (auto Sym = (*H)->getSymbol(Name)) { if (Sym.isExported() || !ExportedSymbolsOnly) { auto Addr = Sym.getAddress(); auto Flags = Sym.getFlags(); - if (!H->NeedsFinalization()) { + if (!(*H)->NeedsFinalization()) { // If this instance has already been finalized then we can just return // the address. return JITSymbol(Addr, Flags); @@ -225,10 +241,10 @@ public: // it. The functor still needs to double-check whether finalization is // required, in case someone else finalizes this set before the // functor is called. - auto GetAddress = + auto GetAddress = [this, Addr, H]() { - if (H->NeedsFinalization()) { - H->Finalize(); + if ((*H)->NeedsFinalization()) { + (*H)->Finalize(); if (NotifyFinalized) NotifyFinalized(H); } @@ -244,14 +260,14 @@ public: /// @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); + (*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(); + (*H)->Finalize(); if (NotifyFinalized) NotifyFinalized(H); } @@ -260,7 +276,6 @@ private: LinkedObjectSetListT LinkedObjSetList; NotifyLoadedFtor NotifyLoaded; NotifyFinalizedFtor NotifyFinalized; - CreateRTDyldMMFtor CreateMemoryManager; }; } // End namespace orc. diff --git a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h index 792a499..207bad0 100644 --- a/include/llvm/ExecutionEngine/RTDyldMemoryManager.h +++ b/include/llvm/ExecutionEngine/RTDyldMemoryManager.h @@ -14,6 +14,7 @@ #ifndef LLVM_EXECUTIONENGINE_RTDYLDMEMORYMANAGER_H #define LLVM_EXECUTIONENGINE_RTDYLDMEMORYMANAGER_H +#include "RuntimeDyld.h" #include "llvm-c/ExecutionEngine.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CBindingWrapping.h" @@ -27,89 +28,91 @@ class ExecutionEngine; class ObjectFile; } +class MCJITMemoryManager : public RuntimeDyld::MemoryManager { +public: + /// This method is called after an object has been loaded into memory but + /// before relocations are applied to the loaded sections. The object load + /// may have been initiated by MCJIT to resolve an external symbol for another + /// object that is being finalized. In that case, the object about which + /// the memory manager is being notified will be finalized immediately after + /// the memory manager returns from this call. + /// + /// Memory managers which are preparing code for execution in an external + /// address space can use this call to remap the section addresses for the + /// newly loaded object. + virtual void notifyObjectLoaded(ExecutionEngine *EE, + const object::ObjectFile &) {} +}; + // RuntimeDyld clients often want to handle the memory management of // what gets placed where. For JIT clients, this is the subset of // JITMemoryManager required for dynamic loading of binaries. // // FIXME: As the RuntimeDyld fills out, additional routines will be needed // for the varying types of objects to be allocated. -class RTDyldMemoryManager { +class RTDyldMemoryManager : public MCJITMemoryManager, + public RuntimeDyld::SymbolResolver { RTDyldMemoryManager(const RTDyldMemoryManager&) = delete; void operator=(const RTDyldMemoryManager&) = delete; public: RTDyldMemoryManager() {} - virtual ~RTDyldMemoryManager(); - - /// Allocate a memory block of (at least) the given size suitable for - /// executable code. The SectionID is a unique identifier assigned by the JIT - /// engine, and optionally recorded by the memory manager to access a loaded - /// section. - virtual uint8_t *allocateCodeSection( - uintptr_t Size, unsigned Alignment, unsigned SectionID, - StringRef SectionName) = 0; - - /// Allocate a memory block of (at least) the given size suitable for data. - /// The SectionID is a unique identifier assigned by the JIT engine, and - /// optionally recorded by the memory manager to access a loaded section. - virtual uint8_t *allocateDataSection( - uintptr_t Size, unsigned Alignment, unsigned SectionID, - StringRef SectionName, bool IsReadOnly) = 0; - - /// Inform the memory manager about the total amount of memory required to - /// allocate all sections to be loaded: - /// \p CodeSize - the total size of all code sections - /// \p DataSizeRO - the total size of all read-only data sections - /// \p DataSizeRW - the total size of all read-write data sections - /// - /// Note that by default the callback is disabled. To enable it - /// redefine the method needsToReserveAllocationSpace to return true. - virtual void reserveAllocationSpace( - uintptr_t CodeSize, uintptr_t DataSizeRO, uintptr_t DataSizeRW) { } - - /// Override to return true to enable the reserveAllocationSpace callback. - virtual bool needsToReserveAllocationSpace() { return false; } - - /// Register the EH frames with the runtime so that c++ exceptions work. - /// - /// \p Addr parameter provides the local address of the EH frame section - /// data, while \p LoadAddr provides the address of the data in the target - /// address space. If the section has not been remapped (which will usually - /// be the case for local execution) these two values will be the same. - virtual void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size); + ~RTDyldMemoryManager() override; - virtual void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size); + void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override; + void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) override; /// This method returns the address of the specified function or variable in /// the current process. static uint64_t getSymbolAddressInProcess(const std::string &Name); + /// Legacy symbol lookup - DEPRECATED! Please override findSymbol instead. + /// /// This method returns the address of the specified function or variable. /// It is used to resolve symbols during module linking. virtual uint64_t getSymbolAddress(const std::string &Name) { 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 method returns a RuntimeDyld::SymbolInfo for the specified function + /// or variable. It is used to resolve symbols during module linking. + /// + /// By default this falls back on the legacy lookup method: + /// 'getSymbolAddress'. The address returned by getSymbolAddress is treated as + /// a strong, exported symbol, consistent with historical treatment by + /// RuntimeDyld. /// - /// 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. + /// Clients writing custom RTDyldMemoryManagers are encouraged to override + /// this method and return a SymbolInfo with the flags set correctly. This is + /// necessary for RuntimeDyld to correctly handle weak and non-exported symbols. + RuntimeDyld::SymbolInfo findSymbol(const std::string &Name) override { + return RuntimeDyld::SymbolInfo(getSymbolAddress(Name), + JITSymbolFlags::Exported); + } + + /// Legacy symbol lookup -- DEPRECATED! Please override + /// findSymbolInLogicalDylib instead. /// - /// 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. + /// Default to treating all modules as separate. virtual uint64_t getSymbolAddressInLogicalDylib(const std::string &Name) { return 0; } + /// Default to treating all modules as separate. + /// + /// By default this falls back on the legacy lookup method: + /// 'getSymbolAddressInLogicalDylib'. The address returned by + /// getSymbolAddressInLogicalDylib is treated as a strong, exported symbol, + /// consistent with historical treatment by RuntimeDyld. + /// + /// Clients writing custom RTDyldMemoryManagers are encouraged to override + /// this method and return a SymbolInfo with the flags set correctly. This is + /// necessary for RuntimeDyld to correctly handle weak and non-exported symbols. + RuntimeDyld::SymbolInfo + findSymbolInLogicalDylib(const std::string &Name) override { + return RuntimeDyld::SymbolInfo(getSymbolAddressInLogicalDylib(Name), + JITSymbolFlags::Exported); + } + /// This method returns the address of the specified function. As such it is /// only useful for resolving library symbols, not code generated symbols. /// @@ -121,30 +124,6 @@ public: /// MCJIT or RuntimeDyld. Use getSymbolAddress instead. virtual void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true); - - /// This method is called after an object has been loaded into memory but - /// before relocations are applied to the loaded sections. The object load - /// may have been initiated by MCJIT to resolve an external symbol for another - /// object that is being finalized. In that case, the object about which - /// the memory manager is being notified will be finalized immediately after - /// the memory manager returns from this call. - /// - /// Memory managers which are preparing code for execution in an external - /// address space can use this call to remap the section addresses for the - /// newly loaded object. - virtual void notifyObjectLoaded(ExecutionEngine *EE, - 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 - /// to decide whether or not to act on this method. The memory manager will - /// typically allocate all sections as read-write and then apply specific - /// permissions when this method is called. Code sections cannot be executed - /// until this function has been called. In addition, any cache coherency - /// operations needed to reliably use the memory are also performed. - /// - /// Returns true if an error occurred, false otherwise. - virtual bool finalizeMemory(std::string *ErrMsg = nullptr) = 0; }; // Create wrappers for C Binding types (see CBindingWrapping.h). @@ -153,4 +132,5 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS( } // namespace llvm + #endif diff --git a/include/llvm/ExecutionEngine/RuntimeDyld.h b/include/llvm/ExecutionEngine/RuntimeDyld.h index fe0ccda..5723f05 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyld.h +++ b/include/llvm/ExecutionEngine/RuntimeDyld.h @@ -16,7 +16,6 @@ #include "JITSymbolFlags.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include "llvm/Support/Memory.h" #include <memory> @@ -29,19 +28,13 @@ namespace object { class RuntimeDyldImpl; class RuntimeDyldCheckerImpl; - + class RuntimeDyld { friend class RuntimeDyldCheckerImpl; RuntimeDyld(const RuntimeDyld &) = delete; void operator=(const RuntimeDyld &) = delete; - // RuntimeDyldImpl is the actual class. RuntimeDyld is just the public - // interface. - std::unique_ptr<RuntimeDyldImpl> Dyld; - RTDyldMemoryManager *MM; - bool ProcessAllSections; - RuntimeDyldCheckerImpl *Checker; protected: // Change the address associated with a section when resolving relocations. // Any relocations already associated with the symbol will be re-resolved. @@ -82,7 +75,101 @@ public: unsigned BeginIdx, EndIdx; }; - RuntimeDyld(RTDyldMemoryManager *); + /// \brief Memory Management. + class MemoryManager { + public: + virtual ~MemoryManager() {}; + + /// Allocate a memory block of (at least) the given size suitable for + /// executable code. The SectionID is a unique identifier assigned by the + /// RuntimeDyld instance, and optionally recorded by the memory manager to + /// access a loaded section. + virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + StringRef SectionName) = 0; + + /// Allocate a memory block of (at least) the given size suitable for data. + /// The SectionID is a unique identifier assigned by the JIT engine, and + /// optionally recorded by the memory manager to access a loaded section. + virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + StringRef SectionName, + bool IsReadOnly) = 0; + + /// Inform the memory manager about the total amount of memory required to + /// allocate all sections to be loaded: + /// \p CodeSize - the total size of all code sections + /// \p DataSizeRO - the total size of all read-only data sections + /// \p DataSizeRW - the total size of all read-write data sections + /// + /// Note that by default the callback is disabled. To enable it + /// redefine the method needsToReserveAllocationSpace to return true. + virtual void reserveAllocationSpace(uintptr_t CodeSize, + uintptr_t DataSizeRO, + uintptr_t DataSizeRW) {} + + /// Override to return true to enable the reserveAllocationSpace callback. + virtual bool needsToReserveAllocationSpace() { return false; } + + /// Register the EH frames with the runtime so that c++ exceptions work. + /// + /// \p Addr parameter provides the local address of the EH frame section + /// data, while \p LoadAddr provides the address of the data in the target + /// address space. If the section has not been remapped (which will usually + /// be the case for local execution) these two values will be the same. + virtual void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, + size_t Size) = 0; + virtual void deregisterEHFrames(uint8_t *addr, uint64_t LoadAddr, + size_t Size) = 0; + + /// This method is called when object loading is complete and section page + /// permissions can be applied. It is up to the memory manager implementation + /// to decide whether or not to act on this method. The memory manager will + /// typically allocate all sections as read-write and then apply specific + /// permissions when this method is called. Code sections cannot be executed + /// until this function has been called. In addition, any cache coherency + /// operations needed to reliably use the memory are also performed. + /// + /// Returns true if an error occurred, false otherwise. + virtual bool finalizeMemory(std::string *ErrMsg = nullptr) = 0; + + private: + virtual void anchor(); + }; + + /// \brief Symbol resolution. + class SymbolResolver { + public: + virtual ~SymbolResolver() {}; + + /// This method returns the address of the specified function or variable. + /// It is used to resolve symbols during module linking. + virtual SymbolInfo findSymbol(const std::string &Name) = 0; + + /// 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 SymbolInfo findSymbolInLogicalDylib(const std::string &Name) = 0; + private: + virtual void anchor(); + }; + + /// \brief Construct a RuntimeDyld instance. + RuntimeDyld(MemoryManager &MemMgr, SymbolResolver &Resolver); ~RuntimeDyld(); /// Add the referenced object file to the list of objects to be loaded and @@ -131,6 +218,15 @@ public: assert(!Dyld && "setProcessAllSections must be called before loadObject."); this->ProcessAllSections = ProcessAllSections; } + +private: + // RuntimeDyldImpl is the actual class. RuntimeDyld is just the public + // interface. + std::unique_ptr<RuntimeDyldImpl> Dyld; + MemoryManager &MemMgr; + SymbolResolver &Resolver; + bool ProcessAllSections; + RuntimeDyldCheckerImpl *Checker; }; } // end namespace llvm diff --git a/include/llvm/ExecutionEngine/SectionMemoryManager.h b/include/llvm/ExecutionEngine/SectionMemoryManager.h index b825aff..0b0dcb0 100644 --- a/include/llvm/ExecutionEngine/SectionMemoryManager.h +++ b/include/llvm/ExecutionEngine/SectionMemoryManager.h @@ -16,7 +16,7 @@ #define LLVM_EXECUTIONENGINE_SECTIONMEMORYMANAGER_H #include "llvm/ADT/SmallVector.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Memory.h" @@ -40,7 +40,7 @@ class SectionMemoryManager : public RTDyldMemoryManager { public: SectionMemoryManager() { } - virtual ~SectionMemoryManager(); + ~SectionMemoryManager() override; /// \brief Allocates a memory block of (at least) the given size suitable for /// executable code. |