Replace use of ExecutionEngine by OrcJIT.
This commit is contained in:
parent
d9a804df73
commit
16fe3f49dc
@ -239,7 +239,7 @@ namespace cling {
|
||||
///
|
||||
void WrapInput(std::string& input, std::string& fname);
|
||||
|
||||
///\brief Runs given function.
|
||||
///\brief Runs given wrapper function void(*)(Value*).
|
||||
///
|
||||
///\param [in] fname - The function name.
|
||||
///\param [in,out] res - The return result of the run function. Must be
|
||||
@ -546,14 +546,13 @@ namespace cling {
|
||||
|
||||
clang::CompilerInstance* getCI() const;
|
||||
clang::Sema& getSema() const;
|
||||
llvm::ExecutionEngine* getExecutionEngine() const;
|
||||
|
||||
//FIXME: This must be in InterpreterCallbacks.
|
||||
void installLazyFunctionCreator(void* (*fp)(const std::string&));
|
||||
|
||||
//FIXME: Terrible hack to let the IncrementalParser run static inits on
|
||||
// transaction completed.
|
||||
ExecutionResult runStaticInitializersOnce(const Transaction& T) const;
|
||||
ExecutionResult executeTransaction(Transaction& T) const;
|
||||
|
||||
///\brief Evaluates given expression within given declaration context.
|
||||
///
|
||||
@ -626,7 +625,7 @@ namespace cling {
|
||||
|
||||
///\brief Forwards to cling::IncrementalExecutor::addModule.
|
||||
///
|
||||
void addModule(std::unique_ptr<llvm::Module> module);
|
||||
void addModule(llvm::Module* module);
|
||||
|
||||
void GenerateAutoloadingMap(llvm::StringRef inFile, llvm::StringRef outFile,
|
||||
bool enableMacros = false, bool enableLogs = true);
|
||||
|
@ -61,6 +61,11 @@ namespace cling {
|
||||
kCCINumStates
|
||||
};
|
||||
|
||||
///\brief Sort of opaque handle for unloading a transaction from the JIT.
|
||||
struct ExeUnloadHandle {
|
||||
void* m_Opaque;
|
||||
};
|
||||
|
||||
///\brief Each declaration group came through different interface at
|
||||
/// different time. We are being conservative and we want to keep all the
|
||||
/// call sequence that originally occurred in clang.
|
||||
@ -141,7 +146,12 @@ namespace cling {
|
||||
|
||||
///\brief The llvm Module containing the information that we will revert
|
||||
///
|
||||
llvm::Module* m_Module;
|
||||
std::unique_ptr<llvm::Module> m_Module;
|
||||
|
||||
///\brief The ExecutionEngine handle allowing an removal of the
|
||||
/// Transaction's symbols.
|
||||
///
|
||||
ExeUnloadHandle m_ExeUnload;
|
||||
|
||||
///\brief The wrapper function produced by the intepreter if any.
|
||||
///
|
||||
@ -426,8 +436,11 @@ namespace cling {
|
||||
m_NestedTransactions->clear();
|
||||
}
|
||||
|
||||
llvm::Module* getModule() const { return m_Module; }
|
||||
void setModule(llvm::Module* M) { m_Module = M ; }
|
||||
llvm::Module* getModule() const { return m_Module.get(); }
|
||||
void setModule(std::unique_ptr<llvm::Module> M) { m_Module.swap(M); }
|
||||
|
||||
ExeUnloadHandle getExeUnloadHandle() { return m_ExeUnload; }
|
||||
void setExeUnloadHandle(ExeUnloadHandle H) { m_ExeUnload = H; }
|
||||
|
||||
clang::FunctionDecl* getWrapperFD() const { return m_WrapperFD; }
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace cling {
|
||||
T->erase(found);
|
||||
}
|
||||
// We know that it didn't end up in the EE by design.
|
||||
TransactionUnloader U(m_Sema, /*CodeGenerator*/0, /*ExecutionEngine*/0);
|
||||
TransactionUnloader U(m_Sema, /*CodeGenerator*/0);
|
||||
U.UnloadDecl(FD);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "IncrementalExecutor.h"
|
||||
#include "IncrementalJIT.h"
|
||||
|
||||
#include "cling/Interpreter/Value.h"
|
||||
#include "cling/Interpreter/Transaction.h"
|
||||
@ -20,99 +21,60 @@
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/ExecutionEngine/MCJIT.h"
|
||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class ClingMemoryManager: public SectionMemoryManager {
|
||||
cling::IncrementalExecutor& m_exe;
|
||||
|
||||
static void local_cxa_atexit(void (*func) (void*), void* arg, void* dso) {
|
||||
cling::IncrementalExecutor* exe = (cling::IncrementalExecutor*)dso;
|
||||
exe->AddAtExitFunc(func, arg);
|
||||
}
|
||||
|
||||
public:
|
||||
ClingMemoryManager(cling::IncrementalExecutor& Exe):
|
||||
m_exe(Exe) {}
|
||||
|
||||
///\brief Return the address of a symbol, use callbacks if needed.
|
||||
uint64_t getSymbolAddress (const std::string &Name) override;
|
||||
|
||||
/// This method returns the address of the specified function or variable
|
||||
/// that could not be resolved by getSymbolAddress() or by resolving
|
||||
/// possible weak symbols by the ExecutionEngine.
|
||||
/// It is used to resolve symbols during module linking.
|
||||
uint64_t getMissingSymbolAddress(const std::string &Name) override {
|
||||
return (uint64_t) m_exe.NotifyLazyFunctionCreators(Name);
|
||||
}
|
||||
|
||||
///\brief Simply wraps the base class's function setting AbortOnFailure
|
||||
/// to false and instead using the error handling mechanism to report it.
|
||||
void* getPointerToNamedFunction(const std::string &Name,
|
||||
bool /*AbortOnFailure*/ =true) override {
|
||||
return SectionMemoryManager::getPointerToNamedFunction(Name, false);
|
||||
}
|
||||
};
|
||||
|
||||
uint64_t ClingMemoryManager::getSymbolAddress(const std::string &Name) {
|
||||
if (Name == "__cxa_atexit") {
|
||||
// Rewrire __cxa_atexit to ~Interpreter(), thus also global destruction
|
||||
// coming from the JIT.
|
||||
return (uint64_t)&local_cxa_atexit;
|
||||
} else if (Name == "__dso_handle") {
|
||||
// Provide IncrementalExecutor as the third argument to __cxa_atexit.
|
||||
return (uint64_t)&m_exe;
|
||||
}
|
||||
uint64_t Addr = SectionMemoryManager::getSymbolAddress(Name);
|
||||
return Addr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace cling {
|
||||
|
||||
std::set<std::string> IncrementalExecutor::m_unresolvedSymbols;
|
||||
IncrementalExecutor::IncrementalExecutor(clang::DiagnosticsEngine& diags):
|
||||
m_CurrentAtExitModule(0)
|
||||
#if 0
|
||||
: m_Diags(diags)
|
||||
#endif
|
||||
{
|
||||
m_AtExitFuncs.reserve(256);
|
||||
|
||||
std::vector<IncrementalExecutor::LazyFunctionCreatorFunc_t>
|
||||
IncrementalExecutor::m_lazyFuncCreator;
|
||||
m_JIT.reset(new IncrementalJIT(*this, std::move(CreateHostTargetMachine())));
|
||||
}
|
||||
|
||||
// Keep in source: ~unique_ptr<ExecutionEngine> needs #include ExecutionEngine
|
||||
// Keep in source: ~unique_ptr<ClingJIT> needs ClingJIT
|
||||
IncrementalExecutor::~IncrementalExecutor() {}
|
||||
|
||||
void IncrementalExecutor::BuildEngine(std::unique_ptr<llvm::Module> m) {
|
||||
//
|
||||
// Create an execution engine to use.
|
||||
//
|
||||
assert(m && "Module cannot be null");
|
||||
// Note: Engine takes ownership of the module.
|
||||
llvm::EngineBuilder builder(std::move(m));
|
||||
std::unique_ptr<TargetMachine>
|
||||
IncrementalExecutor::CreateHostTargetMachine() const {
|
||||
// TODO: make this configurable.
|
||||
Triple TheTriple(sys::getProcessTriple());
|
||||
std::string Error;
|
||||
const Target *TheTarget
|
||||
= TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
|
||||
if (!TheTarget) {
|
||||
llvm::errs() << "cling::IncrementalExecutor: unable to find target:\n"
|
||||
<< Error;
|
||||
}
|
||||
|
||||
std::string errMsg;
|
||||
builder.setErrorStr(&errMsg);
|
||||
builder.setOptLevel(llvm::CodeGenOpt::Less);
|
||||
builder.setEngineKind(llvm::EngineKind::JIT);
|
||||
std::unique_ptr<llvm::RTDyldMemoryManager>
|
||||
MemMan(new ClingMemoryManager(*this));
|
||||
builder.setMCJITMemoryManager(std::move(MemMan));
|
||||
std::string MCPU;
|
||||
std::string FeaturesStr;
|
||||
|
||||
// EngineBuilder uses default c'ted TargetOptions, too:
|
||||
llvm::TargetOptions TargetOpts;
|
||||
TargetOpts.NoFramePointerElim = 1;
|
||||
TargetOpts.JITEmitDebugInfo = 1;
|
||||
TargetOptions Options = TargetOptions();
|
||||
Options.NoFramePointerElim = 1;
|
||||
Options.JITEmitDebugInfo = 1;
|
||||
Reloc::Model RelocModel = Reloc::Default;
|
||||
CodeModel::Model CMModel = CodeModel::JITDefault;
|
||||
CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
|
||||
|
||||
builder.setTargetOptions(TargetOpts);
|
||||
|
||||
m_engine.reset(builder.create());
|
||||
assert(m_engine && "Cannot create module!");
|
||||
|
||||
// install lazy function creators
|
||||
//m_engine->InstallLazyFunctionCreator(NotifyLazyFunctionCreators);
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(),
|
||||
MCPU, FeaturesStr,
|
||||
Options,
|
||||
RelocModel, CMModel,
|
||||
OptLevel));
|
||||
return std::move(TM);
|
||||
}
|
||||
|
||||
void IncrementalExecutor::shuttingDown() {
|
||||
@ -190,48 +152,11 @@ freeCallersOfUnresolvedSymbols(llvm::SmallVectorImpl<llvm::Function*>&
|
||||
}
|
||||
}
|
||||
|
||||
IncrementalExecutor::ExecutionResult
|
||||
IncrementalExecutor::executeFunction(llvm::StringRef funcname,
|
||||
Value* returnValue) {
|
||||
// Call a function without arguments, or with an SRet argument, see SRet below
|
||||
// We don't care whether something was unresolved before.
|
||||
m_unresolvedSymbols.clear();
|
||||
|
||||
// Set the value to cling::invalid.
|
||||
if (returnValue) {
|
||||
*returnValue = Value();
|
||||
}
|
||||
|
||||
llvm::Function* f = m_engine->FindFunctionNamed(funcname.str().c_str());
|
||||
if (!f) {
|
||||
llvm::errs() << "IncrementalExecutor::executeFunction: "
|
||||
"could not find function named " << funcname << '\n';
|
||||
return kExeFunctionNotCompiled;
|
||||
}
|
||||
assert (f->getFunctionType()->getNumParams() == 1
|
||||
&& (*f->getFunctionType()->param_begin())->isPtrOrPtrVectorTy() &&
|
||||
"Wrong signature");
|
||||
typedef void (*PromptWrapper_t)(void*);
|
||||
union {
|
||||
PromptWrapper_t wrapperFunction;
|
||||
void* address;
|
||||
} p2f;
|
||||
p2f.address = (void*)m_engine->getFunctionAddress(funcname);
|
||||
|
||||
// check if there is any unresolved symbol in the list
|
||||
if (diagnoseUnresolvedSymbols(funcname, "function"))
|
||||
return kExeUnresolvedSymbols;
|
||||
|
||||
// Run the function
|
||||
(*p2f.wrapperFunction)(returnValue);
|
||||
|
||||
return kExeSuccess;
|
||||
}
|
||||
|
||||
IncrementalExecutor::ExecutionResult
|
||||
IncrementalExecutor::runStaticInitializersOnce(llvm::Module* m) {
|
||||
IncrementalExecutor::runStaticInitializersOnce(const Transaction& T) {
|
||||
llvm::Module* m = T.getModule();
|
||||
assert(m && "Module must not be null");
|
||||
assert(m_engine && "Code generation did not create an engine!");
|
||||
|
||||
// Set m_CurrentAtExitModule to the Module, unset to 0 once done.
|
||||
struct AtExitModuleSetterRAII {
|
||||
@ -244,8 +169,6 @@ IncrementalExecutor::runStaticInitializersOnce(llvm::Module* m) {
|
||||
// We don't care whether something was unresolved before.
|
||||
m_unresolvedSymbols.clear();
|
||||
|
||||
m_engine->finalizeObject();
|
||||
|
||||
// check if there is any unresolved symbol in the list
|
||||
if (diagnoseUnresolvedSymbols("static initializers"))
|
||||
return kExeUnresolvedSymbols;
|
||||
@ -290,13 +213,8 @@ IncrementalExecutor::runStaticInitializersOnce(llvm::Module* m) {
|
||||
|
||||
// Execute the ctor/dtor function!
|
||||
if (llvm::Function *F = llvm::dyn_cast<llvm::Function>(FP)) {
|
||||
m_engine->getPointerToFunction(F);
|
||||
// check if there is any unresolved symbol in the list
|
||||
if (diagnoseUnresolvedSymbols("static initializers"))
|
||||
return kExeUnresolvedSymbols;
|
||||
executeInit(F->getName());
|
||||
|
||||
//executeFunction(F->getName());
|
||||
m_engine->runFunction(F, std::vector<llvm::GenericValue>());
|
||||
initFuncs.push_back(F);
|
||||
if (F->getName().startswith("_GLOBAL__sub_I__")) {
|
||||
BasicBlock& BB = F->getEntryBlock();
|
||||
@ -369,14 +287,6 @@ IncrementalExecutor::addSymbol(const char* symbolName, void* symbolAddress) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void IncrementalExecutor::addModule(std::unique_ptr<Module> module) {
|
||||
if (!m_engine)
|
||||
BuildEngine(std::move(module));
|
||||
else
|
||||
m_engine->addModule(std::move(module));
|
||||
}
|
||||
|
||||
|
||||
void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName,
|
||||
bool* fromJIT /*=0*/) {
|
||||
// Return a symbol's address, and whether it was jitted.
|
||||
@ -388,7 +298,7 @@ void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName,
|
||||
*fromJIT = !address;
|
||||
|
||||
if (!address)
|
||||
return (void*)m_engine->getGlobalValueAddress(symbolName);
|
||||
return (void*)m_JIT->getSymbolAddress(symbolName);
|
||||
|
||||
return address;
|
||||
}
|
||||
@ -400,14 +310,11 @@ IncrementalExecutor::getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) {
|
||||
// We don't care whether something was unresolved before.
|
||||
m_unresolvedSymbols.clear();
|
||||
|
||||
if (void* addr = m_engine->getPointerToGlobalIfAvailable(&GV))
|
||||
return addr;
|
||||
void* addr = (void*)m_JIT->getSymbolAddress(GV.getName());
|
||||
|
||||
// Function not yet codegened by the JIT, force this to happen now.
|
||||
void* Ptr = m_engine->getPointerToGlobal(&GV);
|
||||
if (diagnoseUnresolvedSymbols(GV.getName(), "symbol"))
|
||||
return 0;
|
||||
return Ptr;
|
||||
return addr;
|
||||
}
|
||||
|
||||
bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
|
||||
@ -435,12 +342,12 @@ bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
|
||||
if (!title.empty())
|
||||
llvm::errs() << "'";
|
||||
llvm::errs() << "!\n";
|
||||
llvm::Function *ff = m_engine->FindFunctionNamed(i->c_str());
|
||||
//llvm::Function *ff = m_engine->FindFunctionNamed(i->c_str());
|
||||
// i could also reference a global variable, in which case ff == 0.
|
||||
if (ff)
|
||||
funcsToFree.push_back(ff);
|
||||
//if (ff)
|
||||
// funcsToFree.push_back(ff);
|
||||
}
|
||||
freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
|
||||
//freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
|
||||
m_unresolvedSymbols.clear();
|
||||
return true;
|
||||
}
|
||||
|
@ -12,7 +12,12 @@
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
#include "IncrementalJIT.h"
|
||||
|
||||
#include "cling/Interpreter/Transaction.h"
|
||||
#include "cling/Interpreter/Value.h"
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
@ -24,32 +29,23 @@ namespace clang {
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
class ExecutionEngine;
|
||||
class GlobalValue;
|
||||
class Module;
|
||||
class TargetMachine;
|
||||
}
|
||||
|
||||
namespace cling {
|
||||
class Transaction;
|
||||
class Value;
|
||||
class IncrementalJIT;
|
||||
|
||||
class IncrementalExecutor {
|
||||
public:
|
||||
typedef void* (*LazyFunctionCreatorFunc_t)(const std::string&);
|
||||
|
||||
private:
|
||||
///\brief Set of the symbols that the ExecutionEngine couldn't resolve.
|
||||
///\brief Our JIT interface.
|
||||
///
|
||||
static std::set<std::string> m_unresolvedSymbols;
|
||||
|
||||
///\brief Lazy function creator, which is a final callback which the
|
||||
/// ExecutionEngine fires if there is unresolved symbol.
|
||||
///
|
||||
static std::vector<LazyFunctionCreatorFunc_t> m_lazyFuncCreator;
|
||||
|
||||
///\brief The llvm ExecutionEngine.
|
||||
///
|
||||
std::unique_ptr<llvm::ExecutionEngine> m_engine;
|
||||
std::unique_ptr<IncrementalJIT> m_JIT;
|
||||
|
||||
///\brief Helper that manages when the destructor of an object to be called.
|
||||
///
|
||||
@ -103,6 +99,18 @@ namespace cling {
|
||||
/// takes place.
|
||||
llvm::Module* m_CurrentAtExitModule;
|
||||
|
||||
///\brief Modules to emit upon the next call to the JIT.
|
||||
///
|
||||
std::vector<llvm::Module*> m_ModulesToJIT;
|
||||
|
||||
///\brief Lazy function creator, which is a final callback which the
|
||||
/// JIT fires if there is unresolved symbol.
|
||||
///
|
||||
std::vector<LazyFunctionCreatorFunc_t> m_lazyFuncCreator;
|
||||
|
||||
///\brief Set of the symbols that the JIT couldn't resolve.
|
||||
///
|
||||
std::set<std::string> m_unresolvedSymbols;
|
||||
|
||||
#if 0 // See FIXME in IncrementalExecutor.cpp
|
||||
///\brief The diagnostics engine, printing out issues coming from the
|
||||
@ -110,6 +118,8 @@ namespace cling {
|
||||
clang::DiagnosticsEngine& m_Diags;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<llvm::TargetMachine> CreateHostTargetMachine() const;
|
||||
|
||||
public:
|
||||
enum ExecutionResult {
|
||||
kExeSuccess,
|
||||
@ -118,20 +128,28 @@ namespace cling {
|
||||
kNumExeResults
|
||||
};
|
||||
|
||||
IncrementalExecutor(clang::DiagnosticsEngine& diags):
|
||||
m_CurrentAtExitModule(0)
|
||||
#if 0
|
||||
: m_Diags(diags)
|
||||
#endif
|
||||
{
|
||||
m_AtExitFuncs.reserve(256);
|
||||
}
|
||||
IncrementalExecutor(clang::DiagnosticsEngine& diags);
|
||||
|
||||
~IncrementalExecutor();
|
||||
|
||||
void installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp);
|
||||
|
||||
ExecutionResult runStaticInitializersOnce(llvm::Module* m);
|
||||
///\brief Send all collected modules to the JIT, making their symbols
|
||||
/// available to jitting (but not necessarily jitting them all).
|
||||
Transaction::ExeUnloadHandle emitToJIT() {
|
||||
size_t handle = m_JIT->addModules(std::move(m_ModulesToJIT));
|
||||
m_ModulesToJIT.clear();
|
||||
//m_JIT->finalizeMemory();
|
||||
return Transaction::ExeUnloadHandle{(void*)handle};
|
||||
}
|
||||
|
||||
///\brief Unload a set of JIT symbols.
|
||||
void unloadFromJIT(Transaction::ExeUnloadHandle H) {
|
||||
m_JIT->removeModules((size_t)H.m_Opaque);
|
||||
}
|
||||
|
||||
///\brief Run the static initializers of all modules collected to far.
|
||||
ExecutionResult runStaticInitializersOnce(const Transaction& T);
|
||||
|
||||
///\brief Runs all destructors bound to the given transaction and removes
|
||||
/// them from the list.
|
||||
@ -139,8 +157,21 @@ namespace cling {
|
||||
///
|
||||
void runAndRemoveStaticDestructors(Transaction* T);
|
||||
|
||||
ExecutionResult executeFunction(llvm::StringRef function,
|
||||
Value* returnValue = 0);
|
||||
///\brief Runs a wrapper function.
|
||||
ExecutionResult executeWrapper(llvm::StringRef function,
|
||||
Value* returnValue = 0) {
|
||||
// Set the value to cling::invalid.
|
||||
if (returnValue) {
|
||||
*returnValue = Value();
|
||||
}
|
||||
typedef void (*InitFun_t)(void*);
|
||||
InitFun_t fun;
|
||||
ExecutionResult res = executeInitOrWrapper(function, fun);
|
||||
if (res != kExeSuccess)
|
||||
return res;
|
||||
(*fun)(returnValue);
|
||||
return kExeSuccess;
|
||||
}
|
||||
|
||||
///\brief Adds a symbol (function) to the execution engine.
|
||||
///
|
||||
@ -154,11 +185,10 @@ namespace cling {
|
||||
///
|
||||
bool addSymbol(const char* symbolName, void* symbolAddress);
|
||||
|
||||
///\brief Add a llvm::Module to the ExecutionEngine, see
|
||||
/// ExecutionEngine::addModule()
|
||||
///\brief Add a llvm::Module to the JIT.
|
||||
///
|
||||
/// @param[in] module - The module to pass to the execution engine.
|
||||
void addModule(std::unique_ptr<llvm::Module> module);
|
||||
void addModule(llvm::Module* module) { m_ModulesToJIT.push_back(module); }
|
||||
|
||||
///\brief Tells the execution context that we are shutting down the system.
|
||||
///
|
||||
@ -179,19 +209,13 @@ namespace cling {
|
||||
///
|
||||
void* getAddressOfGlobal(llvm::StringRef mangledName, bool* fromJIT = 0);
|
||||
|
||||
///\brief Return the address of a global from the ExecutionEngine (as
|
||||
///\brief Return the address of a global from the JIT (as
|
||||
/// opposed to dynamic libraries). Forces the emission of the symbol if
|
||||
/// it has not happened yet.
|
||||
///
|
||||
///param[in] GV - global value for which the address will be returned.
|
||||
void* getPointerToGlobalFromJIT(const llvm::GlobalValue& GV);
|
||||
|
||||
llvm::ExecutionEngine* getExecutionEngine() const {
|
||||
if (!m_engine)
|
||||
return 0;
|
||||
return m_engine.get();
|
||||
}
|
||||
|
||||
///\brief Keep track of the entities whose dtor we need to call.
|
||||
///
|
||||
void AddAtExitFunc(void (*func) (void*), void* arg);
|
||||
@ -201,17 +225,42 @@ namespace cling {
|
||||
void* NotifyLazyFunctionCreators(const std::string&);
|
||||
|
||||
private:
|
||||
///\brief Build the llvm::ExecutionEngine given a readymade llvm::Module
|
||||
/// that can be passed to it.
|
||||
void BuildEngine(std::unique_ptr<llvm::Module> m);
|
||||
|
||||
///\brief Report and empty m_unresolvedSymbols.
|
||||
///\return true if m_unresolvedSymbols was non-empty.
|
||||
bool diagnoseUnresolvedSymbols(llvm::StringRef trigger,
|
||||
llvm::StringRef title = llvm::StringRef());
|
||||
|
||||
static void* HandleMissingFunction(const std::string&);
|
||||
///\brief Remember that the symbol could not be resolved by the JIT.
|
||||
void* HandleMissingFunction(const std::string& symbol);
|
||||
|
||||
///\brief Runs an initializer function.
|
||||
ExecutionResult executeInit(llvm::StringRef function) {
|
||||
typedef void (*InitFun_t)();
|
||||
InitFun_t fun;
|
||||
ExecutionResult res = executeInitOrWrapper(function, fun);
|
||||
if (res != kExeSuccess)
|
||||
return res;
|
||||
(*fun)();
|
||||
return kExeSuccess;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ExecutionResult executeInitOrWrapper(llvm::StringRef funcname, T& fun) {
|
||||
union {
|
||||
T fun;
|
||||
void* address;
|
||||
} p2f;
|
||||
p2f.address = (void*)m_JIT->getSymbolAddress(funcname);
|
||||
|
||||
// check if there is any unresolved symbol in the list
|
||||
if (diagnoseUnresolvedSymbols(funcname, "function") || !p2f.address) {
|
||||
fun = 0;
|
||||
return IncrementalExecutor::kExeUnresolvedSymbols;
|
||||
}
|
||||
|
||||
fun = p2f.fun;
|
||||
return IncrementalExecutor::kExeSuccess;
|
||||
}
|
||||
};
|
||||
} // end cling
|
||||
#endif // CLING_INCREMENTAL_EXECUTOR_H
|
||||
|
227
lib/Interpreter/IncrementalJIT.cpp
Normal file
227
lib/Interpreter/IncrementalJIT.cpp
Normal file
@ -0,0 +1,227 @@
|
||||
//--------------------------------------------------------------------*- C++ -*-
|
||||
// CLING - the C++ LLVM-based InterpreterG :)
|
||||
// author: Axel Naumann <axel@cern.ch>
|
||||
//
|
||||
// This file is dual-licensed: you can choose to license it under the University
|
||||
// of Illinois Open Source License or the GNU Lesser General Public License. See
|
||||
// LICENSE.TXT for details.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "IncrementalJIT.h"
|
||||
|
||||
#include "IncrementalExecutor.h"
|
||||
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
// Forward cxa_atexit for global d'tors.
|
||||
static void local_cxa_atexit(void (*func) (void*), void* arg, void* dso) {
|
||||
cling::IncrementalExecutor* exe = (cling::IncrementalExecutor*)dso;
|
||||
exe->AddAtExitFunc(func, arg);
|
||||
}
|
||||
|
||||
///\brief Memory manager providing the lop-level link to the
|
||||
/// IncrementalExecutor, handles missing or special / replaced symbols.
|
||||
class ClingMemoryManager: public SectionMemoryManager {
|
||||
cling::IncrementalExecutor& m_exe;
|
||||
|
||||
public:
|
||||
ClingMemoryManager(cling::IncrementalExecutor& Exe):
|
||||
m_exe(Exe) {}
|
||||
|
||||
/// This method returns the address of the specified function or variable
|
||||
/// that could not be resolved by getSymbolAddress() or by resolving
|
||||
/// possible weak symbols by the ExecutionEngine.
|
||||
/// It is used to resolve symbols during module linking.
|
||||
uint64_t getMissingSymbolAddress(const std::string &Name) override {
|
||||
return (uint64_t) m_exe.NotifyLazyFunctionCreators(Name);
|
||||
}
|
||||
|
||||
///\brief Simply wraps the base class's function setting AbortOnFailure
|
||||
/// to false and instead using the error handling mechanism to report it.
|
||||
void* getPointerToNamedFunction(const std::string &Name,
|
||||
bool /*AbortOnFailure*/ =true) override {
|
||||
return SectionMemoryManager::getPointerToNamedFunction(Name, false);
|
||||
}
|
||||
};
|
||||
} // unnamed namespace
|
||||
|
||||
namespace cling {
|
||||
|
||||
///\brief Memory manager for the OrcJIT layers to resolve symbols from the
|
||||
/// common IncrementalJIT. I.e. the master of the Orcs.
|
||||
/// Each ObjectLayer instance has one Azog object.
|
||||
class Azog: public RTDyldMemoryManager {
|
||||
cling::IncrementalJIT& m_jit;
|
||||
|
||||
public:
|
||||
Azog(cling::IncrementalJIT& Jit): m_jit(Jit) {}
|
||||
|
||||
RTDyldMemoryManager* getExeMM() const { return m_jit.m_ExeMM.get(); }
|
||||
|
||||
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID,
|
||||
StringRef SectionName) override {
|
||||
uint8_t *Addr =
|
||||
getExeMM()->allocateCodeSection(Size, Alignment, SectionID, SectionName);
|
||||
m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
|
||||
return Addr;
|
||||
}
|
||||
|
||||
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID, StringRef SectionName,
|
||||
bool IsReadOnly) override {
|
||||
uint8_t *Addr = getExeMM()->allocateDataSection(Size, Alignment, SectionID,
|
||||
SectionName, IsReadOnly);
|
||||
m_jit.m_SectionsAllocatedSinceLastLoad.insert(Addr);
|
||||
return Addr;
|
||||
}
|
||||
|
||||
void reserveAllocationSpace(uintptr_t CodeSize, uintptr_t DataSizeRO,
|
||||
uintptr_t DataSizeRW) override {
|
||||
return getExeMM()->reserveAllocationSpace(CodeSize, DataSizeRO, DataSizeRW);
|
||||
}
|
||||
|
||||
bool needsToReserveAllocationSpace() override {
|
||||
return getExeMM()->needsToReserveAllocationSpace();
|
||||
}
|
||||
|
||||
void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
|
||||
size_t Size) override {
|
||||
return getExeMM()->registerEHFrames(Addr, LoadAddr, Size);
|
||||
}
|
||||
|
||||
void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
|
||||
size_t Size) override {
|
||||
return getExeMM()->deregisterEHFrames(Addr, LoadAddr, Size);
|
||||
}
|
||||
|
||||
uint64_t getSymbolAddress(const std::string &Name) override {
|
||||
return m_jit.getSymbolAddressWithoutMangling(Name);
|
||||
}
|
||||
|
||||
void *getPointerToNamedFunction(const std::string &Name,
|
||||
bool AbortOnFailure = true) override {
|
||||
return getExeMM()->getPointerToNamedFunction(Name, AbortOnFailure);
|
||||
}
|
||||
|
||||
void notifyObjectLoaded(ExecutionEngine *EE,
|
||||
const object::ObjectFile &O) override {
|
||||
return getExeMM()->notifyObjectLoaded(EE, O);
|
||||
}
|
||||
|
||||
bool finalizeMemory(std::string *ErrMsg = nullptr) override {
|
||||
// Each set of objects loaded will be finalized exactly once, but since
|
||||
// symbol lookup during relocation may recursively trigger the
|
||||
// loading/relocation of other modules, and since we're forwarding all
|
||||
// finalizeMemory calls to a single underlying memory manager, we need to
|
||||
// defer forwarding the call on until all necessary objects have been
|
||||
// loaded. Otherwise, during the relocation of a leaf object, we will end
|
||||
// up finalizing memory, causing a crash further up the stack when we
|
||||
// attempt to apply relocations to finalized memory.
|
||||
// To avoid finalizing too early, look at how many objects have been
|
||||
// loaded but not yet finalized. This is a bit of a hack that relies on
|
||||
// the fact that we're lazily emitting object files: The only way you can
|
||||
// get more than one set of objects loaded but not yet finalized is if
|
||||
// they were loaded during relocation of another set.
|
||||
if (m_jit.m_UnfinalizedSections.size() == 1)
|
||||
return getExeMM()->finalizeMemory(ErrMsg);
|
||||
return false;
|
||||
};
|
||||
|
||||
/// This method returns the address of the specified function or variable
|
||||
/// that could not be resolved by getSymbolAddress() or by resolving
|
||||
/// possible weak symbols by the ExecutionEngine.
|
||||
/// It is used to resolve symbols during module linking.
|
||||
uint64_t getMissingSymbolAddress(const std::string &Name) override {
|
||||
return (uint64_t) m_jit.getParent().NotifyLazyFunctionCreators(Name);
|
||||
}
|
||||
|
||||
|
||||
}; // class Azog
|
||||
|
||||
IncrementalJIT::IncrementalJIT(IncrementalExecutor& exe,
|
||||
std::unique_ptr<TargetMachine> TM):
|
||||
m_Parent(exe),
|
||||
m_TM(std::move(TM)),
|
||||
m_ExeMM(std::move(llvm::make_unique<ClingMemoryManager>(m_Parent))),
|
||||
m_Mang(m_TM->getDataLayout()),
|
||||
m_NotifyObjectLoaded(*this), m_NotifyFinalized(*this),
|
||||
m_ObjectLayer(ObjectLayerT::CreateRTDyldMMFtor(), m_NotifyObjectLoaded,
|
||||
m_NotifyFinalized),
|
||||
m_CompileLayer(m_ObjectLayer, SimpleCompiler(*m_TM)),
|
||||
m_LazyEmitLayer(m_CompileLayer) {
|
||||
|
||||
// Enable JIT symbol resolution from the binary.
|
||||
llvm::sys::DynamicLibrary::LoadLibraryPermanently(0, 0);
|
||||
|
||||
// #if MCJIT
|
||||
// llvm::EngineBuilder builder(std::move(m));
|
||||
|
||||
// std::string errMsg;
|
||||
// builder.setErrorStr(&errMsg);
|
||||
// builder.setOptLevel(llvm::CodeGenOpt::Less);
|
||||
// builder.setEngineKind(llvm::EngineKind::JIT);
|
||||
// std::unique_ptr<llvm::RTDyldMemoryManager>
|
||||
// MemMan(new ClingMemoryManager(*this));
|
||||
// builder.setMCJITMemoryManager(std::move(MemMan));
|
||||
|
||||
// // EngineBuilder uses default c'ted TargetOptions, too:
|
||||
// llvm::TargetOptions TargetOpts;
|
||||
// TargetOpts.NoFramePointerElim = 1;
|
||||
// TargetOpts.JITEmitDebugInfo = 1;
|
||||
|
||||
// builder.setTargetOptions(TargetOpts);
|
||||
|
||||
// m_engine.reset(builder.create());
|
||||
// assert(m_engine && "Cannot create module!");
|
||||
// #endif
|
||||
}
|
||||
|
||||
|
||||
uint64_t IncrementalJIT::getSymbolAddressWithoutMangling(llvm::StringRef Name) {
|
||||
if (Name == "__cxa_atexit") {
|
||||
// Rewire __cxa_atexit to ~Interpreter(), thus also global destruction
|
||||
// coming from the JIT.
|
||||
return (uint64_t)&local_cxa_atexit;
|
||||
} else if (Name == "__dso_handle") {
|
||||
// Provide IncrementalExecutor as the third argument to __cxa_atexit.
|
||||
return (uint64_t)&m_Parent;
|
||||
}
|
||||
if (uint64_t Addr = m_ExeMM->getSymbolAddress(Name))
|
||||
return Addr;
|
||||
if (uint64_t Addr = m_LazyEmitLayer.getSymbolAddress(Name, false))
|
||||
return Addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t IncrementalJIT::addModules(std::vector<llvm::Module*>&& modules) {
|
||||
// If this module doesn't have a DataLayout attached then attach the
|
||||
// default.
|
||||
for (auto&& mod: modules) {
|
||||
if (!mod->getDataLayout())
|
||||
mod->setDataLayout(m_TM->getDataLayout());
|
||||
}
|
||||
|
||||
ModuleSetHandleT MSHandle
|
||||
= m_LazyEmitLayer.addModuleSet(std::move(modules),
|
||||
llvm::make_unique<Azog>(*this));
|
||||
m_UnloadPoints.push_back(MSHandle);
|
||||
return m_UnloadPoints.size() - 1;
|
||||
}
|
||||
|
||||
// void* IncrementalJIT::finalizeMemory() {
|
||||
// for (auto &P : UnfinalizedSections)
|
||||
// if (P.second.count(LocalAddress))
|
||||
// ObjectLayer.mapSectionAddress(P.first, LocalAddress, TargetAddress);
|
||||
// }
|
||||
|
||||
|
||||
void IncrementalJIT::removeModules(size_t handle) {
|
||||
m_LazyEmitLayer.removeModuleSet(m_UnloadPoints[handle]);
|
||||
}
|
||||
|
||||
}// end namespace cling
|
150
lib/Interpreter/IncrementalJIT.h
Normal file
150
lib/Interpreter/IncrementalJIT.h
Normal file
@ -0,0 +1,150 @@
|
||||
//--------------------------------------------------------------------*- C++ -*-
|
||||
// CLING - the C++ LLVM-based InterpreterG :)
|
||||
// author: Axel Naumann <axel@cern.ch>
|
||||
//
|
||||
// This file is dual-licensed: you can choose to license it under the University
|
||||
// of Illinois Open Source License or the GNU Lesser General Public License. See
|
||||
// LICENSE.TXT for details.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef CLING_INCREMENTAL_JIT_H
|
||||
#define CLING_INCREMENTAL_JIT_H
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/IR/Mangler.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
|
||||
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h"
|
||||
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
class RTDyldMemoryManager;
|
||||
}
|
||||
|
||||
namespace cling {
|
||||
class Azog;
|
||||
class IncrementalExecutor;
|
||||
|
||||
class IncrementalJIT {
|
||||
friend class Azog;
|
||||
|
||||
///\brief The IncrementalExecutor who owns us.
|
||||
IncrementalExecutor& m_Parent;
|
||||
|
||||
class NotifyObjectLoadedT {
|
||||
public:
|
||||
typedef std::vector<std::unique_ptr<llvm::object::ObjectFile>> ObjListT;
|
||||
typedef std::vector<std::unique_ptr<llvm::RuntimeDyld::LoadedObjectInfo>>
|
||||
LoadedObjInfoListT;
|
||||
|
||||
NotifyObjectLoadedT(IncrementalJIT &jit) : m_JIT(jit) {}
|
||||
|
||||
void operator()(llvm::ObjectLinkingLayerBase::ObjSetHandleT H,
|
||||
const ObjListT &Objects,
|
||||
const LoadedObjInfoListT &Infos) const {
|
||||
m_JIT.m_UnfinalizedSections[H]
|
||||
= std::move(m_JIT.m_SectionsAllocatedSinceLastLoad);
|
||||
m_JIT.m_SectionsAllocatedSinceLastLoad = SectionAddrSet();
|
||||
assert(Objects.size() == Infos.size() &&
|
||||
"Incorrect number of Infos for Objects.");
|
||||
// We are no ExecutionEngine.
|
||||
//for (unsigned I = 0; I < Objects.size(); ++I)
|
||||
// m_JIT.m_ExeMM->notifyObjectLoaded(&m_JIT, *Objects[I]);
|
||||
};
|
||||
|
||||
private:
|
||||
IncrementalJIT &m_JIT;
|
||||
};
|
||||
|
||||
class NotifyFinalizedT {
|
||||
public:
|
||||
NotifyFinalizedT(IncrementalJIT &jit) : m_JIT(jit) {}
|
||||
void operator()(llvm::ObjectLinkingLayerBase::ObjSetHandleT H) {
|
||||
m_JIT.m_UnfinalizedSections.erase(H);
|
||||
}
|
||||
|
||||
private:
|
||||
IncrementalJIT &m_JIT;
|
||||
};
|
||||
|
||||
|
||||
typedef llvm::ObjectLinkingLayer<NotifyObjectLoadedT> ObjectLayerT;
|
||||
typedef llvm::IRCompileLayer<ObjectLayerT> CompileLayerT;
|
||||
typedef llvm::LazyEmittingLayer<CompileLayerT> LazyEmitLayerT;
|
||||
typedef LazyEmitLayerT::ModuleSetHandleT ModuleSetHandleT;
|
||||
|
||||
std::unique_ptr<llvm::TargetMachine> m_TM;
|
||||
///\brief The RTDyldMemoryManager used to communicate with the
|
||||
/// IncrementalExecutor to handle missing or special symbols.
|
||||
std::unique_ptr<llvm::RTDyldMemoryManager> m_ExeMM;
|
||||
|
||||
///\brief Target symbol mangler.
|
||||
llvm::Mangler m_Mang;
|
||||
|
||||
NotifyObjectLoadedT m_NotifyObjectLoaded;
|
||||
NotifyFinalizedT m_NotifyFinalized;
|
||||
|
||||
ObjectLayerT m_ObjectLayer;
|
||||
CompileLayerT m_CompileLayer;
|
||||
LazyEmitLayerT m_LazyEmitLayer;
|
||||
|
||||
// We need to store ObjLayerT::ObjSetHandles for each of the object sets
|
||||
// that have been emitted but not yet finalized so that we can forward the
|
||||
// mapSectionAddress calls appropriately.
|
||||
typedef std::set<const void *> SectionAddrSet;
|
||||
struct ObjSetHandleCompare {
|
||||
bool operator()(ObjectLayerT::ObjSetHandleT H1,
|
||||
ObjectLayerT::ObjSetHandleT H2) const {
|
||||
return &*H1 < &*H2;
|
||||
}
|
||||
};
|
||||
SectionAddrSet m_SectionsAllocatedSinceLastLoad;
|
||||
std::map<ObjectLayerT::ObjSetHandleT, SectionAddrSet, ObjSetHandleCompare>
|
||||
m_UnfinalizedSections;
|
||||
|
||||
///\brief Vector of ModuleSetHandleT. UnloadHandles index into that
|
||||
/// vector.
|
||||
std::vector<ModuleSetHandleT> m_UnloadPoints;
|
||||
|
||||
|
||||
std::string Mangle(llvm::StringRef Name) {
|
||||
std::string MangledName;
|
||||
{
|
||||
llvm::raw_string_ostream MangledNameStream(MangledName);
|
||||
m_Mang.getNameWithPrefix(MangledNameStream, Name);
|
||||
}
|
||||
return MangledName;
|
||||
}
|
||||
|
||||
public:
|
||||
IncrementalJIT(IncrementalExecutor& exe,
|
||||
std::unique_ptr<llvm::TargetMachine> TM);
|
||||
|
||||
///\brief Get the address of a symbol from the JIT or the memory manager,
|
||||
/// mangling the name as needed. Use this to resolve symbols as coming
|
||||
/// from clang's mangler.
|
||||
uint64_t getSymbolAddress(llvm::StringRef Name) {
|
||||
return getSymbolAddressWithoutMangling(Mangle(Name));
|
||||
}
|
||||
|
||||
///\brief Get the address of a symbol from the JIT or the memory manager.
|
||||
/// Use this to resolve symbols of known, target-specific names.
|
||||
uint64_t getSymbolAddressWithoutMangling(llvm::StringRef Name);
|
||||
|
||||
size_t addModules(std::vector<llvm::Module*>&& modules);
|
||||
void removeModules(size_t handle);
|
||||
|
||||
IncrementalExecutor& getParent() const { return m_Parent; }
|
||||
//void finalizeMemory();
|
||||
};
|
||||
} // end cling
|
||||
#endif // CLING_INCREMENTAL_EXECUTOR_H
|
@ -396,7 +396,7 @@ namespace cling {
|
||||
transformTransactionIR(T);
|
||||
T->setState(Transaction::kCommitted);
|
||||
if (!T->getParent()) {
|
||||
if (m_Interpreter->runStaticInitializersOnce(*T)
|
||||
if (m_Interpreter->executeTransaction(*T)
|
||||
>= Interpreter::kExeFirstError) {
|
||||
// Roll back on error in initializers
|
||||
//assert(0 && "Error on inits.");
|
||||
@ -445,8 +445,6 @@ namespace cling {
|
||||
assert(T->getState() == Transaction::kCompleted && "Must be completed");
|
||||
assert(hasCodeGenerator() && "No CodeGen");
|
||||
|
||||
T->setModule(getCodeGenerator()->GetModule());
|
||||
|
||||
// Could trigger derserialization of decls.
|
||||
Transaction* deserT = beginTransaction(CompilationOptions());
|
||||
for (Transaction::const_iterator TI = T->decls_begin(), TE = T->decls_end();
|
||||
@ -556,16 +554,30 @@ namespace cling {
|
||||
} // for decls in DGR
|
||||
} // for deserialized DGRs
|
||||
|
||||
getCodeGenerator()->HandleTranslationUnit(getCI()->getASTContext());
|
||||
// The initializers are emitted to the symbol "_GLOBAL__sub_I_" + filename.
|
||||
// Make that unique!
|
||||
ASTContext& Context = getCI()->getASTContext();
|
||||
SourceManager &SM = Context.getSourceManager();
|
||||
const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID());
|
||||
FileEntry* NcMainFile = const_cast<FileEntry*>(MainFile);
|
||||
// Hack to temporarily set the file entry's name to a unique name.
|
||||
assert(MainFile->getName() == *(const char**)MainFile
|
||||
&& "FileEntry does not start with the name");
|
||||
const char* &FileName = *(const char**)NcMainFile;
|
||||
const char* OldName = FileName;
|
||||
std::string ModName = getCodeGenerator()->GetModule()->getName().str();
|
||||
FileName = ModName.c_str();
|
||||
getCodeGenerator()->HandleTranslationUnit(Context);
|
||||
FileName = OldName;
|
||||
|
||||
// This llvm::Module is done; finalize it and pass it to the execution
|
||||
// engine.
|
||||
if (!T->isNestedTransaction() && hasCodeGenerator()) {
|
||||
std::unique_ptr<llvm::Module> M(getCodeGenerator()->ReleaseModule());
|
||||
|
||||
if (M) {
|
||||
assert(M.get() == T->getModule()
|
||||
&& "Transaction has inconsistent module");
|
||||
m_Interpreter->addModule(std::move(M));
|
||||
m_Interpreter->addModule(M.get());
|
||||
T->setModule(std::move(M));
|
||||
}
|
||||
|
||||
// Create a new module.
|
||||
@ -617,8 +629,7 @@ namespace cling {
|
||||
if (m_Interpreter->getOptions().ErrorOut)
|
||||
return;
|
||||
|
||||
TransactionUnloader U(&getCI()->getSema(), m_CodeGen.get(),
|
||||
m_Interpreter->getExecutionEngine());
|
||||
TransactionUnloader U(&getCI()->getSema(), m_CodeGen.get());
|
||||
|
||||
if (U.RevertTransaction(T))
|
||||
T->setState(Transaction::kRolledBack);
|
||||
|
@ -355,7 +355,7 @@ namespace cling {
|
||||
ClangInternalState* state
|
||||
= new ClangInternalState(getCI()->getASTContext(),
|
||||
getCI()->getPreprocessor(),
|
||||
CG ? CG->GetModule() : 0,
|
||||
getLastTransaction()->getModule(),
|
||||
CG, name);
|
||||
m_StoredStates.push_back(state);
|
||||
}
|
||||
@ -473,11 +473,6 @@ namespace cling {
|
||||
return getCI()->getSema();
|
||||
}
|
||||
|
||||
llvm::ExecutionEngine* Interpreter::getExecutionEngine() const {
|
||||
if (!m_Executor) return 0;
|
||||
return m_Executor->getExecutionEngine();
|
||||
}
|
||||
|
||||
///\brief Maybe transform the input line to implement cint command line
|
||||
/// semantics (declarations are global) and compile to produce a module.
|
||||
///
|
||||
@ -638,7 +633,7 @@ namespace cling {
|
||||
// decls that need to end up in a transaction. But this one is done
|
||||
// with CodeGen...
|
||||
T->setState(Transaction::kCommitted);
|
||||
if (runStaticInitializersOnce(*T))
|
||||
if (executeTransaction(*T))
|
||||
return Interpreter::kSuccess;
|
||||
|
||||
return Interpreter::kFailure;
|
||||
@ -749,7 +744,7 @@ namespace cling {
|
||||
std::string mangledNameIfNeeded;
|
||||
utils::Analyze::maybeMangleDeclName(FD, mangledNameIfNeeded);
|
||||
IncrementalExecutor::ExecutionResult ExeRes =
|
||||
m_Executor->executeFunction(mangledNameIfNeeded.c_str(), res);
|
||||
m_Executor->executeWrapper(mangledNameIfNeeded.c_str(), res);
|
||||
return ConvertExecutionResult(ExeRes);
|
||||
}
|
||||
|
||||
@ -1130,14 +1125,16 @@ namespace cling {
|
||||
}
|
||||
|
||||
Interpreter::ExecutionResult
|
||||
Interpreter::runStaticInitializersOnce(const Transaction& T) const {
|
||||
Interpreter::executeTransaction(Transaction& T) const {
|
||||
assert(!isInSyntaxOnlyMode() && "Running on what?");
|
||||
assert(T.getState() == Transaction::kCommitted && "Must be committed");
|
||||
|
||||
T.setExeUnloadHandle(m_Executor->emitToJIT());
|
||||
|
||||
// Forward to IncrementalExecutor; should not be called by
|
||||
// anyone except for IncrementalParser.
|
||||
llvm::Module* module = T.getModule();
|
||||
IncrementalExecutor::ExecutionResult ExeRes
|
||||
= m_Executor->runStaticInitializersOnce(module);
|
||||
= m_Executor->runStaticInitializersOnce(T);
|
||||
|
||||
// Reset the module builder to clean up global initializers, c'tors, d'tors
|
||||
ASTContext& C = getCI()->getASTContext();
|
||||
@ -1154,8 +1151,8 @@ namespace cling {
|
||||
return m_Executor->addSymbol(symbolName, symbolAddress);
|
||||
}
|
||||
|
||||
void Interpreter::addModule(std::unique_ptr<llvm::Module> module) {
|
||||
m_Executor->addModule(std::move(module));
|
||||
void Interpreter::addModule(llvm::Module* module) {
|
||||
m_Executor->addModule(module);
|
||||
}
|
||||
|
||||
|
||||
|
@ -471,8 +471,7 @@ namespace cling {
|
||||
TheDecl = TD->getDefinition();
|
||||
if (TheDecl->isInvalidDecl()) {
|
||||
// if the decl is invalid try to clean up
|
||||
TransactionUnloader U(&S, /*CodeGenerator*/0,
|
||||
/*ExecutionEngine*/0);
|
||||
TransactionUnloader U(&S, /*CodeGenerator*/0);
|
||||
U.UnloadDecl(TheDecl);
|
||||
return 0;
|
||||
}
|
||||
@ -700,7 +699,7 @@ namespace cling {
|
||||
}
|
||||
if (scopeDecl->isInvalidDecl()) {
|
||||
// if the decl is invalid try to clean up
|
||||
TransactionUnloader U(&S, /*CodeGenerator*/0, /*ExecutionEngine*/0);
|
||||
TransactionUnloader U(&S, /*CodeGenerator*/0);
|
||||
U.UnloadDecl(const_cast<Decl*>(scopeDecl));
|
||||
return 0;
|
||||
}
|
||||
@ -869,7 +868,7 @@ namespace cling {
|
||||
true /*recursive instantiation*/);
|
||||
if (TheDecl->isInvalidDecl()) {
|
||||
// if the decl is invalid try to clean up
|
||||
TransactionUnloader U(&S, /*CodeGenerator*/0, /*ExecutionEngine*/0);
|
||||
TransactionUnloader U(&S, /*CodeGenerator*/0);
|
||||
U.UnloadDecl(const_cast<FunctionDecl*>(TheDecl));
|
||||
return 0;
|
||||
}
|
||||
@ -1421,7 +1420,7 @@ namespace cling {
|
||||
true /*recursive instantiation*/);
|
||||
if (fdecl->isInvalidDecl()) {
|
||||
// if the decl is invalid try to clean up
|
||||
TransactionUnloader U(&S, /*CodeGenerator*/0, /*ExecutionEngine*/0);
|
||||
TransactionUnloader U(&S, /*CodeGenerator*/0);
|
||||
U.UnloadDecl(fdecl);
|
||||
return 0;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace clang;
|
||||
@ -41,6 +42,7 @@ namespace cling {
|
||||
m_IssuedDiags = kNone;
|
||||
m_Opts = CompilationOptions();
|
||||
m_Module = 0;
|
||||
m_ExeUnload = {0};
|
||||
m_WrapperFD = 0;
|
||||
m_Next = 0;
|
||||
//m_Sema = S;
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
@ -45,10 +44,9 @@ namespace clang {
|
||||
Globals VisitedGlobals;
|
||||
llvm::SmallPtrSet<llvm::Constant *, 8> SeenConstants;
|
||||
clang::CodeGenerator* m_CodeGen;
|
||||
llvm::ExecutionEngine* m_EEngine;
|
||||
public:
|
||||
GlobalValueEraser(clang::CodeGenerator* CG, llvm::ExecutionEngine* EE)
|
||||
: m_CodeGen(CG), m_EEngine(EE) { }
|
||||
GlobalValueEraser(clang::CodeGenerator* CG)
|
||||
: m_CodeGen(CG) { }
|
||||
|
||||
///\brief Erases the given global value and all unused leftovers
|
||||
///
|
||||
@ -93,7 +91,6 @@ namespace clang {
|
||||
if ((*I)->getName().equals("_Unwind_Resume"))
|
||||
continue;
|
||||
|
||||
m_EEngine->updateGlobalMapping(*I, 0);
|
||||
m_CodeGen->forgetGlobal(*I);
|
||||
(*I)->eraseFromParent();
|
||||
}
|
||||
@ -207,10 +204,6 @@ namespace clang {
|
||||
///
|
||||
clang::CodeGenerator* m_CodeGen;
|
||||
|
||||
///\brief The execution engine, either JIT or MCJIT, being recovered.
|
||||
///
|
||||
llvm::ExecutionEngine* m_EEngine;
|
||||
|
||||
///\brief The current transaction being unloaded.
|
||||
///
|
||||
const Transaction* m_CurTransaction;
|
||||
@ -224,9 +217,8 @@ namespace clang {
|
||||
FileIDs m_FilesToUncache;
|
||||
|
||||
public:
|
||||
DeclUnloader(Sema* S, clang::CodeGenerator* CG, llvm::ExecutionEngine* EE,
|
||||
const Transaction* T)
|
||||
: m_Sema(S), m_CodeGen(CG), m_EEngine(EE), m_CurTransaction(T) { }
|
||||
DeclUnloader(Sema* S, clang::CodeGenerator* CG, const Transaction* T)
|
||||
: m_Sema(S), m_CodeGen(CG), m_CurTransaction(T) { }
|
||||
~DeclUnloader();
|
||||
|
||||
///\brief Interface with nice name, forwarding to Visit.
|
||||
@ -1001,7 +993,7 @@ namespace clang {
|
||||
llvm::Module* M = m_CurTransaction->getModule();
|
||||
GlobalValue* GV = M->getNamedValue(mangledName);
|
||||
if (GV) { // May be deferred decl and thus 0
|
||||
GlobalValueEraser GVEraser(m_CodeGen, m_EEngine);
|
||||
GlobalValueEraser GVEraser(m_CodeGen);
|
||||
GVEraser.EraseGlobalValue(GV);
|
||||
}
|
||||
}
|
||||
@ -1177,16 +1169,15 @@ namespace clang {
|
||||
} // end namespace clang
|
||||
|
||||
namespace cling {
|
||||
TransactionUnloader::TransactionUnloader(Sema* S, clang::CodeGenerator* CG,
|
||||
llvm::ExecutionEngine* EE)
|
||||
: m_Sema(S), m_CodeGen(CG), m_EEngine(EE) {
|
||||
TransactionUnloader::TransactionUnloader(Sema* S, clang::CodeGenerator* CG)
|
||||
: m_Sema(S), m_CodeGen(CG) {
|
||||
}
|
||||
|
||||
TransactionUnloader::~TransactionUnloader() {
|
||||
}
|
||||
|
||||
bool TransactionUnloader::RevertTransaction(Transaction* T) {
|
||||
DeclUnloader DeclU(m_Sema, m_CodeGen, m_EEngine, T);
|
||||
DeclUnloader DeclU(m_Sema, m_CodeGen, T);
|
||||
bool Successful = true;
|
||||
|
||||
for (Transaction::const_reverse_iterator I = T->rdecls_begin(),
|
||||
|
@ -10,10 +10,6 @@
|
||||
#ifndef CLING_TRANSACTION_UNLOADER
|
||||
#define CLING_TRANSACTION_UNLOADER
|
||||
|
||||
namespace llvm {
|
||||
class ExecutionEngine;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
class CodeGenerator;
|
||||
class CompilerInstance;
|
||||
@ -31,11 +27,9 @@ namespace cling {
|
||||
private:
|
||||
clang::Sema* m_Sema;
|
||||
clang::CodeGenerator* m_CodeGen;
|
||||
llvm::ExecutionEngine* m_EEngine;
|
||||
|
||||
public:
|
||||
TransactionUnloader(clang::Sema* S, clang::CodeGenerator* CG,
|
||||
llvm::ExecutionEngine* EE);
|
||||
TransactionUnloader(clang::Sema* S, clang::CodeGenerator* CG);
|
||||
~TransactionUnloader();
|
||||
|
||||
///\brief Rolls back given transaction from the AST.
|
||||
|
Loading…
Reference in New Issue
Block a user