diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:46:15 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:46:15 +0000 |
| commit | dd58ef019b700900793a1eb48b52123db01b654e (patch) | |
| tree | fcfbb4df56a744f4ddc6122c50521dd3f1c5e196 /include/llvm/ExecutionEngine/Orc | |
| parent | 2fe5752e3a7c345cdb59e869278d36af33c13fa4 (diff) | |
Notes
Diffstat (limited to 'include/llvm/ExecutionEngine/Orc')
10 files changed, 702 insertions, 291 deletions
diff --git a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 9694b80d1928..7dab5d1bc67f 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -22,6 +22,7 @@ #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/Transforms/Utils/Cloning.h" #include <list> +#include <memory> #include <set> #include "llvm/Support/Debug.h" @@ -36,56 +37,89 @@ namespace orc { /// added to the layer below. When a stub is called it triggers the extraction /// of the function body from the original module. The extracted body is then /// compiled and executed. -template <typename BaseLayerT, typename CompileCallbackMgrT, - typename PartitioningFtor = - std::function<std::set<Function*>(Function&)>> +template <typename BaseLayerT, + typename CompileCallbackMgrT = JITCompileCallbackManager, + typename IndirectStubsMgrT = IndirectStubsManager> class CompileOnDemandLayer { private: - // Utility class for MapValue. Only materializes declarations for global - // variables. - class GlobalDeclMaterializer : public ValueMaterializer { + template <typename MaterializerFtor> + class LambdaMaterializer final : public ValueMaterializer { public: - typedef std::set<const Function*> StubSet; + LambdaMaterializer(MaterializerFtor M) : M(std::move(M)) {} + Value *materializeDeclFor(Value *V) final { return M(V); } - GlobalDeclMaterializer(Module &Dst, const StubSet *StubsToClone = nullptr) - : Dst(Dst), StubsToClone(StubsToClone) {} - - Value* materializeValueFor(Value *V) final { - if (auto *GV = dyn_cast<GlobalVariable>(V)) - return cloneGlobalVariableDecl(Dst, *GV); - else if (auto *F = dyn_cast<Function>(V)) { - auto *ClonedF = cloneFunctionDecl(Dst, *F); - if (StubsToClone && StubsToClone->count(F)) { - GlobalVariable *FnBodyPtr = - createImplPointer(*ClonedF->getType(), *ClonedF->getParent(), - ClonedF->getName() + "$orc_addr", nullptr); - makeStub(*ClonedF, *FnBodyPtr); - ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage); - ClonedF->addFnAttr(Attribute::AlwaysInline); - } - return ClonedF; - } - // Else. - return nullptr; - } private: - Module &Dst; - const StubSet *StubsToClone; + MaterializerFtor M; }; + template <typename MaterializerFtor> + LambdaMaterializer<MaterializerFtor> + createLambdaMaterializer(MaterializerFtor M) { + return LambdaMaterializer<MaterializerFtor>(std::move(M)); + } + typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT; + class ModuleOwner { + public: + ModuleOwner() = default; + ModuleOwner(const ModuleOwner&) = delete; + ModuleOwner& operator=(const ModuleOwner&) = delete; + virtual ~ModuleOwner() { } + virtual Module& getModule() const = 0; + }; + + template <typename ModulePtrT> + class ModuleOwnerImpl : public ModuleOwner { + public: + ModuleOwnerImpl(ModulePtrT ModulePtr) : ModulePtr(std::move(ModulePtr)) {} + Module& getModule() const override { return *ModulePtr; } + private: + ModulePtrT ModulePtr; + }; + + template <typename ModulePtrT> + std::unique_ptr<ModuleOwner> wrapOwnership(ModulePtrT ModulePtr) { + return llvm::make_unique<ModuleOwnerImpl<ModulePtrT>>(std::move(ModulePtr)); + } + struct LogicalModuleResources { - std::shared_ptr<Module> SourceModule; + std::unique_ptr<ModuleOwner> SourceModuleOwner; std::set<const Function*> StubsToClone; + std::unique_ptr<IndirectStubsMgrT> StubsMgr; + + LogicalModuleResources() = default; + + // Explicit move constructor to make MSVC happy. + LogicalModuleResources(LogicalModuleResources &&Other) + : SourceModuleOwner(std::move(Other.SourceModuleOwner)), + StubsToClone(std::move(Other.StubsToClone)), + StubsMgr(std::move(Other.StubsMgr)) {} + + // Explicit move assignment to make MSVC happy. + LogicalModuleResources& operator=(LogicalModuleResources &&Other) { + SourceModuleOwner = std::move(Other.SourceModuleOwner); + StubsToClone = std::move(Other.StubsToClone); + StubsMgr = std::move(Other.StubsMgr); + } + + JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { + if (Name.endswith("$stub_ptr") && !ExportedSymbolsOnly) { + assert(!ExportedSymbolsOnly && "Stubs are never exported"); + return StubsMgr->findPointer(Name.drop_back(9)); + } + return StubsMgr->findStub(Name, ExportedSymbolsOnly); + } + }; + + struct LogicalDylibResources { typedef std::function<RuntimeDyld::SymbolInfo(const std::string&)> SymbolResolverFtor; SymbolResolverFtor ExternalSymbolResolver; - PartitioningFtor Partitioner; }; typedef LogicalDylib<BaseLayerT, LogicalModuleResources, @@ -95,13 +129,25 @@ private: typedef std::list<CODLogicalDylib> LogicalDylibList; public: + /// @brief Handle to a set of loaded modules. typedef typename LogicalDylibList::iterator ModuleSetHandleT; + /// @brief Module partitioning functor. + typedef std::function<std::set<Function*>(Function&)> PartitioningFtor; + + /// @brief Builder for IndirectStubsManagers. + typedef std::function<std::unique_ptr<IndirectStubsMgrT>()> + IndirectStubsManagerBuilderT; + /// @brief Construct a compile-on-demand layer instance. - CompileOnDemandLayer(BaseLayerT &BaseLayer, CompileCallbackMgrT &CallbackMgr, - bool CloneStubsIntoPartitions) - : BaseLayer(BaseLayer), CompileCallbackMgr(CallbackMgr), + CompileOnDemandLayer(BaseLayerT &BaseLayer, PartitioningFtor Partition, + CompileCallbackMgrT &CallbackMgr, + IndirectStubsManagerBuilderT CreateIndirectStubsManager, + bool CloneStubsIntoPartitions = true) + : BaseLayer(BaseLayer), Partition(Partition), + CompileCallbackMgr(CallbackMgr), + CreateIndirectStubsManager(std::move(CreateIndirectStubsManager)), CloneStubsIntoPartitions(CloneStubsIntoPartitions) {} /// @brief Add a module to the compile-on-demand layer. @@ -122,17 +168,9 @@ public: return Resolver->findSymbol(Name); }; - LDResources.Partitioner = - [](Function &F) { - std::set<Function*> Partition; - Partition.insert(&F); - return Partition; - }; - // Process each of the modules in this module set. for (auto &M : Ms) - addLogicalModule(LogicalDylibs.back(), - std::shared_ptr<Module>(std::move(M))); + addLogicalModule(LogicalDylibs.back(), std::move(M)); return std::prev(LogicalDylibs.end()); } @@ -150,6 +188,10 @@ public: /// @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 LDI = LogicalDylibs.begin(), LDE = LogicalDylibs.end(); + LDI != LDE; ++LDI) + if (auto Symbol = findSymbolIn(LDI, Name, ExportedSymbolsOnly)) + return Symbol; return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); } @@ -162,85 +204,138 @@ public: private: - void addLogicalModule(CODLogicalDylib &LD, std::shared_ptr<Module> SrcM) { + template <typename ModulePtrT> + void addLogicalModule(CODLogicalDylib &LD, ModulePtrT SrcMPtr) { // Bump the linkage and rename any anonymous/privote members in SrcM to // ensure that everything will resolve properly after we partition SrcM. - makeAllSymbolsExternallyAccessible(*SrcM); + makeAllSymbolsExternallyAccessible(*SrcMPtr); // Create a logical module handle for SrcM within the logical dylib. auto LMH = LD.createLogicalModule(); auto &LMResources = LD.getLogicalModuleResources(LMH); - LMResources.SourceModule = SrcM; - // Create the GVs-and-stubs module. - auto GVsAndStubsM = llvm::make_unique<Module>( - (SrcM->getName() + ".globals_and_stubs").str(), - SrcM->getContext()); - GVsAndStubsM->setDataLayout(SrcM->getDataLayout()); - ValueToValueMapTy VMap; + LMResources.SourceModuleOwner = wrapOwnership(std::move(SrcMPtr)); - // Process module and create stubs. - // We create the stubs before copying the global variables as we know the - // stubs won't refer to any globals (they only refer to their implementation - // pointer) so there's no ordering/value-mapping issues. - for (auto &F : *SrcM) { + Module &SrcM = LMResources.SourceModuleOwner->getModule(); - // Skip declarations. - if (F.isDeclaration()) - continue; + // Create the GlobalValues module. + const DataLayout &DL = SrcM.getDataLayout(); + auto GVsM = llvm::make_unique<Module>((SrcM.getName() + ".globals").str(), + SrcM.getContext()); + GVsM->setDataLayout(DL); - // Record all functions defined by this module. - if (CloneStubsIntoPartitions) - LMResources.StubsToClone.insert(&F); + // Create function stubs. + ValueToValueMapTy VMap; + { + typename IndirectStubsMgrT::StubInitsMap StubInits; + for (auto &F : SrcM) { + // Skip declarations. + if (F.isDeclaration()) + continue; - // For each definition: create a callback, a stub, and a function body - // pointer. Initialize the function body pointer to point at the callback, - // and set the callback to compile the function body. - auto CCInfo = CompileCallbackMgr.getCompileCallback(SrcM->getContext()); - Function *StubF = cloneFunctionDecl(*GVsAndStubsM, F, &VMap); - GlobalVariable *FnBodyPtr = - createImplPointer(*StubF->getType(), *StubF->getParent(), - StubF->getName() + "$orc_addr", - createIRTypedAddress(*StubF->getFunctionType(), - CCInfo.getAddress())); - makeStub(*StubF, *FnBodyPtr); - CCInfo.setCompileAction( - [this, &LD, LMH, &F]() { + // Record all functions defined by this module. + if (CloneStubsIntoPartitions) + LMResources.StubsToClone.insert(&F); + + // Create a callback, associate it with the stub for the function, + // and set the compile action to compile the partition containing the + // function. + auto CCInfo = CompileCallbackMgr.getCompileCallback(); + StubInits[mangle(F.getName(), DL)] = + std::make_pair(CCInfo.getAddress(), + JITSymbolBase::flagsFromGlobalValue(F)); + CCInfo.setCompileAction([this, &LD, LMH, &F]() { return this->extractAndCompile(LD, LMH, F); }); + } + + LMResources.StubsMgr = CreateIndirectStubsManager(); + auto EC = LMResources.StubsMgr->createStubs(StubInits); + (void)EC; + // FIXME: This should be propagated back to the user. Stub creation may + // fail for remote JITs. + assert(!EC && "Error generating stubs"); } - // Now clone the global variable declarations. - GlobalDeclMaterializer GDMat(*GVsAndStubsM); - for (auto &GV : SrcM->globals()) - if (!GV.isDeclaration()) - cloneGlobalVariableDecl(*GVsAndStubsM, GV, &VMap); + // Clone global variable decls. + for (auto &GV : SrcM.globals()) + if (!GV.isDeclaration() && !VMap.count(&GV)) + cloneGlobalVariableDecl(*GVsM, GV, &VMap); + + // And the aliases. + for (auto &A : SrcM.aliases()) + if (!VMap.count(&A)) + cloneGlobalAliasDecl(*GVsM, A, VMap); + + // Now we need to clone the GV and alias initializers. + + // Initializers may refer to functions declared (but not defined) in this + // module. Build a materializer to clone decls on demand. + auto Materializer = createLambdaMaterializer( + [this, &GVsM, &LMResources](Value *V) -> Value* { + if (auto *F = dyn_cast<Function>(V)) { + // Decls in the original module just get cloned. + if (F->isDeclaration()) + return cloneFunctionDecl(*GVsM, *F); + + // Definitions in the original module (which we have emitted stubs + // for at this point) get turned into a constant alias to the stub + // instead. + const DataLayout &DL = GVsM->getDataLayout(); + std::string FName = mangle(F->getName(), DL); + auto StubSym = LMResources.StubsMgr->findStub(FName, false); + unsigned PtrBitWidth = DL.getPointerTypeSizeInBits(F->getType()); + ConstantInt *StubAddr = + ConstantInt::get(GVsM->getContext(), + APInt(PtrBitWidth, StubSym.getAddress())); + Constant *Init = ConstantExpr::getCast(Instruction::IntToPtr, + StubAddr, F->getType()); + return GlobalAlias::create(F->getFunctionType(), + F->getType()->getAddressSpace(), + F->getLinkage(), F->getName(), + Init, GVsM.get()); + } + // else.... + return nullptr; + }); - // Then clone the initializers. - for (auto &GV : SrcM->globals()) + // Clone the global variable initializers. + for (auto &GV : SrcM.globals()) if (!GV.isDeclaration()) - moveGlobalVariableInitializer(GV, VMap, &GDMat); + moveGlobalVariableInitializer(GV, VMap, &Materializer); - // Build a resolver for the stubs module and add it to the base layer. - auto GVsAndStubsResolver = createLambdaResolver( - [&LD](const std::string &Name) { + // Clone the global alias initializers. + for (auto &A : SrcM.aliases()) { + auto *NewA = cast<GlobalAlias>(VMap[&A]); + assert(NewA && "Alias not cloned?"); + Value *Init = MapValue(A.getAliasee(), VMap, RF_None, nullptr, + &Materializer); + NewA->setAliasee(cast<Constant>(Init)); + } + + // Build a resolver for the globals module and add it to the base layer. + auto GVsResolver = createLambdaResolver( + [&LD, LMH](const std::string &Name) { + auto &LMResources = LD.getLogicalModuleResources(LMH); + if (auto Sym = LMResources.StubsMgr->findStub(Name, false)) + return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags()); return LD.getDylibResources().ExternalSymbolResolver(Name); }, [](const std::string &Name) { return RuntimeDyld::SymbolInfo(nullptr); }); - std::vector<std::unique_ptr<Module>> GVsAndStubsMSet; - GVsAndStubsMSet.push_back(std::move(GVsAndStubsM)); - auto GVsAndStubsH = - BaseLayer.addModuleSet(std::move(GVsAndStubsMSet), + std::vector<std::unique_ptr<Module>> GVsMSet; + GVsMSet.push_back(std::move(GVsM)); + auto GVsH = + BaseLayer.addModuleSet(std::move(GVsMSet), llvm::make_unique<SectionMemoryManager>(), - std::move(GVsAndStubsResolver)); - LD.addToLogicalModule(LMH, GVsAndStubsH); + std::move(GVsResolver)); + LD.addToLogicalModule(LMH, GVsH); } - static std::string Mangle(StringRef Name, const DataLayout &DL) { + static std::string mangle(StringRef Name, const DataLayout &DL) { std::string MangledName; { raw_string_ostream MangledNameStream(MangledName); @@ -252,42 +347,35 @@ private: TargetAddress extractAndCompile(CODLogicalDylib &LD, LogicalModuleHandle LMH, Function &F) { - Module &SrcM = *LD.getLogicalModuleResources(LMH).SourceModule; + auto &LMResources = LD.getLogicalModuleResources(LMH); + Module &SrcM = LMResources.SourceModuleOwner->getModule(); // If F is a declaration we must already have compiled it. if (F.isDeclaration()) return 0; // Grab the name of the function being called here. - std::string CalledFnName = Mangle(F.getName(), SrcM.getDataLayout()); + std::string CalledFnName = mangle(F.getName(), SrcM.getDataLayout()); - auto Partition = LD.getDylibResources().Partitioner(F); - auto PartitionH = emitPartition(LD, LMH, Partition); + auto Part = Partition(F); + auto PartH = emitPartition(LD, LMH, Part); TargetAddress CalledAddr = 0; - for (auto *SubF : Partition) { - std::string FName = SubF->getName(); - auto FnBodySym = - BaseLayer.findSymbolIn(PartitionH, Mangle(FName, SrcM.getDataLayout()), - false); - auto FnPtrSym = - BaseLayer.findSymbolIn(*LD.moduleHandlesBegin(LMH), - Mangle(FName + "$orc_addr", - SrcM.getDataLayout()), - false); + for (auto *SubF : Part) { + std::string FnName = mangle(SubF->getName(), SrcM.getDataLayout()); + auto FnBodySym = BaseLayer.findSymbolIn(PartH, FnName, false); assert(FnBodySym && "Couldn't find function body."); - assert(FnPtrSym && "Couldn't find function body pointer."); TargetAddress FnBodyAddr = FnBodySym.getAddress(); - void *FnPtrAddr = reinterpret_cast<void*>( - static_cast<uintptr_t>(FnPtrSym.getAddress())); // If this is the function we're calling record the address so we can // return it from this function. if (SubF == &F) CalledAddr = FnBodyAddr; - memcpy(FnPtrAddr, &FnBodyAddr, sizeof(uintptr_t)); + // Update the function body pointer for the stub. + if (auto EC = LMResources.StubsMgr->updatePointer(FnName, FnBodyAddr)) + return 0; } return CalledAddr; @@ -296,13 +384,13 @@ private: template <typename PartitionT> BaseLayerModuleSetHandleT emitPartition(CODLogicalDylib &LD, LogicalModuleHandle LMH, - const PartitionT &Partition) { + const PartitionT &Part) { auto &LMResources = LD.getLogicalModuleResources(LMH); - Module &SrcM = *LMResources.SourceModule; + Module &SrcM = LMResources.SourceModuleOwner->getModule(); // Create the module. std::string NewName = SrcM.getName(); - for (auto *F : Partition) { + for (auto *F : Part) { NewName += "."; NewName += F->getName(); } @@ -310,15 +398,51 @@ private: auto M = llvm::make_unique<Module>(NewName, SrcM.getContext()); M->setDataLayout(SrcM.getDataLayout()); ValueToValueMapTy VMap; - GlobalDeclMaterializer GDM(*M, &LMResources.StubsToClone); + + auto Materializer = createLambdaMaterializer([this, &LMResources, &M, + &VMap](Value *V) -> Value * { + if (auto *GV = dyn_cast<GlobalVariable>(V)) + return cloneGlobalVariableDecl(*M, *GV); + + if (auto *F = dyn_cast<Function>(V)) { + // Check whether we want to clone an available_externally definition. + if (!LMResources.StubsToClone.count(F)) + return cloneFunctionDecl(*M, *F); + + // Ok - we want an inlinable stub. For that to work we need a decl + // for the stub pointer. + auto *StubPtr = createImplPointer(*F->getType(), *M, + F->getName() + "$stub_ptr", nullptr); + auto *ClonedF = cloneFunctionDecl(*M, *F); + makeStub(*ClonedF, *StubPtr); + ClonedF->setLinkage(GlobalValue::AvailableExternallyLinkage); + ClonedF->addFnAttr(Attribute::AlwaysInline); + return ClonedF; + } + + if (auto *A = dyn_cast<GlobalAlias>(V)) { + auto *Ty = A->getValueType(); + if (Ty->isFunctionTy()) + return Function::Create(cast<FunctionType>(Ty), + GlobalValue::ExternalLinkage, A->getName(), + M.get()); + + return new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage, + nullptr, A->getName(), nullptr, + GlobalValue::NotThreadLocal, + A->getType()->getAddressSpace()); + } + + return nullptr; + }); // Create decls in the new module. - for (auto *F : Partition) + for (auto *F : Part) cloneFunctionDecl(*M, *F, &VMap); // Move the function bodies. - for (auto *F : Partition) - moveFunctionBody(*F, VMap, &GDM); + for (auto *F : Part) + moveFunctionBody(*F, VMap, &Materializer); // Create memory manager and symbol resolver. auto MemMgr = llvm::make_unique<SectionMemoryManager>(); @@ -342,7 +466,10 @@ private: } BaseLayerT &BaseLayer; + PartitioningFtor Partition; CompileCallbackMgrT &CompileCallbackMgr; + IndirectStubsManagerBuilderT CreateIndirectStubsManager; + LogicalDylibList LogicalDylibs; bool CloneStubsIntoPartitions; }; diff --git a/include/llvm/ExecutionEngine/Orc/CompileUtils.h b/include/llvm/ExecutionEngine/Orc/CompileUtils.h index 49a1fbadb295..1e7d211196f5 100644 --- a/include/llvm/ExecutionEngine/Orc/CompileUtils.h +++ b/include/llvm/ExecutionEngine/Orc/CompileUtils.h @@ -40,7 +40,6 @@ public: 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 = diff --git a/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h b/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h new file mode 100644 index 000000000000..9fa222c340f8 --- /dev/null +++ b/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h @@ -0,0 +1,108 @@ +//===---- GlobalMappingLayer.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. +// +//===----------------------------------------------------------------------===// +// +// Convenience layer for injecting symbols that will appear in calls to +// findSymbol. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H +#define LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H + +#include "JITSymbol.h" +#include <map> + +namespace llvm { +namespace orc { + +/// @brief Global mapping layer. +/// +/// This layer overrides the findSymbol method to first search a local symbol +/// table that the client can define. It can be used to inject new symbol +/// mappings into the JIT. Beware, however: symbols within a single IR module or +/// object file will still resolve locally (via RuntimeDyld's symbol table) - +/// such internal references cannot be overriden via this layer. +template <typename BaseLayerT> +class GlobalMappingLayer { +public: + /// @brief Handle to a set of added modules. + typedef typename BaseLayerT::ModuleSetHandleT ModuleSetHandleT; + + /// @brief Construct an GlobalMappingLayer with the given BaseLayer + GlobalMappingLayer(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {} + + /// @brief Add the given module set to the JIT. + /// @return A handle for the added modules. + template <typename ModuleSetT, typename MemoryManagerPtrT, + typename SymbolResolverPtrT> + ModuleSetHandleT addModuleSet(ModuleSetT Ms, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + 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 Manually set the address to return for the given symbol. + void setGlobalMapping(const std::string &Name, TargetAddress Addr) { + SymbolTable[Name] = Addr; + } + + /// @brief Remove the given symbol from the global mapping. + void eraseGlobalMapping(const std::string &Name) { + SymbolTable.erase(Name); + } + + /// @brief Search for the given named symbol. + /// + /// This method will first search the local symbol table, returning + /// any symbol found there. If the symbol is not found in the local + /// table then this call will be passed through to the base layer. + /// + /// @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) { + auto I = SymbolTable.find(Name); + if (I != SymbolTable.end()) + return JITSymbol(I->second, JITSymbolFlags::Exported); + 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); + } + +private: + BaseLayerT &BaseLayer; + std::map<std::string, TargetAddress> SymbolTable; +}; + +} // End namespace orc. +} // End namespace llvm. + +#endif // LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H diff --git a/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h index 637902200786..e4bed95fdabf 100644 --- a/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h +++ b/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h @@ -85,8 +85,6 @@ public: ModuleSetHandleT H = BaseLayer.addObjectSet(Objects, std::move(MemMgr), std::move(Resolver)); - BaseLayer.takeOwnershipOfBuffers(H, std::move(Buffers)); - return H; } diff --git a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h index 4b7fc5e84b9c..d6ee3a846b04 100644 --- a/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h +++ b/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h @@ -27,9 +27,8 @@ namespace llvm { namespace orc { -/// @brief Base class for JITLayer independent aspects of -/// JITCompileCallbackManager. -class JITCompileCallbackManagerBase { +/// @brief Target-independent base class for compile callback management. +class JITCompileCallbackManager { public: typedef std::function<TargetAddress()> CompileFtor; @@ -51,18 +50,13 @@ public: CompileFtor &Compile; }; - /// @brief Construct a JITCompileCallbackManagerBase. + /// @brief Construct a JITCompileCallbackManager. /// @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) {} + JITCompileCallbackManager(TargetAddress ErrorHandlerAddress) + : ErrorHandlerAddress(ErrorHandlerAddress) {} - virtual ~JITCompileCallbackManagerBase() {} + virtual ~JITCompileCallbackManager() {} /// @brief Execute the callback for the given trampoline id. Called by the JIT /// to compile functions on demand. @@ -90,7 +84,11 @@ public: } /// @brief Reserve a compile callback. - virtual CompileCallbackInfo getCompileCallback(LLVMContext &Context) = 0; + CompileCallbackInfo getCompileCallback() { + TargetAddress TrampolineAddr = getAvailableTrampolineAddr(); + auto &Compile = this->ActiveTrampolines[TrampolineAddr]; + return CompileCallbackInfo(TrampolineAddr, Compile); + } /// @brief Get a CompileCallbackInfo for an existing callback. CompileCallbackInfo getCompileCallbackInfo(TargetAddress TrampolineAddr) { @@ -113,113 +111,229 @@ public: protected: TargetAddress ErrorHandlerAddress; - unsigned NumTrampolinesPerBlock; typedef std::map<TargetAddress, CompileFtor> TrampolineMapT; TrampolineMapT ActiveTrampolines; std::vector<TargetAddress> AvailableTrampolines; + +private: + + TargetAddress getAvailableTrampolineAddr() { + if (this->AvailableTrampolines.empty()) + grow(); + assert(!this->AvailableTrampolines.empty() && + "Failed to grow available trampolines."); + TargetAddress TrampolineAddr = this->AvailableTrampolines.back(); + this->AvailableTrampolines.pop_back(); + return TrampolineAddr; + } + + // Create new trampolines - to be implemented in subclasses. + virtual void grow() = 0; + + virtual void anchor(); }; -/// @brief Manage compile callbacks. -template <typename JITLayerT, typename TargetT> -class JITCompileCallbackManager : public JITCompileCallbackManagerBase { +/// @brief Manage compile callbacks for in-process JITs. +template <typename TargetT> +class LocalJITCompileCallbackManager : public JITCompileCallbackManager { public: - /// @brief Construct a JITCompileCallbackManager. - /// @param JIT JIT layer to emit callback trampolines, etc. into. - /// @param Context LLVMContext to use for trampoline & resolve block modules. + /// @brief Construct a InProcessJITCompileCallbackManager. /// @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, RuntimeDyld::MemoryManager &MemMgr, - LLVMContext &Context, - TargetAddress ErrorHandlerAddress, - unsigned NumTrampolinesPerBlock) - : JITCompileCallbackManagerBase(ErrorHandlerAddress, - NumTrampolinesPerBlock), - JIT(JIT), MemMgr(MemMgr) { - emitResolverBlock(Context); + LocalJITCompileCallbackManager(TargetAddress ErrorHandlerAddress) + : JITCompileCallbackManager(ErrorHandlerAddress) { + + /// Set up the resolver block. + std::error_code EC; + ResolverBlock = + sys::OwningMemoryBlock( + sys::Memory::allocateMappedMemory(TargetT::ResolverCodeSize, nullptr, + sys::Memory::MF_READ | + sys::Memory::MF_WRITE, EC)); + assert(!EC && "Failed to allocate resolver block"); + + TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()), + &reenter, this); + + EC = sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(), + sys::Memory::MF_READ | + sys::Memory::MF_EXEC); + assert(!EC && "Failed to mprotect resolver block"); } - /// @brief Get/create a compile callback with the given signature. - CompileCallbackInfo getCompileCallback(LLVMContext &Context) final { - TargetAddress TrampolineAddr = getAvailableTrampolineAddr(Context); - auto &Compile = this->ActiveTrampolines[TrampolineAddr]; - return CompileCallbackInfo(TrampolineAddr, Compile); +private: + + static TargetAddress reenter(void *CCMgr, void *TrampolineId) { + JITCompileCallbackManager *Mgr = + static_cast<JITCompileCallbackManager*>(CCMgr); + return Mgr->executeCompileCallback( + static_cast<TargetAddress>( + reinterpret_cast<uintptr_t>(TrampolineId))); } + void grow() override { + assert(this->AvailableTrampolines.empty() && "Growing prematurely?"); + + std::error_code EC; + auto TrampolineBlock = + sys::OwningMemoryBlock( + sys::Memory::allocateMappedMemory(TargetT::PageSize, nullptr, + sys::Memory::MF_READ | + sys::Memory::MF_WRITE, EC)); + assert(!EC && "Failed to allocate trampoline block"); + + + unsigned NumTrampolines = + (TargetT::PageSize - TargetT::PointerSize) / TargetT::TrampolineSize; + + uint8_t *TrampolineMem = static_cast<uint8_t*>(TrampolineBlock.base()); + TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(), + NumTrampolines); + + for (unsigned I = 0; I < NumTrampolines; ++I) + this->AvailableTrampolines.push_back( + static_cast<TargetAddress>(reinterpret_cast<uintptr_t>( + TrampolineMem + (I * TargetT::TrampolineSize)))); + + EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(), + sys::Memory::MF_READ | + sys::Memory::MF_EXEC); + assert(!EC && "Failed to mprotect trampoline block"); + + TrampolineBlocks.push_back(std::move(TrampolineBlock)); + } + + sys::OwningMemoryBlock ResolverBlock; + std::vector<sys::OwningMemoryBlock> TrampolineBlocks; +}; + +/// @brief Base class for managing collections of named indirect stubs. +class IndirectStubsManager { +public: + + /// @brief Map type for initializing the manager. See init. + typedef StringMap<std::pair<TargetAddress, JITSymbolFlags>> StubInitsMap; + + virtual ~IndirectStubsManager() {} + + /// @brief Create a single stub with the given name, target address and flags. + virtual std::error_code createStub(StringRef StubName, TargetAddress StubAddr, + JITSymbolFlags StubFlags) = 0; + + /// @brief Create StubInits.size() stubs with the given names, target + /// addresses, and flags. + virtual std::error_code createStubs(const StubInitsMap &StubInits) = 0; + + /// @brief Find the stub with the given name. If ExportedStubsOnly is true, + /// this will only return a result if the stub's flags indicate that it + /// is exported. + virtual JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) = 0; + + /// @brief Find the implementation-pointer for the stub. + virtual JITSymbol findPointer(StringRef Name) = 0; + + /// @brief Change the value of the implementation pointer for the stub. + virtual std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) = 0; private: + virtual void anchor(); +}; + +/// @brief IndirectStubsManager implementation for a concrete target, e.g. +/// OrcX86_64. (See OrcTargetSupport.h). +template <typename TargetT> +class LocalIndirectStubsManager : public IndirectStubsManager { +public: + + std::error_code createStub(StringRef StubName, TargetAddress StubAddr, + JITSymbolFlags StubFlags) override { + if (auto EC = reserveStubs(1)) + return EC; - 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; + createStubInternal(StubName, StubAddr, StubFlags); + + return std::error_code(); } - void emitResolverBlock(LLVMContext &Context) { - std::unique_ptr<Module> M(new Module("resolver_block_module", - Context)); - TargetT::insertResolverBlock(*M, *this); - auto NonResolver = - createLambdaResolver( - [](const std::string &Name) -> RuntimeDyld::SymbolInfo { - llvm_unreachable("External symbols in resolver block?"); - }, - [](const std::string &Name) -> RuntimeDyld::SymbolInfo { - llvm_unreachable("Dylib symbols in resolver block?"); - }); - auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr, - std::move(NonResolver)); - JIT.emitAndFinalize(H); - auto ResolverBlockSymbol = - JIT.findSymbolIn(H, TargetT::ResolverBlockName, false); - assert(ResolverBlockSymbol && "Failed to insert resolver block"); - ResolverBlockAddr = ResolverBlockSymbol.getAddress(); + std::error_code createStubs(const StubInitsMap &StubInits) override { + if (auto EC = reserveStubs(StubInits.size())) + return EC; + + for (auto &Entry : StubInits) + createStubInternal(Entry.first(), Entry.second.first, + Entry.second.second); + + return std::error_code(); } - 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; + JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override { + auto I = StubIndexes.find(Name); + if (I == StubIndexes.end()) + return nullptr; + auto Key = I->second.first; + void *StubAddr = IndirectStubsInfos[Key.first].getStub(Key.second); + assert(StubAddr && "Missing stub address"); + auto StubTargetAddr = + static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(StubAddr)); + auto StubSymbol = JITSymbol(StubTargetAddr, I->second.second); + if (ExportedStubsOnly && !StubSymbol.isExported()) + return nullptr; + return StubSymbol; } - 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 NonResolver = - createLambdaResolver( - [](const std::string &Name) -> RuntimeDyld::SymbolInfo { - llvm_unreachable("External symbols in trampoline block?"); - }, - [](const std::string &Name) -> RuntimeDyld::SymbolInfo { - llvm_unreachable("Dylib symbols in trampoline block?"); - }); - auto H = JIT.addModuleSet(SingletonSet(std::move(M)), &MemMgr, - std::move(NonResolver)); - 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()); - } + JITSymbol findPointer(StringRef Name) override { + auto I = StubIndexes.find(Name); + if (I == StubIndexes.end()) + return nullptr; + auto Key = I->second.first; + void *PtrAddr = IndirectStubsInfos[Key.first].getPtr(Key.second); + assert(PtrAddr && "Missing pointer address"); + auto PtrTargetAddr = + static_cast<TargetAddress>(reinterpret_cast<uintptr_t>(PtrAddr)); + return JITSymbol(PtrTargetAddr, I->second.second); + } + + std::error_code updatePointer(StringRef Name, TargetAddress NewAddr) override { + auto I = StubIndexes.find(Name); + assert(I != StubIndexes.end() && "No stub pointer for symbol"); + auto Key = I->second.first; + *IndirectStubsInfos[Key.first].getPtr(Key.second) = + reinterpret_cast<void*>(static_cast<uintptr_t>(NewAddr)); + return std::error_code(); } - JITLayerT &JIT; - RuntimeDyld::MemoryManager &MemMgr; - TargetAddress ResolverBlockAddr; +private: + + std::error_code reserveStubs(unsigned NumStubs) { + if (NumStubs <= FreeStubs.size()) + return std::error_code(); + + unsigned NewStubsRequired = NumStubs - FreeStubs.size(); + unsigned NewBlockId = IndirectStubsInfos.size(); + typename TargetT::IndirectStubsInfo ISI; + if (auto EC = TargetT::emitIndirectStubsBlock(ISI, NewStubsRequired, + nullptr)) + return EC; + for (unsigned I = 0; I < ISI.getNumStubs(); ++I) + FreeStubs.push_back(std::make_pair(NewBlockId, I)); + IndirectStubsInfos.push_back(std::move(ISI)); + return std::error_code(); + } + + void createStubInternal(StringRef StubName, TargetAddress InitAddr, + JITSymbolFlags StubFlags) { + auto Key = FreeStubs.back(); + FreeStubs.pop_back(); + *IndirectStubsInfos[Key.first].getPtr(Key.second) = + reinterpret_cast<void*>(static_cast<uintptr_t>(InitAddr)); + StubIndexes[StubName] = std::make_pair(Key, StubFlags); + } + + std::vector<typename TargetT::IndirectStubsInfo> IndirectStubsInfos; + typedef std::pair<uint16_t, uint16_t> StubKey; + std::vector<StubKey> FreeStubs; + StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes; }; /// @brief Build a function pointer of FunctionType with the given constant @@ -236,7 +350,7 @@ GlobalVariable* createImplPointer(PointerType &PT, Module &M, /// @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); +void makeStub(Function &F, Value &ImplPointer); /// @brief Raise linkage types and rename as necessary to ensure that all /// symbols are accessible for other modules. @@ -289,6 +403,10 @@ void moveGlobalVariableInitializer(GlobalVariable &OrigGV, ValueMaterializer *Materializer = nullptr, GlobalVariable *NewGV = nullptr); +/// @brief Clone +GlobalAlias* cloneGlobalAliasDecl(Module &Dst, const GlobalAlias &OrigA, + ValueToValueMapTy &VMap); + } // End namespace orc. } // End namespace llvm. diff --git a/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h index 93ba02b38706..a5286ff9adde 100644 --- a/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h @@ -67,10 +67,10 @@ private: } 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. + // Calling "emit" can trigger a recursive call to 'find' (e.g. to check + // for pre-existing definitions of common-symbol), but any symbol in + // this module would already have been found internally (in the + // RuntimeDyld that did the lookup), so just return a nullptr here. return nullptr; case Emitted: return B.findSymbolIn(Handle, Name, ExportedSymbolsOnly); diff --git a/include/llvm/ExecutionEngine/Orc/LogicalDylib.h b/include/llvm/ExecutionEngine/Orc/LogicalDylib.h index 28700ef347d6..883fa9eac560 100644 --- a/include/llvm/ExecutionEngine/Orc/LogicalDylib.h +++ b/include/llvm/ExecutionEngine/Orc/LogicalDylib.h @@ -14,6 +14,10 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_LOGICALDYLIB_H #define LLVM_EXECUTIONENGINE_ORC_LOGICALDYLIB_H +#include "llvm/ExecutionEngine/Orc/JITSymbol.h" +#include <string> +#include <vector> + namespace llvm { namespace orc { @@ -28,6 +32,12 @@ private: typedef std::vector<BaseLayerModuleSetHandleT> BaseLayerHandleList; struct LogicalModule { + // Make this move-only to ensure they don't get duplicated across moves of + // LogicalDylib or anything like that. + LogicalModule(LogicalModule &&RHS) + : Resources(std::move(RHS.Resources)), + BaseLayerHandles(std::move(RHS.BaseLayerHandles)) {} + LogicalModule() = default; LogicalModuleResources Resources; BaseLayerHandleList BaseLayerHandles; }; @@ -46,6 +56,13 @@ public: BaseLayer.removeModuleSet(BLH); } + // If possible, remove this and ~LogicalDylib once the work in the dtor is + // moved to members (eg: self-unregistering base layer handles). + LogicalDylib(LogicalDylib &&RHS) + : BaseLayer(std::move(RHS.BaseLayer)), + LogicalModules(std::move(RHS.LogicalModules)), + DylibResources(std::move(RHS.DylibResources)) {} + LogicalModuleHandle createLogicalModule() { LogicalModules.push_back(LogicalModule()); return std::prev(LogicalModules.end()); @@ -69,22 +86,27 @@ public: } JITSymbol findSymbolInLogicalModule(LogicalModuleHandle LMH, - const std::string &Name) { + const std::string &Name, + bool ExportedSymbolsOnly) { + + if (auto StubSym = LMH->Resources.findSymbol(Name, ExportedSymbolsOnly)) + return StubSym; + for (auto BLH : LMH->BaseLayerHandles) - if (auto Symbol = BaseLayer.findSymbolIn(BLH, Name, false)) + if (auto Symbol = BaseLayer.findSymbolIn(BLH, Name, ExportedSymbolsOnly)) return Symbol; return nullptr; } JITSymbol findSymbolInternally(LogicalModuleHandle LMH, const std::string &Name) { - if (auto Symbol = findSymbolInLogicalModule(LMH, Name)) + if (auto Symbol = findSymbolInLogicalModule(LMH, Name, false)) return Symbol; for (auto LMI = LogicalModules.begin(), LME = LogicalModules.end(); LMI != LME; ++LMI) { if (LMI != LMH) - if (auto Symbol = findSymbolInLogicalModule(LMI, Name)) + if (auto Symbol = findSymbolInLogicalModule(LMI, Name, false)) return Symbol; } @@ -92,11 +114,10 @@ public: } JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) { - for (auto &LM : LogicalModules) - for (auto BLH : LM.BaseLayerHandles) - if (auto Symbol = - BaseLayer.findSymbolIn(BLH, Name, ExportedSymbolsOnly)) - return Symbol; + for (auto LMI = LogicalModules.begin(), LME = LogicalModules.end(); + LMI != LME; ++LMI) + if (auto Sym = findSymbolInLogicalModule(LMI, Name, ExportedSymbolsOnly)) + return Sym; return nullptr; } @@ -106,7 +127,6 @@ protected: BaseLayerT BaseLayer; LogicalModuleList LogicalModules; LogicalDylibResources DylibResources; - }; } // End namespace orc. diff --git a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h index f3094dafae3c..2acfecfb94dc 100644 --- a/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -39,9 +39,12 @@ protected: void operator=(const LinkedObjectSet&) = delete; public: LinkedObjectSet(RuntimeDyld::MemoryManager &MemMgr, - RuntimeDyld::SymbolResolver &Resolver) + RuntimeDyld::SymbolResolver &Resolver, + bool ProcessAllSections) : RTDyld(llvm::make_unique<RuntimeDyld>(MemMgr, Resolver)), - State(Raw) {} + State(Raw) { + RTDyld->setProcessAllSections(ProcessAllSections); + } virtual ~LinkedObjectSet() {} @@ -64,18 +67,9 @@ protected: RTDyld->mapSectionAddress(LocalAddress, TargetAddr); } - void takeOwnershipOfBuffer(std::unique_ptr<MemoryBuffer> B) { - OwnedBuffers.push_back(std::move(B)); - } - protected: 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<std::unique_ptr<LinkedObjectSet>> LinkedObjectSetListT; @@ -83,16 +77,6 @@ protected: 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. @@ -117,16 +101,16 @@ private: class ConcreteLinkedObjectSet : public LinkedObjectSet { public: ConcreteLinkedObjectSet(MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) - : LinkedObjectSet(*MemMgr, *Resolver), MemMgr(std::move(MemMgr)), - Resolver(std::move(Resolver)) { } + SymbolResolverPtrT Resolver, + bool ProcessAllSections) + : LinkedObjectSet(*MemMgr, *Resolver, ProcessAllSections), + MemMgr(std::move(MemMgr)), Resolver(std::move(Resolver)) { } void Finalize() override { State = Finalizing; RTDyld->resolveRelocations(); RTDyld->registerEHFrames(); MemMgr->finalizeMemory(); - OwnedBuffers.clear(); State = Finalized; } @@ -137,9 +121,11 @@ private: template <typename MemoryManagerPtrT, typename SymbolResolverPtrT> std::unique_ptr<LinkedObjectSet> - createLinkedObjectSet(MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver) { + createLinkedObjectSet(MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver, + bool ProcessAllSections) { typedef ConcreteLinkedObjectSet<MemoryManagerPtrT, SymbolResolverPtrT> LOS; - return llvm::make_unique<LOS>(std::move(MemMgr), std::move(Resolver)); + return llvm::make_unique<LOS>(std::move(MemMgr), std::move(Resolver), + ProcessAllSections); } public: @@ -158,7 +144,18 @@ public: NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor()) : NotifyLoaded(std::move(NotifyLoaded)), - NotifyFinalized(std::move(NotifyFinalized)) {} + NotifyFinalized(std::move(NotifyFinalized)), + ProcessAllSections(false) {} + + /// @brief Set the 'ProcessAllSections' flag. + /// + /// If set to true, all sections in each object file will be allocated using + /// the memory manager, rather than just the sections required for execution. + /// + /// This is kludgy, and may be removed in the future. + void setProcessAllSections(bool ProcessAllSections) { + this->ProcessAllSections = ProcessAllSections; + } /// @brief Add a set of objects (or archives) that will be treated as a unit /// for the purposes of symbol lookup and memory management. @@ -180,7 +177,8 @@ public: ObjSetHandleT Handle = LinkedObjSetList.insert( LinkedObjSetList.end(), - createLinkedObjectSet(std::move(MemMgr), std::move(Resolver))); + createLinkedObjectSet(std::move(MemMgr), std::move(Resolver), + ProcessAllSections)); LinkedObjectSet &LOS = **Handle; LoadedObjInfoList LoadedObjInfos; @@ -276,6 +274,7 @@ private: LinkedObjectSetListT LinkedObjSetList; NotifyLoadedFtor NotifyLoaded; NotifyFinalizedFtor NotifyFinalized; + bool ProcessAllSections; }; } // End namespace orc. diff --git a/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h b/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h index 7af662085474..f96e83ed5a1a 100644 --- a/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h +++ b/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h @@ -87,14 +87,6 @@ public: BaseLayer.mapSectionAddress(H, LocalAddress, TargetAddr); } - // 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) { - BaseLayer.takeOwnershipOfBuffers(H, std::move(MBs)); - } - /// @brief Access the transform functor directly. TransformFtor &getTransform() { return Transform; } diff --git a/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h b/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h index 309f5a96090e..246d3e0a9fc6 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h +++ b/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h @@ -9,42 +9,92 @@ // // Target specific code for Orc, e.g. callback assembly. // +// Target classes should be part of the JIT *target* process, not the host +// process (except where you're doing hosted JITing and the two are one and the +// same). +// //===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H #define LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H #include "IndirectionUtils.h" +#include "llvm/Support/Memory.h" namespace llvm { namespace orc { class OrcX86_64 { public: - static const char *ResolverBlockName; + static const unsigned PageSize = 4096; + static const unsigned PointerSize = 8; + static const unsigned TrampolineSize = 8; + static const unsigned ResolverCodeSize = 0x78; - /// @brief Insert module-level inline callback asm into module M for the - /// symbols managed by JITResolveCallbackHandler J. - static void insertResolverBlock(Module &M, - JITCompileCallbackManagerBase &JCBM); + typedef TargetAddress (*JITReentryFn)(void *CallbackMgr, + void *TrampolineId); - /// @brief Get a label name from the given index. - typedef std::function<std::string(unsigned)> LabelNameFtor; + /// @brief Write the resolver code into the given memory. The user is be + /// responsible for allocating the memory and setting permissions. + static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, + void *CallbackMgr); - /// @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); + /// @brief Write the requsted number of trampolines into the given memory, + /// which must be big enough to hold 1 pointer, plus NumTrampolines + /// trampolines. + static void writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr, + unsigned NumTrampolines); + + /// @brief Provide information about stub blocks generated by the + /// makeIndirectStubsBlock function. + class IndirectStubsInfo { + friend class OrcX86_64; + public: + const static unsigned StubSize = 8; + const static unsigned PtrSize = 8; + + IndirectStubsInfo() : NumStubs(0) {} + IndirectStubsInfo(IndirectStubsInfo &&Other) + : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) { + Other.NumStubs = 0; + } + IndirectStubsInfo& operator=(IndirectStubsInfo &&Other) { + NumStubs = Other.NumStubs; + Other.NumStubs = 0; + StubsMem = std::move(Other.StubsMem); + return *this; + } + /// @brief Number of stubs in this block. + unsigned getNumStubs() const { return NumStubs; } + + /// @brief Get a pointer to the stub at the given index, which must be in + /// the range 0 .. getNumStubs() - 1. + void* getStub(unsigned Idx) const { + return static_cast<uint64_t*>(StubsMem.base()) + Idx; + } + + /// @brief Get a pointer to the implementation-pointer at the given index, + /// which must be in the range 0 .. getNumStubs() - 1. + void** getPtr(unsigned Idx) const { + char *PtrsBase = + static_cast<char*>(StubsMem.base()) + NumStubs * StubSize; + return reinterpret_cast<void**>(PtrsBase) + Idx; + } + private: + unsigned NumStubs; + sys::OwningMemoryBlock StubsMem; + }; + + /// @brief Emit at least MinStubs worth of indirect call stubs, rounded out to + /// the nearest page size. + /// + /// E.g. Asking for 4 stubs on x86-64, where stubs are 8-bytes, with 4k + /// pages will return a block of 512 stubs (4096 / 8 = 512). Asking for 513 + /// will return a block of 1024 (2-pages worth). + static std::error_code emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, + unsigned MinStubs, + void *InitialPtrVal); }; } // End namespace orc. |
