Replace use of ExecutionEngine by OrcJIT.

This commit is contained in:
Axel Naumann 2015-02-03 21:32:09 +01:00 committed by sftnight
parent d9a804df73
commit 16fe3f49dc
13 changed files with 582 additions and 243 deletions

View File

@ -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);

View File

@ -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; }

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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

View 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

View 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

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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(),

View File

@ -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.