using IndirectStubsManagerBuilder =
std::function<std::unique_ptr<IndirectStubsManager>()>;
- using GetAvailableContextFunction = std::function<LLVMContext &()>;
-
CompileOnDemandLayer2(ExecutionSession &ES, IRLayer &BaseLayer,
JITCompileCallbackManager &CCMgr,
- IndirectStubsManagerBuilder BuildIndirectStubsManager,
- GetAvailableContextFunction GetAvailableContext);
+ IndirectStubsManagerBuilder BuildIndirectStubsManager);
- Error add(JITDylib &V, VModuleKey K, std::unique_ptr<Module> M) override;
+ Error add(JITDylib &V, VModuleKey K, ThreadSafeModule TSM) override;
void emit(MaterializationResponsibility R, VModuleKey K,
- std::unique_ptr<Module> M) override;
+ ThreadSafeModule TSM) override;
private:
using StubManagersMap =
IndirectStubsManager &getStubsManager(const JITDylib &JD);
void emitExtractedFunctionsModule(MaterializationResponsibility R,
- std::unique_ptr<Module> M);
+ ThreadSafeModule TSM);
mutable std::mutex CODLayerMutex;
JITCompileCallbackManager &CCMgr;
IndirectStubsManagerBuilder BuildIndirectStubsManager;
StubManagersMap StubsMgrs;
- GetAvailableContextFunction GetAvailableContext;
};
/// Compile-on-demand layer.
std::function<Expected<std::unique_ptr<MemoryBuffer>>(Module &)>;
using NotifyCompiledFunction =
- std::function<void(VModuleKey K, std::unique_ptr<Module>)>;
+ std::function<void(VModuleKey K, ThreadSafeModule TSM)>;
IRCompileLayer2(ExecutionSession &ES, ObjectLayer &BaseLayer,
CompileFunction Compile);
void setNotifyCompiled(NotifyCompiledFunction NotifyCompiled);
void emit(MaterializationResponsibility R, VModuleKey K,
- std::unique_ptr<Module> M) override;
+ ThreadSafeModule TSM) override;
private:
mutable std::mutex IRLayerMutex;
class IRTransformLayer2 : public IRLayer {
public:
-
using TransformFunction =
- std::function<Expected<std::unique_ptr<Module>>(std::unique_ptr<Module>)>;
+ std::function<Expected<ThreadSafeModule>(ThreadSafeModule)>;
IRTransformLayer2(ExecutionSession &ES, IRLayer &BaseLayer,
TransformFunction Transform = identityTransform);
}
void emit(MaterializationResponsibility R, VModuleKey K,
- std::unique_ptr<Module> M) override;
+ ThreadSafeModule TSM) override;
- static std::unique_ptr<Module> identityTransform(std::unique_ptr<Module> M) {
- return M;
+ static ThreadSafeModule identityTransform(ThreadSafeModule TSM) {
+ return TSM;
}
private:
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
#include "llvm/Target/TargetMachine.h"
namespace llvm {
Error defineAbsolute(StringRef Name, JITEvaluatedSymbol Address);
/// Adds an IR module to the given JITDylib.
- Error addIRModule(JITDylib &JD, std::unique_ptr<Module> M);
+ Error addIRModule(JITDylib &JD, ThreadSafeModule TSM);
/// Adds an IR module to the Main JITDylib.
- Error addIRModule(std::unique_ptr<Module> M) {
- return addIRModule(Main, std::move(M));
+ Error addIRModule(ThreadSafeModule TSM) {
+ return addIRModule(Main, std::move(TSM));
}
/// Adds an object file to the given JITDylib.
public:
/// Create an LLLazyJIT instance.
static Expected<std::unique_ptr<LLLazyJIT>>
- Create(std::unique_ptr<TargetMachine> TM, DataLayout DL, LLVMContext &Ctx);
+ Create(std::unique_ptr<TargetMachine> TM, DataLayout DL);
/// Set an IR transform (e.g. pass manager pipeline) to run on each function
/// when it is compiled.
}
/// Add a module to be lazily compiled to JITDylib JD.
- Error addLazyIRModule(JITDylib &JD, std::unique_ptr<Module> M);
+ Error addLazyIRModule(JITDylib &JD, ThreadSafeModule M);
/// Add a module to be lazily compiled to the main JITDylib.
- Error addLazyIRModule(std::unique_ptr<Module> M) {
+ Error addLazyIRModule(ThreadSafeModule M) {
return addLazyIRModule(Main, std::move(M));
}
private:
LLLazyJIT(std::unique_ptr<ExecutionSession> ES,
- std::unique_ptr<TargetMachine> TM, DataLayout DL, LLVMContext &Ctx,
+ std::unique_ptr<TargetMachine> TM, DataLayout DL,
std::unique_ptr<JITCompileCallbackManager> CCMgr,
std::function<std::unique_ptr<IndirectStubsManager>()> ISMBuilder);
#define LLVM_EXECUTIONENGINE_ORC_LAYER_H
#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/MemoryBuffer.h"
/// Returns the ExecutionSession for this layer.
ExecutionSession &getExecutionSession() { return ES; }
+ /// Sets the CloneToNewContextOnEmit flag (false by default).
+ ///
+ /// When set, IR modules added to this layer will be cloned on to a new
+ /// context before emit is called. This can be used by clients who want
+ /// to load all IR using one LLVMContext (to save memory via type and
+ /// constant uniquing), but want to move Modules to fresh contexts before
+ /// compiling them to enable concurrent compilation.
+ /// Single threaded clients, or clients who load every module on a new
+ /// context, need not set this.
+ void setCloneToNewContextOnEmit(bool CloneToNewContextOnEmit);
+
+ /// Returns the current value of the CloneToNewContextOnEmit flag.
+ bool getCloneToNewContextOnEmit() const { return CloneToNewContextOnEmit; }
+
/// Adds a MaterializationUnit representing the given IR to the given
/// JITDylib.
- virtual Error add(JITDylib &JD, VModuleKey K, std::unique_ptr<Module> M);
+ virtual Error add(JITDylib &JD, VModuleKey K, ThreadSafeModule TSM);
/// Adds a MaterializationUnit representing the given IR to the main
/// JITDylib.
- Error add(VModuleKey K, std::unique_ptr<Module> M) {
- return add(ES.getMainJITDylib(), K, std::move(M));
+ Error add(VModuleKey K, ThreadSafeModule TSM) {
+ return add(ES.getMainJITDylib(), K, std::move(TSM));
}
/// Emit should materialize the given IR.
virtual void emit(MaterializationResponsibility R, VModuleKey K,
- std::unique_ptr<Module> M) = 0;
+ ThreadSafeModule TSM) = 0;
private:
+ bool CloneToNewContextOnEmit = false;
ExecutionSession &ES;
};
/// Create an IRMaterializationLayer. Scans the module to build the
/// SymbolFlags and SymbolToDefinition maps.
- IRMaterializationUnit(ExecutionSession &ES, std::unique_ptr<Module> M);
+ IRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM);
/// Create an IRMaterializationLayer from a module, and pre-existing
/// SymbolFlags and SymbolToDefinition maps. The maps must provide
/// entries for each definition in M.
/// This constructor is useful for delegating work from one
/// IRMaterializationUnit to another.
- IRMaterializationUnit(std::unique_ptr<Module> M, SymbolFlagsMap SymbolFlags,
+ IRMaterializationUnit(ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags,
SymbolNameToDefinitionMap SymbolToDefinition);
protected:
- std::unique_ptr<Module> M;
+ ThreadSafeModule TSM;
SymbolNameToDefinitionMap SymbolToDefinition;
private:
class BasicIRLayerMaterializationUnit : public IRMaterializationUnit {
public:
BasicIRLayerMaterializationUnit(IRLayer &L, VModuleKey K,
- std::unique_ptr<Module> M);
+ ThreadSafeModule TSM);
+
private:
void materialize(MaterializationResponsibility R) override;
--- /dev/null
+//===----------- ThreadSafeModule.h -- Layer interfaces ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Thread safe wrappers and utilities for Module and LLVMContext.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
+#define LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
+
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+
+namespace llvm {
+namespace orc {
+
+/// An LLVMContext together with an associated mutex that can be used to lock
+/// the context to prevent concurrent access by other threads.
+class ThreadSafeContext {
+private:
+
+ struct State {
+ State(std::unique_ptr<LLVMContext> Ctx)
+ : Ctx(std::move(Ctx)) {}
+
+ std::unique_ptr<LLVMContext> Ctx;
+ std::recursive_mutex Mutex;
+ };
+
+public:
+
+ // RAII based lock for ThreadSafeContext.
+ class Lock {
+ private:
+ using UnderlyingLock = std::lock_guard<std::recursive_mutex>;
+ public:
+
+ Lock(std::shared_ptr<State> S)
+ : S(std::move(S)),
+ L(llvm::make_unique<UnderlyingLock>(this->S->Mutex)) {}
+ private:
+ std::shared_ptr<State> S;
+ std::unique_ptr<UnderlyingLock> L;
+ };
+
+ /// Construct a null context.
+ ThreadSafeContext() = default;
+
+ /// Construct a ThreadSafeContext from the given LLVMContext.
+ ThreadSafeContext(std::unique_ptr<LLVMContext> NewCtx)
+ : S(std::make_shared<State>(std::move(NewCtx))) {
+ assert(S->Ctx != nullptr &&
+ "Can not construct a ThreadSafeContext from a nullptr");
+ }
+
+ /// Returns a pointer to the LLVMContext that was used to construct this
+ /// instance, or null if the instance was default constructed.
+ LLVMContext* getContext() {
+ return S ? S->Ctx.get() : nullptr;
+ }
+
+ Lock getLock() {
+ assert(S && "Can not lock an empty ThreadSafeContext");
+ return Lock(S);
+ }
+
+private:
+ std::shared_ptr<State> S;
+};
+
+/// An LLVM Module together with a shared ThreadSafeContext.
+class ThreadSafeModule {
+public:
+ /// Default construct a ThreadSafeModule. This results in a null module and
+ /// null context.
+ ThreadSafeModule() = default;
+
+ /// Construct a ThreadSafeModule from a unique_ptr<Module> and a
+ /// unique_ptr<LLVMContext>. This creates a new ThreadSafeContext from the
+ /// given context.
+ ThreadSafeModule(std::unique_ptr<Module> M,
+ std::unique_ptr<LLVMContext> Ctx)
+ : M(std::move(M)), TSCtx(std::move(Ctx)) {}
+
+ ThreadSafeModule(std::unique_ptr<Module> M,
+ ThreadSafeContext TSCtx)
+ : M(std::move(M)), TSCtx(std::move(TSCtx)) {}
+
+ Module* getModule() { return M.get(); }
+
+ ThreadSafeContext::Lock getContextLock() { return TSCtx.getLock(); }
+
+ explicit operator bool() {
+ if (M) {
+ assert(TSCtx.getContext() && "Non-null module must have non-null context");
+ return true;
+ }
+ return false;
+ }
+
+private:
+ std::unique_ptr<Module> M;
+ ThreadSafeContext TSCtx;
+};
+
+using GVPredicate = std::function<bool(const GlobalValue&)>;
+using GVModifier = std::function<void(GlobalValue&)>;
+
+/// Clones the given module on to a new context.
+ThreadSafeModule
+cloneToNewContext(ThreadSafeModule &TSMW,
+ GVPredicate ShouldCloneDef = GVPredicate(),
+ GVModifier UpdateClonedDefSource = GVModifier());
+
+} // End namespace orc
+} // End namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_THREADSAFEMODULEWRAPPER_H
OrcMCJITReplacement.cpp
RPCUtils.cpp
RTDyldObjectLinkingLayer.cpp
+ ThreadSafeModule.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Transforms/Utils/Cloning.h"
using namespace llvm;
using namespace llvm::orc;
R.replace(symbolAliases(std::move(Aliases)));
}
-static std::unique_ptr<Module>
-extractAndClone(Module &M, LLVMContext &NewContext, StringRef Suffix,
- function_ref<bool(const GlobalValue *)> ShouldCloneDefinition) {
- SmallVector<char, 1> ClonedModuleBuffer;
-
- {
- std::set<GlobalValue *> ClonedDefsInSrc;
- ValueToValueMapTy VMap;
- auto Tmp = CloneModule(M, VMap, [&](const GlobalValue *GV) {
- if (ShouldCloneDefinition(GV)) {
- ClonedDefsInSrc.insert(const_cast<GlobalValue *>(GV));
- return true;
- }
- return false;
- });
-
- for (auto *GV : ClonedDefsInSrc) {
- // Delete the definition and bump the linkage in the source module.
- if (isa<Function>(GV)) {
- auto &F = *cast<Function>(GV);
- F.deleteBody();
- F.setPersonalityFn(nullptr);
- } else if (isa<GlobalVariable>(GV)) {
- cast<GlobalVariable>(GV)->setInitializer(nullptr);
- } else
- llvm_unreachable("Unsupported global type");
-
- GV->setLinkage(GlobalValue::ExternalLinkage);
- }
+static ThreadSafeModule extractAndClone(ThreadSafeModule &TSM, StringRef Suffix,
+ GVPredicate ShouldCloneDefinition) {
- BitcodeWriter BCWriter(ClonedModuleBuffer);
+ auto DeleteClonedDefsAndPromoteDeclLinkages = [](GlobalValue &GV) {
+ // Delete the definition and bump the linkage in the source module.
+ if (isa<Function>(GV)) {
+ auto &F = cast<Function>(GV);
+ F.deleteBody();
+ F.setPersonalityFn(nullptr);
+ } else if (isa<GlobalVariable>(GV)) {
+ cast<GlobalVariable>(GV).setInitializer(nullptr);
+ } else
+ llvm_unreachable("Unsupported global type");
- BCWriter.writeModule(*Tmp);
- BCWriter.writeSymtab();
- BCWriter.writeStrtab();
- }
+ GV.setLinkage(GlobalValue::ExternalLinkage);
+ };
- MemoryBufferRef ClonedModuleBufferRef(
- StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
- "cloned module buffer");
+ auto NewTSMod = cloneToNewContext(TSM, ShouldCloneDefinition,
+ DeleteClonedDefsAndPromoteDeclLinkages);
+ auto &M = *NewTSMod.getModule();
+ M.setModuleIdentifier((M.getModuleIdentifier() + Suffix).str());
- auto ClonedModule =
- cantFail(parseBitcodeFile(ClonedModuleBufferRef, NewContext));
- ClonedModule->setModuleIdentifier((M.getName() + Suffix).str());
- return ClonedModule;
+ return NewTSMod;
}
-static std::unique_ptr<Module> extractGlobals(Module &M,
- LLVMContext &NewContext) {
- return extractAndClone(M, NewContext, ".globals", [](const GlobalValue *GV) {
+static ThreadSafeModule extractGlobals(ThreadSafeModule &TSM) {
+ return extractAndClone(TSM, ".globals", [](const GlobalValue &GV) {
return isa<GlobalVariable>(GV);
});
}
public:
ExtractingIRMaterializationUnit(ExecutionSession &ES,
CompileOnDemandLayer2 &Parent,
- std::unique_ptr<Module> M)
- : IRMaterializationUnit(ES, std::move(M)), Parent(Parent) {}
+ ThreadSafeModule TSM)
+ : IRMaterializationUnit(ES, std::move(TSM)), Parent(Parent) {}
- ExtractingIRMaterializationUnit(std::unique_ptr<Module> M,
+ ExtractingIRMaterializationUnit(ThreadSafeModule TSM,
SymbolFlagsMap SymbolFlags,
SymbolNameToDefinitionMap SymbolToDefinition,
CompileOnDemandLayer2 &Parent)
- : IRMaterializationUnit(std::move(M), std::move(SymbolFlags),
+ : IRMaterializationUnit(std::move(TSM), std::move(SymbolFlags),
std::move(SymbolToDefinition)),
Parent(Parent) {}
auto RequestedSymbols = R.getRequestedSymbols();
// Extract the requested functions into a new module.
- std::unique_ptr<Module> ExtractedFunctionsModule;
+ ThreadSafeModule ExtractedFunctionsModule;
if (!RequestedSymbols.empty()) {
std::string Suffix;
std::set<const GlobalValue *> FunctionsToClone;
std::lock_guard<std::mutex> Lock(SourceModuleMutex);
ExtractedFunctionsModule =
- extractAndClone(*M, Parent.GetAvailableContext(), Suffix,
- [&](const GlobalValue *GV) -> bool {
- return FunctionsToClone.count(GV);
- });
+ extractAndClone(TSM, Suffix, [&](const GlobalValue &GV) -> bool {
+ return FunctionsToClone.count(&GV);
+ });
}
// Build a new ExtractingIRMaterializationUnit to delegate the unrequested
"SymbolFlags and SymbolToDefinition should have the same number "
"of entries");
R.replace(llvm::make_unique<ExtractingIRMaterializationUnit>(
- std::move(M), std::move(DelegatedSymbolFlags),
+ std::move(TSM), std::move(DelegatedSymbolFlags),
std::move(DelegatedSymbolToDefinition), Parent));
}
CompileOnDemandLayer2::CompileOnDemandLayer2(
ExecutionSession &ES, IRLayer &BaseLayer, JITCompileCallbackManager &CCMgr,
- IndirectStubsManagerBuilder BuildIndirectStubsManager,
- GetAvailableContextFunction GetAvailableContext)
+ IndirectStubsManagerBuilder BuildIndirectStubsManager)
: IRLayer(ES), BaseLayer(BaseLayer), CCMgr(CCMgr),
- BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)),
- GetAvailableContext(std::move(GetAvailableContext)) {}
+ BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {}
Error CompileOnDemandLayer2::add(JITDylib &V, VModuleKey K,
- std::unique_ptr<Module> M) {
- return IRLayer::add(V, K, std::move(M));
+ ThreadSafeModule TSM) {
+ return IRLayer::add(V, K, std::move(TSM));
}
void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K,
- std::unique_ptr<Module> M) {
+ ThreadSafeModule TSM) {
auto &ES = getExecutionSession();
- assert(M && "M should not be null");
+ assert(TSM && "M should not be null");
+ auto &M = *TSM.getModule();
- for (auto &GV : M->global_values())
+ for (auto &GV : M.global_values())
if (GV.hasWeakLinkage())
GV.setLinkage(GlobalValue::ExternalLinkage);
- MangleAndInterner Mangle(ES, M->getDataLayout());
+ MangleAndInterner Mangle(ES, M.getDataLayout());
- extractAliases(R, *M, Mangle);
+ extractAliases(R, *TSM.getModule(), Mangle);
- auto GlobalsModule = extractGlobals(*M, GetAvailableContext());
+ auto GlobalsModule = extractGlobals(TSM);
// Delete the bodies of any available externally functions, rename the
// rest, and build the compile callbacks.
StubCallbacksAndLinkages;
auto &TargetJD = R.getTargetJITDylib();
- for (auto &F : M->functions()) {
+ for (auto &F : M.functions()) {
if (F.isDeclaration())
continue;
assert(F.hasName() && "Function should have a name");
std::string StubUnmangledName = F.getName();
F.setName(F.getName() + "$body");
- auto StubDecl = cloneFunctionDecl(*M, F);
+ auto StubDecl = cloneFunctionDecl(*TSM.getModule(), F);
StubDecl->setName(StubUnmangledName);
StubDecl->setPersonalityFn(nullptr);
StubDecl->setLinkage(GlobalValue::ExternalLinkage);
// Build the function-body-extracting materialization unit.
if (auto Err = R.getTargetJITDylib().define(
llvm::make_unique<ExtractingIRMaterializationUnit>(ES, *this,
- std::move(M)))) {
+ std::move(TSM)))) {
ES.reportError(std::move(Err));
R.failMaterialization();
return;
}
void CompileOnDemandLayer2::emitExtractedFunctionsModule(
- MaterializationResponsibility R, std::unique_ptr<Module> M) {
+ MaterializationResponsibility R, ThreadSafeModule TSM) {
auto K = getExecutionSession().allocateVModule();
- BaseLayer.emit(std::move(R), std::move(K), std::move(M));
+ BaseLayer.emit(std::move(R), std::move(K), std::move(TSM));
}
} // end namespace orc
}
void IRCompileLayer2::emit(MaterializationResponsibility R, VModuleKey K,
- std::unique_ptr<Module> M) {
- assert(M && "Module must not be null");
+ ThreadSafeModule TSM) {
+ assert(TSM.getModule() && "Module must not be null");
- if (auto Obj = Compile(*M)) {
+ if (auto Obj = Compile(*TSM.getModule())) {
{
std::lock_guard<std::mutex> Lock(IRLayerMutex);
if (NotifyCompiled)
- NotifyCompiled(K, std::move(M));
+ NotifyCompiled(K, std::move(TSM));
else
- M = nullptr;
+ TSM = ThreadSafeModule();
}
BaseLayer.emit(std::move(R), std::move(K), std::move(*Obj));
} else {
: IRLayer(ES), BaseLayer(BaseLayer), Transform(std::move(Transform)) {}
void IRTransformLayer2::emit(MaterializationResponsibility R, VModuleKey K,
- std::unique_ptr<Module> M) {
- assert(M && "Module must not be null");
+ ThreadSafeModule TSM) {
+ assert(TSM.getModule() && "Module must not be null");
- if (auto TransformedMod = Transform(std::move(M)))
- BaseLayer.emit(std::move(R), std::move(K), std::move(*TransformedMod));
+ if (auto TransformedTSM = Transform(std::move(TSM)))
+ BaseLayer.emit(std::move(R), std::move(K), std::move(*TransformedTSM));
else {
R.failMaterialization();
- getExecutionSession().reportError(TransformedMod.takeError());
+ getExecutionSession().reportError(TransformedTSM.takeError());
}
}
return Main.define(absoluteSymbols(std::move(Symbols)));
}
-Error LLJIT::addIRModule(JITDylib &JD, std::unique_ptr<Module> M) {
- assert(M && "Can not add null module");
+Error LLJIT::addIRModule(JITDylib &JD, ThreadSafeModule TSM) {
+ assert(TSM && "Can not add null module");
- if (auto Err = applyDataLayout(*M))
+ if (auto Err = applyDataLayout(*TSM.getModule()))
return Err;
auto K = ES->allocateVModule();
- return CompileLayer.add(JD, K, std::move(M));
+ return CompileLayer.add(JD, K, std::move(TSM));
}
Error LLJIT::addObjectFile(JITDylib &JD, std::unique_ptr<MemoryBuffer> Obj) {
}
Expected<std::unique_ptr<LLLazyJIT>>
-LLLazyJIT::Create(std::unique_ptr<TargetMachine> TM, DataLayout DL,
- LLVMContext &Ctx) {
+LLLazyJIT::Create(std::unique_ptr<TargetMachine> TM, DataLayout DL) {
auto ES = llvm::make_unique<ExecutionSession>();
const Triple &TT = TM->getTargetTriple();
inconvertibleErrorCode());
return std::unique_ptr<LLLazyJIT>(
- new LLLazyJIT(std::move(ES), std::move(TM), std::move(DL), Ctx,
+ new LLLazyJIT(std::move(ES), std::move(TM), std::move(DL),
std::move(CCMgr), std::move(ISMBuilder)));
}
-Error LLLazyJIT::addLazyIRModule(JITDylib &JD, std::unique_ptr<Module> M) {
- assert(M && "Can not add null module");
+Error LLLazyJIT::addLazyIRModule(JITDylib &JD, ThreadSafeModule TSM) {
+ assert(TSM && "Can not add null module");
- if (auto Err = applyDataLayout(*M))
+ if (auto Err = applyDataLayout(*TSM.getModule()))
return Err;
- makeAllSymbolsExternallyAccessible(*M);
+ makeAllSymbolsExternallyAccessible(*TSM.getModule());
- recordCtorDtors(*M);
+ recordCtorDtors(*TSM.getModule());
auto K = ES->allocateVModule();
- return CODLayer.add(JD, K, std::move(M));
+ return CODLayer.add(JD, K, std::move(TSM));
}
LLLazyJIT::LLLazyJIT(
std::unique_ptr<ExecutionSession> ES, std::unique_ptr<TargetMachine> TM,
- DataLayout DL, LLVMContext &Ctx,
- std::unique_ptr<JITCompileCallbackManager> CCMgr,
+ DataLayout DL, std::unique_ptr<JITCompileCallbackManager> CCMgr,
std::function<std::unique_ptr<IndirectStubsManager>()> ISMBuilder)
: LLJIT(std::move(ES), std::move(TM), std::move(DL)),
CCMgr(std::move(CCMgr)), TransformLayer(*this->ES, CompileLayer),
- CODLayer(*this->ES, TransformLayer, *this->CCMgr, std::move(ISMBuilder),
- [&]() -> LLVMContext & { return Ctx; }) {}
+ CODLayer(*this->ES, TransformLayer, *this->CCMgr, std::move(ISMBuilder)) {
+}
} // End namespace orc.
} // End namespace llvm.
IRLayer::IRLayer(ExecutionSession &ES) : ES(ES) {}
IRLayer::~IRLayer() {}
-Error IRLayer::add(JITDylib &JD, VModuleKey K, std::unique_ptr<Module> M) {
+Error IRLayer::add(JITDylib &JD, VModuleKey K, ThreadSafeModule TSM) {
return JD.define(llvm::make_unique<BasicIRLayerMaterializationUnit>(
- *this, std::move(K), std::move(M)));
+ *this, std::move(K), std::move(TSM)));
}
IRMaterializationUnit::IRMaterializationUnit(ExecutionSession &ES,
- std::unique_ptr<Module> M)
- : MaterializationUnit(SymbolFlagsMap()), M(std::move(M)) {
+ ThreadSafeModule TSM)
+ : MaterializationUnit(SymbolFlagsMap()), TSM(std::move(TSM)) {
- MangleAndInterner Mangle(ES, this->M->getDataLayout());
- for (auto &G : this->M->global_values()) {
+ assert(this->TSM && "Module must not be null");
+
+ MangleAndInterner Mangle(ES, this->TSM.getModule()->getDataLayout());
+ for (auto &G : this->TSM.getModule()->global_values()) {
if (G.hasName() && !G.isDeclaration() && !G.hasLocalLinkage() &&
!G.hasAvailableExternallyLinkage() && !G.hasAppendingLinkage()) {
auto MangledName = Mangle(G.getName());
}
IRMaterializationUnit::IRMaterializationUnit(
- std::unique_ptr<Module> M, SymbolFlagsMap SymbolFlags,
+ ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags,
SymbolNameToDefinitionMap SymbolToDefinition)
- : MaterializationUnit(std::move(SymbolFlags)), M(std::move(M)),
+ : MaterializationUnit(std::move(SymbolFlags)), TSM(std::move(TSM)),
SymbolToDefinition(std::move(SymbolToDefinition)) {}
void IRMaterializationUnit::discard(const JITDylib &JD, SymbolStringPtr Name) {
}
BasicIRLayerMaterializationUnit::BasicIRLayerMaterializationUnit(
- IRLayer &L, VModuleKey K, std::unique_ptr<Module> M)
- : IRMaterializationUnit(L.getExecutionSession(), std::move(M)),
- L(L), K(std::move(K)) {}
+ IRLayer &L, VModuleKey K, ThreadSafeModule TSM)
+ : IRMaterializationUnit(L.getExecutionSession(), std::move(TSM)), L(L),
+ K(std::move(K)) {}
void BasicIRLayerMaterializationUnit::materialize(
MaterializationResponsibility R) {
- L.emit(std::move(R), std::move(K), std::move(M));
+
+ if (L.getCloneToNewContextOnEmit())
+ TSM = cloneToNewContext(TSM);
+
+ auto Lock = TSM.getContextLock();
+ L.emit(std::move(R), std::move(K), std::move(TSM));
}
ObjectLayer::ObjectLayer(ExecutionSession &ES) : ES(ES) {}
--- /dev/null
+//===-- ThreadSafeModule.cpp - Thread safe Module, Context, and Utilities h-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+namespace llvm {
+namespace orc {
+
+ThreadSafeModule cloneToNewContext(ThreadSafeModule &TSM,
+ GVPredicate ShouldCloneDef,
+ GVModifier UpdateClonedDefSource) {
+ assert(TSM && "Can not clone null module");
+
+ if (!ShouldCloneDef)
+ ShouldCloneDef = [](const GlobalValue&) { return true; };
+
+ auto Lock = TSM.getContextLock();
+
+ SmallVector<char, 1> ClonedModuleBuffer;
+
+ {
+ std::vector<GlobalValue *> ClonedDefsInSrc;
+ ValueToValueMapTy VMap;
+ auto Tmp = CloneModule(*TSM.getModule(), VMap,
+ [&](const GlobalValue *GV) {
+ if (ShouldCloneDef(*GV)) {
+ ClonedDefsInSrc.push_back(const_cast<GlobalValue *>(GV));
+ return true;
+ }
+ return false;
+ });
+
+ if (UpdateClonedDefSource)
+ for (auto *GV : ClonedDefsInSrc)
+ UpdateClonedDefSource(*GV);
+
+ BitcodeWriter BCWriter(ClonedModuleBuffer);
+
+ BCWriter.writeModule(*Tmp);
+ BCWriter.writeSymtab();
+ BCWriter.writeStrtab();
+ }
+
+ MemoryBufferRef ClonedModuleBufferRef(
+ StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
+ "cloned module buffer");
+ ThreadSafeContext NewTSCtx(llvm::make_unique<LLVMContext>());
+
+ auto ClonedModule =
+ cantFail(parseBitcodeFile(ClonedModuleBufferRef, *NewTSCtx.getContext()));
+ ClonedModule->setModuleIdentifier(TSM.getModule()->getName());
+ return ThreadSafeModule(std::move(ClonedModule), std::move(NewTSCtx));
+}
+
+} // end namespace orc
+} // end namespace llvm
static orc::IRTransformLayer2::TransformFunction createDebugDumper() {
switch (OrcDumpKind) {
case DumpKind::NoDump:
- return [](std::unique_ptr<Module> M) { return M; };
+ return [](orc::ThreadSafeModule TSM) { return TSM; };
case DumpKind::DumpFuncsToStdOut:
- return [](std::unique_ptr<Module> M) {
+ return [](orc::ThreadSafeModule TSM) {
printf("[ ");
- for (const auto &F : *M) {
+ for (const auto &F : *TSM.getModule()) {
if (F.isDeclaration())
continue;
}
printf("]\n");
- return M;
+ return TSM;
};
case DumpKind::DumpModsToStdOut:
- return [](std::unique_ptr<Module> M) {
+ return [](orc::ThreadSafeModule TSM) {
outs() << "----- Module Start -----\n"
- << *M << "----- Module End -----\n";
+ << *TSM.getModule() << "----- Module End -----\n";
- return M;
+ return TSM;
};
case DumpKind::DumpModsToDisk:
- return [](std::unique_ptr<Module> M) {
+ return [](orc::ThreadSafeModule TSM) {
std::error_code EC;
- raw_fd_ostream Out(M->getModuleIdentifier() + ".ll", EC, sys::fs::F_Text);
+ raw_fd_ostream Out(TSM.getModule()->getModuleIdentifier() + ".ll", EC,
+ sys::fs::F_Text);
if (EC) {
- errs() << "Couldn't open " << M->getModuleIdentifier()
+ errs() << "Couldn't open " << TSM.getModule()->getModuleIdentifier()
<< " for dumping.\nError:" << EC.message() << "\n";
exit(1);
}
- Out << *M;
- return M;
+ Out << *TSM.getModule();
+ return TSM;
};
}
llvm_unreachable("Unknown DumpKind");
}
// Parse the main module.
- LLVMContext Ctx;
+ orc::ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>());
SMDiagnostic Err;
- auto MainModule = parseIRFile(InputFile, Err, Ctx);
+ auto MainModule = orc::ThreadSafeModule(
+ parseIRFile(InputFile, Err, *TSCtx.getContext()), TSCtx);
if (!MainModule)
reportError(Err, ProgName);
- const auto &TT = MainModule->getTargetTriple();
+ const auto &TT = MainModule.getModule()->getTargetTriple();
orc::JITTargetMachineBuilder TMD =
TT.empty() ? ExitOnErr(orc::JITTargetMachineBuilder::detectHost())
: orc::JITTargetMachineBuilder(Triple(TT));
: None);
auto TM = ExitOnErr(TMD.createTargetMachine());
auto DL = TM->createDataLayout();
- auto J = ExitOnErr(orc::LLLazyJIT::Create(std::move(TM), DL, Ctx));
+ auto J = ExitOnErr(orc::LLLazyJIT::Create(std::move(TM), DL));
auto Dump = createDebugDumper();
- J->setLazyCompileTransform(
- [&](std::unique_ptr<Module> M) {
- if (verifyModule(*M, &dbgs())) {
- dbgs() << "Bad module: " << *M << "\n";
- exit(1);
- }
- return Dump(std::move(M));
- });
+ J->setLazyCompileTransform([&](orc::ThreadSafeModule TSM) {
+ if (verifyModule(*TSM.getModule(), &dbgs())) {
+ dbgs() << "Bad module: " << *TSM.getModule() << "\n";
+ exit(1);
+ }
+ return Dump(std::move(TSM));
+ });
J->getMainJITDylib().setFallbackDefinitionGenerator(
orc::DynamicLibraryFallbackGenerator(
std::move(LibLLI), DL, [](orc::SymbolStringPtr) { return true; }));
// Add any extra modules.
for (auto &ModulePath : ExtraModules) {
- auto M = parseIRFile(ModulePath, Err, Ctx);
+ auto M = parseIRFile(ModulePath, Err, *TSCtx.getContext());
if (!M)
reportError(Err, ProgName);
orc::makeAllSymbolsExternallyAccessible(*M);
- ExitOnErr(J->addLazyIRModule(std::move(M)));
+ ExitOnErr(J->addLazyIRModule(orc::ThreadSafeModule(std::move(M), TSCtx)));
}
// Add the objects.
};
// Create a module with two void() functions: foo and bar.
- LLVMContext Context;
- std::unique_ptr<Module> M;
+ ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>());
+ ThreadSafeModule M;
{
- ModuleBuilder MB(Context, TM->getTargetTriple().str(), "dummy");
+ ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy");
MB.getModule()->setDataLayout(TM->createDataLayout());
Function *FooImpl = MB.createFunctionDecl<void()>("foo");
- BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
+ BasicBlock *FooEntry =
+ BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl);
IRBuilder<> B1(FooEntry);
B1.CreateRetVoid();
Function *BarImpl = MB.createFunctionDecl<void()>("bar");
- BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
+ BasicBlock *BarEntry =
+ BasicBlock::Create(*TSCtx.getContext(), "entry", BarImpl);
IRBuilder<> B2(BarEntry);
B2.CreateRetVoid();
- M = MB.takeModule();
+ M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx));
}
// Create a simple stack and set the override flags option.
};
// Create a module with two void() functions: foo and bar.
- LLVMContext Context;
- std::unique_ptr<Module> M;
+ ThreadSafeContext TSCtx(llvm::make_unique<LLVMContext>());
+ ThreadSafeModule M;
{
- ModuleBuilder MB(Context, TM->getTargetTriple().str(), "dummy");
+ ModuleBuilder MB(*TSCtx.getContext(), TM->getTargetTriple().str(), "dummy");
MB.getModule()->setDataLayout(TM->createDataLayout());
Function *FooImpl = MB.createFunctionDecl<void()>("foo");
- BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
+ BasicBlock *FooEntry =
+ BasicBlock::Create(*TSCtx.getContext(), "entry", FooImpl);
IRBuilder<> B(FooEntry);
B.CreateRetVoid();
- M = MB.takeModule();
+ M = ThreadSafeModule(MB.takeModule(), std::move(TSCtx));
}
// Create a simple stack and set the override flags option.