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);
|
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] fname - The function name.
|
||||||
///\param [in,out] res - The return result of the run function. Must be
|
///\param [in,out] res - The return result of the run function. Must be
|
||||||
@ -546,14 +546,13 @@ namespace cling {
|
|||||||
|
|
||||||
clang::CompilerInstance* getCI() const;
|
clang::CompilerInstance* getCI() const;
|
||||||
clang::Sema& getSema() const;
|
clang::Sema& getSema() const;
|
||||||
llvm::ExecutionEngine* getExecutionEngine() const;
|
|
||||||
|
|
||||||
//FIXME: This must be in InterpreterCallbacks.
|
//FIXME: This must be in InterpreterCallbacks.
|
||||||
void installLazyFunctionCreator(void* (*fp)(const std::string&));
|
void installLazyFunctionCreator(void* (*fp)(const std::string&));
|
||||||
|
|
||||||
//FIXME: Terrible hack to let the IncrementalParser run static inits on
|
//FIXME: Terrible hack to let the IncrementalParser run static inits on
|
||||||
// transaction completed.
|
// transaction completed.
|
||||||
ExecutionResult runStaticInitializersOnce(const Transaction& T) const;
|
ExecutionResult executeTransaction(Transaction& T) const;
|
||||||
|
|
||||||
///\brief Evaluates given expression within given declaration context.
|
///\brief Evaluates given expression within given declaration context.
|
||||||
///
|
///
|
||||||
@ -626,7 +625,7 @@ namespace cling {
|
|||||||
|
|
||||||
///\brief Forwards to cling::IncrementalExecutor::addModule.
|
///\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,
|
void GenerateAutoloadingMap(llvm::StringRef inFile, llvm::StringRef outFile,
|
||||||
bool enableMacros = false, bool enableLogs = true);
|
bool enableMacros = false, bool enableLogs = true);
|
||||||
|
@ -61,6 +61,11 @@ namespace cling {
|
|||||||
kCCINumStates
|
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
|
///\brief Each declaration group came through different interface at
|
||||||
/// different time. We are being conservative and we want to keep all the
|
/// different time. We are being conservative and we want to keep all the
|
||||||
/// call sequence that originally occurred in clang.
|
/// call sequence that originally occurred in clang.
|
||||||
@ -141,7 +146,12 @@ namespace cling {
|
|||||||
|
|
||||||
///\brief The llvm Module containing the information that we will revert
|
///\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.
|
///\brief The wrapper function produced by the intepreter if any.
|
||||||
///
|
///
|
||||||
@ -426,8 +436,11 @@ namespace cling {
|
|||||||
m_NestedTransactions->clear();
|
m_NestedTransactions->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Module* getModule() const { return m_Module; }
|
llvm::Module* getModule() const { return m_Module.get(); }
|
||||||
void setModule(llvm::Module* M) { m_Module = M ; }
|
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; }
|
clang::FunctionDecl* getWrapperFD() const { return m_WrapperFD; }
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ namespace cling {
|
|||||||
T->erase(found);
|
T->erase(found);
|
||||||
}
|
}
|
||||||
// We know that it didn't end up in the EE by design.
|
// 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);
|
U.UnloadDecl(FD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "IncrementalExecutor.h"
|
#include "IncrementalExecutor.h"
|
||||||
|
#include "IncrementalJIT.h"
|
||||||
|
|
||||||
#include "cling/Interpreter/Value.h"
|
#include "cling/Interpreter/Value.h"
|
||||||
#include "cling/Interpreter/Transaction.h"
|
#include "cling/Interpreter/Transaction.h"
|
||||||
@ -20,99 +21,60 @@
|
|||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
#include "llvm/PassManager.h"
|
#include "llvm/PassManager.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
#include "llvm/ADT/Triple.h"
|
||||||
#include "llvm/ExecutionEngine/MCJIT.h"
|
|
||||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/Support/DynamicLibrary.h"
|
#include "llvm/Support/DynamicLibrary.h"
|
||||||
|
#include "llvm/Support/Host.h"
|
||||||
|
#include "llvm/Support/TargetRegistry.h"
|
||||||
|
#include "llvm/Target/TargetMachine.h"
|
||||||
|
|
||||||
using namespace llvm;
|
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 {
|
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>
|
m_JIT.reset(new IncrementalJIT(*this, std::move(CreateHostTargetMachine())));
|
||||||
IncrementalExecutor::m_lazyFuncCreator;
|
}
|
||||||
|
|
||||||
// Keep in source: ~unique_ptr<ExecutionEngine> needs #include ExecutionEngine
|
// Keep in source: ~unique_ptr<ClingJIT> needs ClingJIT
|
||||||
IncrementalExecutor::~IncrementalExecutor() {}
|
IncrementalExecutor::~IncrementalExecutor() {}
|
||||||
|
|
||||||
void IncrementalExecutor::BuildEngine(std::unique_ptr<llvm::Module> m) {
|
std::unique_ptr<TargetMachine>
|
||||||
//
|
IncrementalExecutor::CreateHostTargetMachine() const {
|
||||||
// Create an execution engine to use.
|
// TODO: make this configurable.
|
||||||
//
|
Triple TheTriple(sys::getProcessTriple());
|
||||||
assert(m && "Module cannot be null");
|
std::string Error;
|
||||||
// Note: Engine takes ownership of the module.
|
const Target *TheTarget
|
||||||
llvm::EngineBuilder builder(std::move(m));
|
= TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
|
||||||
|
if (!TheTarget) {
|
||||||
|
llvm::errs() << "cling::IncrementalExecutor: unable to find target:\n"
|
||||||
|
<< Error;
|
||||||
|
}
|
||||||
|
|
||||||
std::string errMsg;
|
std::string MCPU;
|
||||||
builder.setErrorStr(&errMsg);
|
std::string FeaturesStr;
|
||||||
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:
|
TargetOptions Options = TargetOptions();
|
||||||
llvm::TargetOptions TargetOpts;
|
Options.NoFramePointerElim = 1;
|
||||||
TargetOpts.NoFramePointerElim = 1;
|
Options.JITEmitDebugInfo = 1;
|
||||||
TargetOpts.JITEmitDebugInfo = 1;
|
Reloc::Model RelocModel = Reloc::Default;
|
||||||
|
CodeModel::Model CMModel = CodeModel::JITDefault;
|
||||||
|
CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
|
||||||
|
|
||||||
builder.setTargetOptions(TargetOpts);
|
std::unique_ptr<TargetMachine> TM;
|
||||||
|
TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(),
|
||||||
m_engine.reset(builder.create());
|
MCPU, FeaturesStr,
|
||||||
assert(m_engine && "Cannot create module!");
|
Options,
|
||||||
|
RelocModel, CMModel,
|
||||||
// install lazy function creators
|
OptLevel));
|
||||||
//m_engine->InstallLazyFunctionCreator(NotifyLazyFunctionCreators);
|
return std::move(TM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncrementalExecutor::shuttingDown() {
|
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::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 && "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.
|
// Set m_CurrentAtExitModule to the Module, unset to 0 once done.
|
||||||
struct AtExitModuleSetterRAII {
|
struct AtExitModuleSetterRAII {
|
||||||
@ -244,8 +169,6 @@ IncrementalExecutor::runStaticInitializersOnce(llvm::Module* m) {
|
|||||||
// We don't care whether something was unresolved before.
|
// We don't care whether something was unresolved before.
|
||||||
m_unresolvedSymbols.clear();
|
m_unresolvedSymbols.clear();
|
||||||
|
|
||||||
m_engine->finalizeObject();
|
|
||||||
|
|
||||||
// check if there is any unresolved symbol in the list
|
// check if there is any unresolved symbol in the list
|
||||||
if (diagnoseUnresolvedSymbols("static initializers"))
|
if (diagnoseUnresolvedSymbols("static initializers"))
|
||||||
return kExeUnresolvedSymbols;
|
return kExeUnresolvedSymbols;
|
||||||
@ -290,13 +213,8 @@ IncrementalExecutor::runStaticInitializersOnce(llvm::Module* m) {
|
|||||||
|
|
||||||
// Execute the ctor/dtor function!
|
// Execute the ctor/dtor function!
|
||||||
if (llvm::Function *F = llvm::dyn_cast<llvm::Function>(FP)) {
|
if (llvm::Function *F = llvm::dyn_cast<llvm::Function>(FP)) {
|
||||||
m_engine->getPointerToFunction(F);
|
executeInit(F->getName());
|
||||||
// check if there is any unresolved symbol in the list
|
|
||||||
if (diagnoseUnresolvedSymbols("static initializers"))
|
|
||||||
return kExeUnresolvedSymbols;
|
|
||||||
|
|
||||||
//executeFunction(F->getName());
|
|
||||||
m_engine->runFunction(F, std::vector<llvm::GenericValue>());
|
|
||||||
initFuncs.push_back(F);
|
initFuncs.push_back(F);
|
||||||
if (F->getName().startswith("_GLOBAL__sub_I__")) {
|
if (F->getName().startswith("_GLOBAL__sub_I__")) {
|
||||||
BasicBlock& BB = F->getEntryBlock();
|
BasicBlock& BB = F->getEntryBlock();
|
||||||
@ -369,14 +287,6 @@ IncrementalExecutor::addSymbol(const char* symbolName, void* symbolAddress) {
|
|||||||
return true;
|
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,
|
void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName,
|
||||||
bool* fromJIT /*=0*/) {
|
bool* fromJIT /*=0*/) {
|
||||||
// Return a symbol's address, and whether it was jitted.
|
// Return a symbol's address, and whether it was jitted.
|
||||||
@ -388,7 +298,7 @@ void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName,
|
|||||||
*fromJIT = !address;
|
*fromJIT = !address;
|
||||||
|
|
||||||
if (!address)
|
if (!address)
|
||||||
return (void*)m_engine->getGlobalValueAddress(symbolName);
|
return (void*)m_JIT->getSymbolAddress(symbolName);
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
@ -400,14 +310,11 @@ IncrementalExecutor::getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) {
|
|||||||
// We don't care whether something was unresolved before.
|
// We don't care whether something was unresolved before.
|
||||||
m_unresolvedSymbols.clear();
|
m_unresolvedSymbols.clear();
|
||||||
|
|
||||||
if (void* addr = m_engine->getPointerToGlobalIfAvailable(&GV))
|
void* addr = (void*)m_JIT->getSymbolAddress(GV.getName());
|
||||||
return addr;
|
|
||||||
|
|
||||||
// Function not yet codegened by the JIT, force this to happen now.
|
|
||||||
void* Ptr = m_engine->getPointerToGlobal(&GV);
|
|
||||||
if (diagnoseUnresolvedSymbols(GV.getName(), "symbol"))
|
if (diagnoseUnresolvedSymbols(GV.getName(), "symbol"))
|
||||||
return 0;
|
return 0;
|
||||||
return Ptr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
|
bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
|
||||||
@ -435,12 +342,12 @@ bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
|
|||||||
if (!title.empty())
|
if (!title.empty())
|
||||||
llvm::errs() << "'";
|
llvm::errs() << "'";
|
||||||
llvm::errs() << "!\n";
|
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.
|
// i could also reference a global variable, in which case ff == 0.
|
||||||
if (ff)
|
//if (ff)
|
||||||
funcsToFree.push_back(ff);
|
// funcsToFree.push_back(ff);
|
||||||
}
|
}
|
||||||
freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
|
//freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
|
||||||
m_unresolvedSymbols.clear();
|
m_unresolvedSymbols.clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,12 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/StringRef.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 <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
@ -24,32 +29,23 @@ namespace clang {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class ExecutionEngine;
|
|
||||||
class GlobalValue;
|
class GlobalValue;
|
||||||
class Module;
|
class Module;
|
||||||
|
class TargetMachine;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace cling {
|
namespace cling {
|
||||||
class Transaction;
|
|
||||||
class Value;
|
class Value;
|
||||||
|
class IncrementalJIT;
|
||||||
|
|
||||||
class IncrementalExecutor {
|
class IncrementalExecutor {
|
||||||
public:
|
public:
|
||||||
typedef void* (*LazyFunctionCreatorFunc_t)(const std::string&);
|
typedef void* (*LazyFunctionCreatorFunc_t)(const std::string&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///\brief Set of the symbols that the ExecutionEngine couldn't resolve.
|
///\brief Our JIT interface.
|
||||||
///
|
///
|
||||||
static std::set<std::string> m_unresolvedSymbols;
|
std::unique_ptr<IncrementalJIT> m_JIT;
|
||||||
|
|
||||||
///\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;
|
|
||||||
|
|
||||||
///\brief Helper that manages when the destructor of an object to be called.
|
///\brief Helper that manages when the destructor of an object to be called.
|
||||||
///
|
///
|
||||||
@ -103,6 +99,18 @@ namespace cling {
|
|||||||
/// takes place.
|
/// takes place.
|
||||||
llvm::Module* m_CurrentAtExitModule;
|
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
|
#if 0 // See FIXME in IncrementalExecutor.cpp
|
||||||
///\brief The diagnostics engine, printing out issues coming from the
|
///\brief The diagnostics engine, printing out issues coming from the
|
||||||
@ -110,6 +118,8 @@ namespace cling {
|
|||||||
clang::DiagnosticsEngine& m_Diags;
|
clang::DiagnosticsEngine& m_Diags;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::unique_ptr<llvm::TargetMachine> CreateHostTargetMachine() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum ExecutionResult {
|
enum ExecutionResult {
|
||||||
kExeSuccess,
|
kExeSuccess,
|
||||||
@ -118,20 +128,28 @@ namespace cling {
|
|||||||
kNumExeResults
|
kNumExeResults
|
||||||
};
|
};
|
||||||
|
|
||||||
IncrementalExecutor(clang::DiagnosticsEngine& diags):
|
IncrementalExecutor(clang::DiagnosticsEngine& diags);
|
||||||
m_CurrentAtExitModule(0)
|
|
||||||
#if 0
|
|
||||||
: m_Diags(diags)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
m_AtExitFuncs.reserve(256);
|
|
||||||
}
|
|
||||||
|
|
||||||
~IncrementalExecutor();
|
~IncrementalExecutor();
|
||||||
|
|
||||||
void installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp);
|
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
|
///\brief Runs all destructors bound to the given transaction and removes
|
||||||
/// them from the list.
|
/// them from the list.
|
||||||
@ -139,8 +157,21 @@ namespace cling {
|
|||||||
///
|
///
|
||||||
void runAndRemoveStaticDestructors(Transaction* T);
|
void runAndRemoveStaticDestructors(Transaction* T);
|
||||||
|
|
||||||
ExecutionResult executeFunction(llvm::StringRef function,
|
///\brief Runs a wrapper function.
|
||||||
Value* returnValue = 0);
|
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.
|
///\brief Adds a symbol (function) to the execution engine.
|
||||||
///
|
///
|
||||||
@ -154,11 +185,10 @@ namespace cling {
|
|||||||
///
|
///
|
||||||
bool addSymbol(const char* symbolName, void* symbolAddress);
|
bool addSymbol(const char* symbolName, void* symbolAddress);
|
||||||
|
|
||||||
///\brief Add a llvm::Module to the ExecutionEngine, see
|
///\brief Add a llvm::Module to the JIT.
|
||||||
/// ExecutionEngine::addModule()
|
|
||||||
///
|
///
|
||||||
/// @param[in] module - The module to pass to the execution engine.
|
/// @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.
|
///\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);
|
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
|
/// opposed to dynamic libraries). Forces the emission of the symbol if
|
||||||
/// it has not happened yet.
|
/// it has not happened yet.
|
||||||
///
|
///
|
||||||
///param[in] GV - global value for which the address will be returned.
|
///param[in] GV - global value for which the address will be returned.
|
||||||
void* getPointerToGlobalFromJIT(const llvm::GlobalValue& GV);
|
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.
|
///\brief Keep track of the entities whose dtor we need to call.
|
||||||
///
|
///
|
||||||
void AddAtExitFunc(void (*func) (void*), void* arg);
|
void AddAtExitFunc(void (*func) (void*), void* arg);
|
||||||
@ -201,17 +225,42 @@ namespace cling {
|
|||||||
void* NotifyLazyFunctionCreators(const std::string&);
|
void* NotifyLazyFunctionCreators(const std::string&);
|
||||||
|
|
||||||
private:
|
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.
|
///\brief Report and empty m_unresolvedSymbols.
|
||||||
///\return true if m_unresolvedSymbols was non-empty.
|
///\return true if m_unresolvedSymbols was non-empty.
|
||||||
bool diagnoseUnresolvedSymbols(llvm::StringRef trigger,
|
bool diagnoseUnresolvedSymbols(llvm::StringRef trigger,
|
||||||
llvm::StringRef title = llvm::StringRef());
|
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
|
} // end cling
|
||||||
#endif // CLING_INCREMENTAL_EXECUTOR_H
|
#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);
|
transformTransactionIR(T);
|
||||||
T->setState(Transaction::kCommitted);
|
T->setState(Transaction::kCommitted);
|
||||||
if (!T->getParent()) {
|
if (!T->getParent()) {
|
||||||
if (m_Interpreter->runStaticInitializersOnce(*T)
|
if (m_Interpreter->executeTransaction(*T)
|
||||||
>= Interpreter::kExeFirstError) {
|
>= Interpreter::kExeFirstError) {
|
||||||
// Roll back on error in initializers
|
// Roll back on error in initializers
|
||||||
//assert(0 && "Error on inits.");
|
//assert(0 && "Error on inits.");
|
||||||
@ -445,8 +445,6 @@ namespace cling {
|
|||||||
assert(T->getState() == Transaction::kCompleted && "Must be completed");
|
assert(T->getState() == Transaction::kCompleted && "Must be completed");
|
||||||
assert(hasCodeGenerator() && "No CodeGen");
|
assert(hasCodeGenerator() && "No CodeGen");
|
||||||
|
|
||||||
T->setModule(getCodeGenerator()->GetModule());
|
|
||||||
|
|
||||||
// Could trigger derserialization of decls.
|
// Could trigger derserialization of decls.
|
||||||
Transaction* deserT = beginTransaction(CompilationOptions());
|
Transaction* deserT = beginTransaction(CompilationOptions());
|
||||||
for (Transaction::const_iterator TI = T->decls_begin(), TE = T->decls_end();
|
for (Transaction::const_iterator TI = T->decls_begin(), TE = T->decls_end();
|
||||||
@ -556,16 +554,30 @@ namespace cling {
|
|||||||
} // for decls in DGR
|
} // for decls in DGR
|
||||||
} // for deserialized DGRs
|
} // 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
|
// This llvm::Module is done; finalize it and pass it to the execution
|
||||||
// engine.
|
// engine.
|
||||||
if (!T->isNestedTransaction() && hasCodeGenerator()) {
|
if (!T->isNestedTransaction() && hasCodeGenerator()) {
|
||||||
std::unique_ptr<llvm::Module> M(getCodeGenerator()->ReleaseModule());
|
std::unique_ptr<llvm::Module> M(getCodeGenerator()->ReleaseModule());
|
||||||
|
|
||||||
if (M) {
|
if (M) {
|
||||||
assert(M.get() == T->getModule()
|
m_Interpreter->addModule(M.get());
|
||||||
&& "Transaction has inconsistent module");
|
T->setModule(std::move(M));
|
||||||
m_Interpreter->addModule(std::move(M));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new module.
|
// Create a new module.
|
||||||
@ -617,8 +629,7 @@ namespace cling {
|
|||||||
if (m_Interpreter->getOptions().ErrorOut)
|
if (m_Interpreter->getOptions().ErrorOut)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TransactionUnloader U(&getCI()->getSema(), m_CodeGen.get(),
|
TransactionUnloader U(&getCI()->getSema(), m_CodeGen.get());
|
||||||
m_Interpreter->getExecutionEngine());
|
|
||||||
|
|
||||||
if (U.RevertTransaction(T))
|
if (U.RevertTransaction(T))
|
||||||
T->setState(Transaction::kRolledBack);
|
T->setState(Transaction::kRolledBack);
|
||||||
|
@ -355,7 +355,7 @@ namespace cling {
|
|||||||
ClangInternalState* state
|
ClangInternalState* state
|
||||||
= new ClangInternalState(getCI()->getASTContext(),
|
= new ClangInternalState(getCI()->getASTContext(),
|
||||||
getCI()->getPreprocessor(),
|
getCI()->getPreprocessor(),
|
||||||
CG ? CG->GetModule() : 0,
|
getLastTransaction()->getModule(),
|
||||||
CG, name);
|
CG, name);
|
||||||
m_StoredStates.push_back(state);
|
m_StoredStates.push_back(state);
|
||||||
}
|
}
|
||||||
@ -473,11 +473,6 @@ namespace cling {
|
|||||||
return getCI()->getSema();
|
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
|
///\brief Maybe transform the input line to implement cint command line
|
||||||
/// semantics (declarations are global) and compile to produce a module.
|
/// 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
|
// decls that need to end up in a transaction. But this one is done
|
||||||
// with CodeGen...
|
// with CodeGen...
|
||||||
T->setState(Transaction::kCommitted);
|
T->setState(Transaction::kCommitted);
|
||||||
if (runStaticInitializersOnce(*T))
|
if (executeTransaction(*T))
|
||||||
return Interpreter::kSuccess;
|
return Interpreter::kSuccess;
|
||||||
|
|
||||||
return Interpreter::kFailure;
|
return Interpreter::kFailure;
|
||||||
@ -749,7 +744,7 @@ namespace cling {
|
|||||||
std::string mangledNameIfNeeded;
|
std::string mangledNameIfNeeded;
|
||||||
utils::Analyze::maybeMangleDeclName(FD, mangledNameIfNeeded);
|
utils::Analyze::maybeMangleDeclName(FD, mangledNameIfNeeded);
|
||||||
IncrementalExecutor::ExecutionResult ExeRes =
|
IncrementalExecutor::ExecutionResult ExeRes =
|
||||||
m_Executor->executeFunction(mangledNameIfNeeded.c_str(), res);
|
m_Executor->executeWrapper(mangledNameIfNeeded.c_str(), res);
|
||||||
return ConvertExecutionResult(ExeRes);
|
return ConvertExecutionResult(ExeRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,14 +1125,16 @@ namespace cling {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Interpreter::ExecutionResult
|
Interpreter::ExecutionResult
|
||||||
Interpreter::runStaticInitializersOnce(const Transaction& T) const {
|
Interpreter::executeTransaction(Transaction& T) const {
|
||||||
assert(!isInSyntaxOnlyMode() && "Running on what?");
|
assert(!isInSyntaxOnlyMode() && "Running on what?");
|
||||||
assert(T.getState() == Transaction::kCommitted && "Must be committed");
|
assert(T.getState() == Transaction::kCommitted && "Must be committed");
|
||||||
|
|
||||||
|
T.setExeUnloadHandle(m_Executor->emitToJIT());
|
||||||
|
|
||||||
// Forward to IncrementalExecutor; should not be called by
|
// Forward to IncrementalExecutor; should not be called by
|
||||||
// anyone except for IncrementalParser.
|
// anyone except for IncrementalParser.
|
||||||
llvm::Module* module = T.getModule();
|
|
||||||
IncrementalExecutor::ExecutionResult ExeRes
|
IncrementalExecutor::ExecutionResult ExeRes
|
||||||
= m_Executor->runStaticInitializersOnce(module);
|
= m_Executor->runStaticInitializersOnce(T);
|
||||||
|
|
||||||
// Reset the module builder to clean up global initializers, c'tors, d'tors
|
// Reset the module builder to clean up global initializers, c'tors, d'tors
|
||||||
ASTContext& C = getCI()->getASTContext();
|
ASTContext& C = getCI()->getASTContext();
|
||||||
@ -1154,8 +1151,8 @@ namespace cling {
|
|||||||
return m_Executor->addSymbol(symbolName, symbolAddress);
|
return m_Executor->addSymbol(symbolName, symbolAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::addModule(std::unique_ptr<llvm::Module> module) {
|
void Interpreter::addModule(llvm::Module* module) {
|
||||||
m_Executor->addModule(std::move(module));
|
m_Executor->addModule(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -471,8 +471,7 @@ namespace cling {
|
|||||||
TheDecl = TD->getDefinition();
|
TheDecl = TD->getDefinition();
|
||||||
if (TheDecl->isInvalidDecl()) {
|
if (TheDecl->isInvalidDecl()) {
|
||||||
// if the decl is invalid try to clean up
|
// if the decl is invalid try to clean up
|
||||||
TransactionUnloader U(&S, /*CodeGenerator*/0,
|
TransactionUnloader U(&S, /*CodeGenerator*/0);
|
||||||
/*ExecutionEngine*/0);
|
|
||||||
U.UnloadDecl(TheDecl);
|
U.UnloadDecl(TheDecl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -700,7 +699,7 @@ namespace cling {
|
|||||||
}
|
}
|
||||||
if (scopeDecl->isInvalidDecl()) {
|
if (scopeDecl->isInvalidDecl()) {
|
||||||
// if the decl is invalid try to clean up
|
// 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));
|
U.UnloadDecl(const_cast<Decl*>(scopeDecl));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -869,7 +868,7 @@ namespace cling {
|
|||||||
true /*recursive instantiation*/);
|
true /*recursive instantiation*/);
|
||||||
if (TheDecl->isInvalidDecl()) {
|
if (TheDecl->isInvalidDecl()) {
|
||||||
// if the decl is invalid try to clean up
|
// 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));
|
U.UnloadDecl(const_cast<FunctionDecl*>(TheDecl));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1421,7 +1420,7 @@ namespace cling {
|
|||||||
true /*recursive instantiation*/);
|
true /*recursive instantiation*/);
|
||||||
if (fdecl->isInvalidDecl()) {
|
if (fdecl->isInvalidDecl()) {
|
||||||
// if the decl is invalid try to clean up
|
// if the decl is invalid try to clean up
|
||||||
TransactionUnloader U(&S, /*CodeGenerator*/0, /*ExecutionEngine*/0);
|
TransactionUnloader U(&S, /*CodeGenerator*/0);
|
||||||
U.UnloadDecl(fdecl);
|
U.UnloadDecl(fdecl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "clang/Lex/Preprocessor.h"
|
#include "clang/Lex/Preprocessor.h"
|
||||||
#include "clang/Sema/Sema.h"
|
#include "clang/Sema/Sema.h"
|
||||||
|
|
||||||
|
#include "llvm/IR/Module.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
@ -41,6 +42,7 @@ namespace cling {
|
|||||||
m_IssuedDiags = kNone;
|
m_IssuedDiags = kNone;
|
||||||
m_Opts = CompilationOptions();
|
m_Opts = CompilationOptions();
|
||||||
m_Module = 0;
|
m_Module = 0;
|
||||||
|
m_ExeUnload = {0};
|
||||||
m_WrapperFD = 0;
|
m_WrapperFD = 0;
|
||||||
m_Next = 0;
|
m_Next = 0;
|
||||||
//m_Sema = S;
|
//m_Sema = S;
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include "clang/Lex/MacroInfo.h"
|
#include "clang/Lex/MacroInfo.h"
|
||||||
#include "clang/Lex/Preprocessor.h"
|
#include "clang/Lex/Preprocessor.h"
|
||||||
|
|
||||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
|
||||||
#include "llvm/IR/Constants.h"
|
#include "llvm/IR/Constants.h"
|
||||||
#include "llvm/IR/DerivedTypes.h"
|
#include "llvm/IR/DerivedTypes.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
@ -45,10 +44,9 @@ namespace clang {
|
|||||||
Globals VisitedGlobals;
|
Globals VisitedGlobals;
|
||||||
llvm::SmallPtrSet<llvm::Constant *, 8> SeenConstants;
|
llvm::SmallPtrSet<llvm::Constant *, 8> SeenConstants;
|
||||||
clang::CodeGenerator* m_CodeGen;
|
clang::CodeGenerator* m_CodeGen;
|
||||||
llvm::ExecutionEngine* m_EEngine;
|
|
||||||
public:
|
public:
|
||||||
GlobalValueEraser(clang::CodeGenerator* CG, llvm::ExecutionEngine* EE)
|
GlobalValueEraser(clang::CodeGenerator* CG)
|
||||||
: m_CodeGen(CG), m_EEngine(EE) { }
|
: m_CodeGen(CG) { }
|
||||||
|
|
||||||
///\brief Erases the given global value and all unused leftovers
|
///\brief Erases the given global value and all unused leftovers
|
||||||
///
|
///
|
||||||
@ -93,7 +91,6 @@ namespace clang {
|
|||||||
if ((*I)->getName().equals("_Unwind_Resume"))
|
if ((*I)->getName().equals("_Unwind_Resume"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_EEngine->updateGlobalMapping(*I, 0);
|
|
||||||
m_CodeGen->forgetGlobal(*I);
|
m_CodeGen->forgetGlobal(*I);
|
||||||
(*I)->eraseFromParent();
|
(*I)->eraseFromParent();
|
||||||
}
|
}
|
||||||
@ -207,10 +204,6 @@ namespace clang {
|
|||||||
///
|
///
|
||||||
clang::CodeGenerator* m_CodeGen;
|
clang::CodeGenerator* m_CodeGen;
|
||||||
|
|
||||||
///\brief The execution engine, either JIT or MCJIT, being recovered.
|
|
||||||
///
|
|
||||||
llvm::ExecutionEngine* m_EEngine;
|
|
||||||
|
|
||||||
///\brief The current transaction being unloaded.
|
///\brief The current transaction being unloaded.
|
||||||
///
|
///
|
||||||
const Transaction* m_CurTransaction;
|
const Transaction* m_CurTransaction;
|
||||||
@ -224,9 +217,8 @@ namespace clang {
|
|||||||
FileIDs m_FilesToUncache;
|
FileIDs m_FilesToUncache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeclUnloader(Sema* S, clang::CodeGenerator* CG, llvm::ExecutionEngine* EE,
|
DeclUnloader(Sema* S, clang::CodeGenerator* CG, const Transaction* T)
|
||||||
const Transaction* T)
|
: m_Sema(S), m_CodeGen(CG), m_CurTransaction(T) { }
|
||||||
: m_Sema(S), m_CodeGen(CG), m_EEngine(EE), m_CurTransaction(T) { }
|
|
||||||
~DeclUnloader();
|
~DeclUnloader();
|
||||||
|
|
||||||
///\brief Interface with nice name, forwarding to Visit.
|
///\brief Interface with nice name, forwarding to Visit.
|
||||||
@ -1001,7 +993,7 @@ namespace clang {
|
|||||||
llvm::Module* M = m_CurTransaction->getModule();
|
llvm::Module* M = m_CurTransaction->getModule();
|
||||||
GlobalValue* GV = M->getNamedValue(mangledName);
|
GlobalValue* GV = M->getNamedValue(mangledName);
|
||||||
if (GV) { // May be deferred decl and thus 0
|
if (GV) { // May be deferred decl and thus 0
|
||||||
GlobalValueEraser GVEraser(m_CodeGen, m_EEngine);
|
GlobalValueEraser GVEraser(m_CodeGen);
|
||||||
GVEraser.EraseGlobalValue(GV);
|
GVEraser.EraseGlobalValue(GV);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1177,16 +1169,15 @@ namespace clang {
|
|||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
namespace cling {
|
namespace cling {
|
||||||
TransactionUnloader::TransactionUnloader(Sema* S, clang::CodeGenerator* CG,
|
TransactionUnloader::TransactionUnloader(Sema* S, clang::CodeGenerator* CG)
|
||||||
llvm::ExecutionEngine* EE)
|
: m_Sema(S), m_CodeGen(CG) {
|
||||||
: m_Sema(S), m_CodeGen(CG), m_EEngine(EE) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionUnloader::~TransactionUnloader() {
|
TransactionUnloader::~TransactionUnloader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TransactionUnloader::RevertTransaction(Transaction* T) {
|
bool TransactionUnloader::RevertTransaction(Transaction* T) {
|
||||||
DeclUnloader DeclU(m_Sema, m_CodeGen, m_EEngine, T);
|
DeclUnloader DeclU(m_Sema, m_CodeGen, T);
|
||||||
bool Successful = true;
|
bool Successful = true;
|
||||||
|
|
||||||
for (Transaction::const_reverse_iterator I = T->rdecls_begin(),
|
for (Transaction::const_reverse_iterator I = T->rdecls_begin(),
|
||||||
|
@ -10,10 +10,6 @@
|
|||||||
#ifndef CLING_TRANSACTION_UNLOADER
|
#ifndef CLING_TRANSACTION_UNLOADER
|
||||||
#define CLING_TRANSACTION_UNLOADER
|
#define CLING_TRANSACTION_UNLOADER
|
||||||
|
|
||||||
namespace llvm {
|
|
||||||
class ExecutionEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
class CodeGenerator;
|
class CodeGenerator;
|
||||||
class CompilerInstance;
|
class CompilerInstance;
|
||||||
@ -31,11 +27,9 @@ namespace cling {
|
|||||||
private:
|
private:
|
||||||
clang::Sema* m_Sema;
|
clang::Sema* m_Sema;
|
||||||
clang::CodeGenerator* m_CodeGen;
|
clang::CodeGenerator* m_CodeGen;
|
||||||
llvm::ExecutionEngine* m_EEngine;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TransactionUnloader(clang::Sema* S, clang::CodeGenerator* CG,
|
TransactionUnloader(clang::Sema* S, clang::CodeGenerator* CG);
|
||||||
llvm::ExecutionEngine* EE);
|
|
||||||
~TransactionUnloader();
|
~TransactionUnloader();
|
||||||
|
|
||||||
///\brief Rolls back given transaction from the AST.
|
///\brief Rolls back given transaction from the AST.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user