summaryrefslogtreecommitdiff
path: root/include/llvm/ExecutionEngine/Orc
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-12-30 11:46:15 +0000
commitdd58ef019b700900793a1eb48b52123db01b654e (patch)
treefcfbb4df56a744f4ddc6122c50521dd3f1c5e196 /include/llvm/ExecutionEngine/Orc
parent2fe5752e3a7c345cdb59e869278d36af33c13fa4 (diff)
Notes
Diffstat (limited to 'include/llvm/ExecutionEngine/Orc')
-rw-r--r--include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h367
-rw-r--r--include/llvm/ExecutionEngine/Orc/CompileUtils.h1
-rw-r--r--include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h108
-rw-r--r--include/llvm/ExecutionEngine/Orc/IRCompileLayer.h2
-rw-r--r--include/llvm/ExecutionEngine/Orc/IndirectionUtils.h312
-rw-r--r--include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h8
-rw-r--r--include/llvm/ExecutionEngine/Orc/LogicalDylib.h40
-rw-r--r--include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h57
-rw-r--r--include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h8
-rw-r--r--include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h90
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.