432c91f534
This is needed because TOC and text sections can be more than 2GB apart. LLVM SectionMemoryManager is not aware of the design limits of ppc64le while allocating memory for JIT'ed sections. DSO limit was set to 2GB by design. While running CMSSW ROOT/Cling puts TOC and .text.func ~2.7GB apart in VA space. Usually was triggered by TFormula in CMSSW. IBM has modified global entry function prologue. TOC is now stored in 64-bit value before global entry to allow addressing beyond 2GB. This was merged to Clang months ago, but is only applicable to large code model. Later IBM propagated this further: - binutils patches are here: https://sourceware.org/ml/binutils/2015-11/msg00232.html https://sourceware.org/ml/binutils/2015-11/msg00233.html and will be available with binutils 2.26 - GCC patch is here: https://gcc.gnu.org/ml/gcc-patches/2015-12/msg00355.html and will be available with GCC 6.0. - LLVM patch is here: http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20160111/324454.html and will be available with LLVM 3.8. - Kernel patches (module loader etc.) are here: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=a61674bdfc7c2bf909c4010699607b62b69b7bec https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=2e50c4bef77511b42cc226865d6bc568fa7f8769 and will be available with Linux 4.5. Signed-off-by: David Abdurachmanov <David.Abdurachmanov@cern.ch>
435 lines
14 KiB
C++
435 lines
14 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 "IncrementalExecutor.h"
|
|
#include "IncrementalJIT.h"
|
|
#include "Threading.h"
|
|
|
|
#include "cling/Interpreter/Value.h"
|
|
#include "cling/Interpreter/Transaction.h"
|
|
#include "cling/Utils/AST.h"
|
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
#include <clang/Frontend/CodeGenOptions.h>
|
|
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include "llvm/ADT/Triple.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/Support/Host.h"
|
|
#include "llvm/Support/TargetRegistry.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#ifdef LLVM_ON_WIN32
|
|
extern "C"
|
|
char *__unDName(char *demangled, const char *mangled, int out_len,
|
|
void * (* pAlloc )(size_t), void (* pFree )(void *),
|
|
unsigned short int flags);
|
|
#else
|
|
#include <cxxabi.h>
|
|
#endif
|
|
|
|
using namespace llvm;
|
|
|
|
namespace cling {
|
|
|
|
IncrementalExecutor::IncrementalExecutor(clang::DiagnosticsEngine& diags,
|
|
const clang::CodeGenOptions& CGOpt):
|
|
m_externalIncrementalExecutor(nullptr),
|
|
m_CurrentAtExitModule(0)
|
|
#if 0
|
|
: m_Diags(diags)
|
|
#endif
|
|
{
|
|
|
|
// MSVC doesn't support m_AtExitFuncsSpinLock=ATOMIC_FLAG_INIT; in the class definition
|
|
std::atomic_flag_clear( &m_AtExitFuncsSpinLock );
|
|
|
|
// No need to protect this access of m_AtExitFuncs, since nobody
|
|
// can use this object yet.
|
|
m_AtExitFuncs.reserve(256);
|
|
|
|
m_JIT.reset(new IncrementalJIT(*this, CreateHostTargetMachine(CGOpt)));
|
|
}
|
|
|
|
// Keep in source: ~unique_ptr<ClingJIT> needs ClingJIT
|
|
IncrementalExecutor::~IncrementalExecutor() {}
|
|
|
|
std::unique_ptr<TargetMachine>
|
|
IncrementalExecutor::CreateHostTargetMachine(const
|
|
clang::CodeGenOptions& CGOpt) const {
|
|
// TODO: make this configurable.
|
|
Triple TheTriple(sys::getProcessTriple());
|
|
#ifdef _WIN32
|
|
/*
|
|
* MCJIT works on Windows, but currently only through ELF object format.
|
|
*/
|
|
TheTriple.setObjectFormat(llvm::Triple::ELF);
|
|
#endif
|
|
std::string Error;
|
|
const Target *TheTarget
|
|
= TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
|
|
if (!TheTarget) {
|
|
llvm::errs() << "cling::IncrementalExecutor: unable to find target:\n"
|
|
<< Error;
|
|
return std::unique_ptr<TargetMachine>();
|
|
}
|
|
|
|
std::string MCPU;
|
|
std::string FeaturesStr;
|
|
|
|
TargetOptions Options = TargetOptions();
|
|
// We have to use large code model for PowerPC64 because TOC and text sections
|
|
// can be more than 2GB apart.
|
|
#if defined(__powerpc64__) || defined(__PPC64__)
|
|
CodeModel::Model CMModel = CodeModel::Large;
|
|
#else
|
|
CodeModel::Model CMModel = CodeModel::JITDefault;
|
|
#endif
|
|
CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
|
|
switch (CGOpt.OptimizationLevel) {
|
|
case 0: OptLevel = CodeGenOpt::None; break;
|
|
case 1: OptLevel = CodeGenOpt::Less; break;
|
|
case 2: OptLevel = CodeGenOpt::Default; break;
|
|
case 3: OptLevel = CodeGenOpt::Aggressive; break;
|
|
default: OptLevel = CodeGenOpt::Default;
|
|
}
|
|
|
|
std::unique_ptr<TargetMachine> TM;
|
|
TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(),
|
|
MCPU, FeaturesStr,
|
|
Options,
|
|
Optional<Reloc::Model>(),
|
|
CMModel,
|
|
OptLevel));
|
|
return TM;
|
|
}
|
|
|
|
void IncrementalExecutor::shuttingDown() {
|
|
// No need to protect this access, since hopefully there is no concurrent
|
|
// shutdown request.
|
|
for (size_t I = 0, N = m_AtExitFuncs.size(); I < N; ++I) {
|
|
const CXAAtExitElement& AEE = m_AtExitFuncs[N - I - 1];
|
|
(*AEE.m_Func)(AEE.m_Arg);
|
|
}
|
|
}
|
|
|
|
void IncrementalExecutor::AddAtExitFunc(void (*func) (void*), void* arg) {
|
|
// Register a CXAAtExit function
|
|
cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
|
|
m_AtExitFuncs.push_back(CXAAtExitElement(func, arg, m_CurrentAtExitModule));
|
|
}
|
|
|
|
void unresolvedSymbol()
|
|
{
|
|
// This might get called recursively, or a billion of times. Do not generate
|
|
// useless output; unresolvedSymbol() is always handed out with an error
|
|
// message - that's enough.
|
|
//llvm::errs() << "IncrementalExecutor: calling unresolved symbol, "
|
|
// "see previous error message!\n";
|
|
|
|
// throw exception instead?
|
|
}
|
|
|
|
void* IncrementalExecutor::HandleMissingFunction(const std::string& mangled_name)
|
|
{
|
|
// Not found in the map, add the symbol in the list of unresolved symbols
|
|
if (m_unresolvedSymbols.insert(mangled_name).second) {
|
|
//llvm::errs() << "IncrementalExecutor: use of undefined symbol '"
|
|
// << mangled_name << "'!\n";
|
|
}
|
|
|
|
// Avoid "ISO C++ forbids casting between pointer-to-function and
|
|
// pointer-to-object":
|
|
return (void*)reinterpret_cast<size_t>(unresolvedSymbol);
|
|
}
|
|
|
|
void* IncrementalExecutor::NotifyLazyFunctionCreators(const std::string& mangled_name)
|
|
{
|
|
for (std::vector<LazyFunctionCreatorFunc_t>::iterator it
|
|
= m_lazyFuncCreator.begin(), et = m_lazyFuncCreator.end();
|
|
it != et; ++it) {
|
|
void* ret = (void*)((LazyFunctionCreatorFunc_t)*it)(mangled_name);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
void *address = nullptr;
|
|
if (m_externalIncrementalExecutor)
|
|
address = m_externalIncrementalExecutor->getAddressOfGlobal(mangled_name);
|
|
|
|
return (address ? address : HandleMissingFunction(mangled_name));
|
|
}
|
|
|
|
#if 0
|
|
// FIXME: employ to empty module dependencies *within* the *current* module.
|
|
static void
|
|
freeCallersOfUnresolvedSymbols(llvm::SmallVectorImpl<llvm::Function*>&
|
|
funcsToFree, llvm::ExecutionEngine* engine) {
|
|
llvm::SmallPtrSet<llvm::Function*, 40> funcsToFreeUnique;
|
|
for (size_t i = 0; i < funcsToFree.size(); ++i) {
|
|
llvm::Function* func = funcsToFree[i];
|
|
assert(func && "Cannot free NULL function");
|
|
if (funcsToFreeUnique.insert(func).second) {
|
|
for (llvm::Value::use_iterator IU = func->use_begin(),
|
|
EU = func->use_end(); IU != EU; ++IU) {
|
|
llvm::Instruction* instUser = llvm::dyn_cast<llvm::Instruction>(*IU);
|
|
if (!instUser) continue;
|
|
if (!instUser->getParent()) continue;
|
|
if (llvm::Function* userFunc = instUser->getParent()->getParent())
|
|
funcsToFree.push_back(userFunc);
|
|
}
|
|
}
|
|
}
|
|
for (llvm::SmallPtrSet<llvm::Function*, 40>::iterator
|
|
I = funcsToFreeUnique.begin(), E = funcsToFreeUnique.end();
|
|
I != E; ++I) {
|
|
// This should force the JIT to recompile the function. But the stubs stay,
|
|
// and the JIT reuses the stubs now pointing nowhere, i.e. without updating
|
|
// the machine code address. Fix the JIT, or hope that MCJIT helps.
|
|
//engine->freeMachineCodeForFunction(*I);
|
|
engine->updateGlobalMapping(*I, 0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
IncrementalExecutor::ExecutionResult
|
|
IncrementalExecutor::runStaticInitializersOnce(const Transaction& T) {
|
|
llvm::Module* m = T.getModule();
|
|
assert(m && "Module must not be null");
|
|
|
|
// Set m_CurrentAtExitModule to the Module, unset to 0 once done.
|
|
struct AtExitModuleSetterRAII {
|
|
llvm::Module*& m_AEM;
|
|
AtExitModuleSetterRAII(llvm::Module* M, llvm::Module*& AEM): m_AEM(AEM)
|
|
{ AEM = M; }
|
|
~AtExitModuleSetterRAII() { m_AEM = 0; }
|
|
} DSOHandleSetter(m, m_CurrentAtExitModule);
|
|
|
|
// We don't care whether something was unresolved before.
|
|
m_unresolvedSymbols.clear();
|
|
|
|
// check if there is any unresolved symbol in the list
|
|
if (diagnoseUnresolvedSymbols("static initializers"))
|
|
return kExeUnresolvedSymbols;
|
|
|
|
llvm::GlobalVariable* GV
|
|
= m->getGlobalVariable("llvm.global_ctors", true);
|
|
// Nothing to do is good, too.
|
|
if (!GV) return kExeSuccess;
|
|
|
|
// Close similarity to
|
|
// m_engine->runStaticConstructorsDestructors(false) aka
|
|
// llvm::ExecutionEngine::runStaticConstructorsDestructors()
|
|
// is intentional; we do an extra pass to check whether the JIT
|
|
// managed to collect all the symbols needed by the niitializers.
|
|
// Should be an array of '{ i32, void ()* }' structs. The first value is
|
|
// the init priority, which we ignore.
|
|
llvm::ConstantArray *InitList
|
|
= llvm::dyn_cast<llvm::ConstantArray>(GV->getInitializer());
|
|
|
|
// We need to delete it here just in case we have recursive inits, otherwise
|
|
// it will call inits multiple times.
|
|
GV->eraseFromParent();
|
|
|
|
if (InitList == 0)
|
|
return kExeSuccess;
|
|
|
|
//SmallVector<Function*, 2> initFuncs;
|
|
|
|
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
|
|
llvm::ConstantStruct *CS
|
|
= llvm::dyn_cast<llvm::ConstantStruct>(InitList->getOperand(i));
|
|
if (CS == 0) continue;
|
|
|
|
llvm::Constant *FP = CS->getOperand(1);
|
|
if (FP->isNullValue())
|
|
continue; // Found a sentinal value, ignore.
|
|
|
|
// Strip off constant expression casts.
|
|
if (llvm::ConstantExpr *CE = llvm::dyn_cast<llvm::ConstantExpr>(FP))
|
|
if (CE->isCast())
|
|
FP = CE->getOperand(0);
|
|
|
|
// Execute the ctor/dtor function!
|
|
if (llvm::Function *F = llvm::dyn_cast<llvm::Function>(FP)) {
|
|
const llvm::StringRef fName = F->getName();
|
|
executeInit(fName);
|
|
/*
|
|
initFuncs.push_back(F);
|
|
if (fName.startswith("_GLOBAL__sub_I_")) {
|
|
BasicBlock& BB = F->getEntryBlock();
|
|
for (BasicBlock::iterator I = BB.begin(), E = BB.end(); I != E; ++I)
|
|
if (CallInst* call = dyn_cast<CallInst>(I))
|
|
initFuncs.push_back(call->getCalledFunction());
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
/*
|
|
for (SmallVector<Function*,2>::iterator I = initFuncs.begin(),
|
|
E = initFuncs.end(); I != E; ++I) {
|
|
// Cleanup also the dangling init functions. They are in the form:
|
|
// define internal void @_GLOBAL__I_aN() section "..."{
|
|
// entry:
|
|
// call void @__cxx_global_var_init(N-1)()
|
|
// call void @__cxx_global_var_initM()
|
|
// ret void
|
|
// }
|
|
//
|
|
// define internal void @__cxx_global_var_init(N-1)() section "..." {
|
|
// entry:
|
|
// call void @_ZN7MyClassC1Ev(%struct.MyClass* @n)
|
|
// ret void
|
|
// }
|
|
|
|
// Erase __cxx_global_var_init(N-1)() first.
|
|
(*I)->removeDeadConstantUsers();
|
|
(*I)->eraseFromParent();
|
|
}
|
|
*/
|
|
|
|
return kExeSuccess;
|
|
}
|
|
|
|
void IncrementalExecutor::runAndRemoveStaticDestructors(Transaction* T) {
|
|
assert(T && "Must be set");
|
|
// Collect all the dtors bound to this transaction.
|
|
AtExitFunctions boundToT;
|
|
|
|
{
|
|
cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock);
|
|
for (AtExitFunctions::iterator I = m_AtExitFuncs.begin();
|
|
I != m_AtExitFuncs.end();)
|
|
if (I->m_FromM == T->getModule()) {
|
|
boundToT.push_back(*I);
|
|
I = m_AtExitFuncs.erase(I);
|
|
}
|
|
else
|
|
++I;
|
|
} // end of spin lock lifetime block.
|
|
|
|
// 'Unload' the cxa_atexit entities.
|
|
for (AtExitFunctions::reverse_iterator I = boundToT.rbegin(),
|
|
E = boundToT.rend(); I != E; ++I) {
|
|
const CXAAtExitElement& AEE = *I;
|
|
(*AEE.m_Func)(AEE.m_Arg);
|
|
}
|
|
}
|
|
|
|
void
|
|
IncrementalExecutor::installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp)
|
|
{
|
|
m_lazyFuncCreator.push_back(fp);
|
|
}
|
|
|
|
bool
|
|
IncrementalExecutor::addSymbol(const char* symbolName, void* symbolAddress) {
|
|
return IncrementalJIT::searchLibraries(symbolName, symbolAddress).second;
|
|
}
|
|
|
|
void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName,
|
|
bool* fromJIT /*=0*/) {
|
|
// Return a symbol's address, and whether it was jitted.
|
|
void* address = IncrementalJIT::searchLibraries(symbolName).first;
|
|
|
|
// It's not from the JIT if it's in a dylib.
|
|
if (fromJIT)
|
|
*fromJIT = !address;
|
|
|
|
if (!address)
|
|
return (void*)m_JIT->getSymbolAddress(symbolName, false /*no dlsym*/);
|
|
|
|
return address;
|
|
}
|
|
|
|
void*
|
|
IncrementalExecutor::getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) {
|
|
// Get the function / variable pointer referenced by GV.
|
|
|
|
// We don't care whether something was unresolved before.
|
|
m_unresolvedSymbols.clear();
|
|
|
|
void* addr = (void*)m_JIT->getSymbolAddress(GV.getName(),
|
|
false /*no dlsym*/);
|
|
|
|
if (diagnoseUnresolvedSymbols(GV.getName(), "symbol"))
|
|
return 0;
|
|
return addr;
|
|
}
|
|
|
|
bool IncrementalExecutor::diagnoseUnresolvedSymbols(llvm::StringRef trigger,
|
|
llvm::StringRef title) {
|
|
if (m_unresolvedSymbols.empty())
|
|
return false;
|
|
|
|
llvm::SmallVector<llvm::Function*, 128> funcsToFree;
|
|
for (std::set<std::string>::const_iterator i = m_unresolvedSymbols.begin(),
|
|
e = m_unresolvedSymbols.end(); i != e; ++i) {
|
|
#if 0
|
|
// FIXME: This causes a lot of test failures, for some reason it causes
|
|
// the call to HandleMissingFunction to be elided.
|
|
unsigned diagID = m_Diags.getCustomDiagID(clang::DiagnosticsEngine::Error,
|
|
"%0 unresolved while jitting %1");
|
|
(void)diagID;
|
|
//m_Diags.Report(diagID) << *i << funcname; // TODO: demangle the names.
|
|
#endif
|
|
|
|
llvm::errs() << "IncrementalExecutor::executeFunction: symbol '" << *i
|
|
<< "' unresolved while linking ";
|
|
if (trigger.find(utils::Synthesize::UniquePrefix) != llvm::StringRef::npos)
|
|
llvm::errs() << "[cling interface function]";
|
|
else {
|
|
if (!title.empty())
|
|
llvm::errs() << title << " '";
|
|
llvm::errs() << trigger;
|
|
if (!title.empty())
|
|
llvm::errs() << "'";
|
|
}
|
|
llvm::errs() << "!\n";
|
|
|
|
// Be helpful, demangle!
|
|
std::string demangledName;
|
|
{
|
|
#ifndef LLVM_ON_WIN32
|
|
int status = 0;
|
|
char *demang = abi::__cxa_demangle(i->c_str(), 0, 0, &status);
|
|
if (status == 0)
|
|
demangledName = demang;
|
|
free(demang);
|
|
#else
|
|
if (char* demang = __unDName(0, i->c_str(), 0, malloc, free, 0)) {
|
|
demangledName = demang;
|
|
free(demang);
|
|
}
|
|
#endif
|
|
}
|
|
if (!demangledName.empty()) {
|
|
llvm::errs()
|
|
<< "You are probably missing the definition of "
|
|
<< demangledName << "\n"
|
|
<< "Maybe you need to load the corresponding shared library?\n";
|
|
}
|
|
|
|
//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);
|
|
}
|
|
//freeCallersOfUnresolvedSymbols(funcsToFree, m_engine.get());
|
|
m_unresolvedSymbols.clear();
|
|
return true;
|
|
}
|
|
|
|
}// end namespace cling
|