cling/lib/Interpreter/IncrementalJIT.cpp

241 lines
8.8 KiB
C++

//--------------------------------------------------------------------*- 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"
#ifdef __APPLE__
// Apple adds an extra '_'
# define MANGLE_PREFIX "_"
#else
# define MANGLE_PREFIX ""
#endif
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 {
std::string NameNoPrefix;
if (MANGLE_PREFIX[0]
&& !Name.compare(0, strlen(MANGLE_PREFIX), MANGLE_PREFIX))
NameNoPrefix = Name.substr(strlen(MANGLE_PREFIX), -1);
else
NameNoPrefix = std::move(Name);
return (uint64_t) m_jit.getParent().NotifyLazyFunctionCreators(NameNoPrefix);
}
}; // 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 == MANGLE_PREFIX "__cxa_atexit") {
// Rewire __cxa_atexit to ~Interpreter(), thus also global destruction
// coming from the JIT.
return (uint64_t)&local_cxa_atexit;
} else if (Name == MANGLE_PREFIX "__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