Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 35 additions & 33 deletions core/metacling/src/TCling.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ clang/LLVM technology.
#include "clang/Serialization/GlobalModuleIndex.h"

#include "cling/Interpreter/ClangInternalState.h"
#include "cling/Interpreter/DynamicLibraryManager.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/LookupHelper.h"
#include "cling/Interpreter/Value.h"
Expand All @@ -115,6 +114,9 @@ clang/LLVM technology.
#include "cling/Utils/SourceNormalization.h"
#include "cling/Interpreter/Exception.h"

#include "llvm/ExecutionEngine/Orc/AutoLoadEPC.h"
#include "llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibLookup.h"

#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Module.h"

Expand Down Expand Up @@ -1600,17 +1602,17 @@ TCling::TCling(const char *name, const char *title, const char* const argv[], vo
fInterpreter->setCallbacks(std::move(clingCallbacks));

if (!fromRootCling) {
cling::DynamicLibraryManager& DLM = *fInterpreter->getDynamicLibraryManager();
llvm::orc::AutoLoadEPC& EPC = *fInterpreter->getClingEPC();
// Make sure cling looks into ROOT's libdir, even if not part of LD_LIBRARY_PATH
// e.g. because of an RPATH build.
DLM.addSearchPath(TROOT::GetSharedLibDir().Data(), /*isUser=*/true,
/*prepend=*/true);
EPC.getDylibLookup().addSearchPath(TROOT::GetSharedLibDir().Data(), /*isUser=*/true,
/*prepend=*/true);
auto ShouldPermanentlyIgnore = [](llvm::StringRef FileName) -> bool{
llvm::StringRef stem = llvm::sys::path::stem(FileName);
return stem.startswith("libNew") || stem.startswith("libcppyy_backend");
};
// Initialize the dyld for AutoloadLibraryGenerator.
DLM.initializeDyld(ShouldPermanentlyIgnore);
EPC.getDylibLookup().initializeDynamicLoader(ShouldPermanentlyIgnore);
}
}

Expand Down Expand Up @@ -2087,7 +2089,7 @@ void TCling::RegisterModule(const char* modulename,
if (payloadCode)
code += payloadCode;

std::string dyLibName = cling::DynamicLibraryManager::getSymbolLocation(triggerFunc);
std::string dyLibName = llvm::orc::AutoLoadDynamicLibraryLookup::getSymbolLocation(triggerFunc);
assert(!llvm::sys::fs::is_symlink_file(dyLibName));

if (dyLibName.empty()) {
Expand All @@ -2096,7 +2098,7 @@ void TCling::RegisterModule(const char* modulename,
}

// The triggerFunc may not be in a shared object but in an executable.
bool isSharedLib = cling::DynamicLibraryManager::isSharedLibrary(dyLibName);
bool isSharedLib = llvm::orc::AutoLoadDynamicLibraryLookup::isSharedLibrary(dyLibName);

bool wasDlopened = false;

Expand Down Expand Up @@ -2551,7 +2553,7 @@ Longptr_t TCling::ProcessLine(const char* line, EErrorCode* error/*=0*/)
indent = HandleInterpreterException(GetMetaProcessorImpl(), mod_line, compRes, &result);
}
}
} else if (cling::DynamicLibraryManager::isSharedLibrary(fname.Data()) &&
} else if (llvm::orc::AutoLoadDynamicLibraryLookup::isSharedLibrary(fname.Data()) &&
strncmp(sLine.Data(), ".L", 2) != 0) { // .x *.so or *.dll
if (gSystem->Load(fname) < 0) {
// Loading failed.
Expand Down Expand Up @@ -3144,7 +3146,7 @@ static Bool_t s_IsLibraryLoaded(const char* libname, cling::Interpreter* fInterp
// Check shared library.
TString tLibName(libname);
if (gSystem->FindDynamicLibrary(tLibName, kTRUE))
return fInterpreter->getDynamicLibraryManager()->isLibraryLoaded(tLibName.Data());
return fInterpreter->getClingEPC()->IsDylibLoaded(tLibName.Data());
return false;
}

Expand Down Expand Up @@ -3187,7 +3189,7 @@ Bool_t TCling::IsLoaded(const char* filename) const
R__LOCKGUARD(gInterpreterMutex);

//FIXME: if we use llvm::sys::fs::make_absolute all this can go away. See
// cling::DynamicLibraryManager.
// llvm::orc::AutoLoadDynamicLibraryLookup.

std::string file_name = filename;
size_t at = std::string::npos;
Expand Down Expand Up @@ -3338,7 +3340,7 @@ static int callback_for_dl_iterate_phdr(struct dl_phdr_info *info, size_t size,
//has no path
&& strncmp(info->dlpi_name, "[vdso]", 6)
//the linker does not like to be mmapped
//causes a crash in cling::DynamicLibraryManager::loadLibrary())
//causes a crash in llvm::orc::AutoLoadDynamicLibraryLookup::loadLibrary())
//with error message "mmap of entire address space failed: Cannot allocate memory"
&& strncmp(info->dlpi_name, "/libexec/ld-elf.so.1", 20)
#endif
Expand Down Expand Up @@ -3432,9 +3434,9 @@ void TCling::RegisterLoadedSharedLibrary(const char* filename)

// Tell the interpreter that this library is available; all libraries can be
// used to resolve symbols.
cling::DynamicLibraryManager* DLM = fInterpreter->getDynamicLibraryManager();
if (!DLM->isLibraryLoaded(filename)) {
DLM->loadLibrary(filename, true /*permanent*/, true /*resolved*/);
llvm::orc::AutoLoadEPC* EPC = fInterpreter->getClingEPC();
if (!EPC->IsDylibLoaded(filename)) {
EPC->loadDylib(filename, true /*permanent*/, true /*resolved*/);
}

#if defined(R__MACOSX)
Expand Down Expand Up @@ -3531,29 +3533,28 @@ Int_t TCling::Load(const char* filename, Bool_t system)

// Used to return 0 on success, 1 on duplicate, -1 on failure, -2 on "fatal".
R__LOCKGUARD_CLING(gInterpreterMutex);
cling::DynamicLibraryManager* DLM = fInterpreter->getDynamicLibraryManager();
std::string canonLib = DLM->lookupLibrary(filename);
cling::DynamicLibraryManager::LoadLibResult res
= cling::DynamicLibraryManager::kLoadLibNotFound;
llvm::orc::AutoLoadEPC *EPC = fInterpreter->getClingEPC();
std::string canonLib = EPC->lookupDylib(filename);
llvm::orc::AutoLoadEPC::LoadLibResult res = llvm::orc::AutoLoadEPC::kLoadLibNotFound;
if (!canonLib.empty()) {
if (system)
res = DLM->loadLibrary(filename, system, true);
res = EPC->loadDylib(filename, system, true);
else {
// For the non system libs, we'd like to be able to unload them.
// FIXME: Here we lose the information about kLoadLibAlreadyLoaded case.
cling::Interpreter::CompilationResult compRes;
HandleInterpreterException(GetMetaProcessorImpl(), Form(".L %s", canonLib.c_str()), compRes, /*cling::Value*/nullptr);
if (compRes == cling::Interpreter::kSuccess)
res = cling::DynamicLibraryManager::kLoadLibSuccess;
res = llvm::orc::AutoLoadEPC::kLoadLibSuccess;
}
}

if (res == cling::DynamicLibraryManager::kLoadLibSuccess) {
if (res == llvm::orc::AutoLoadEPC::kLoadLibSuccess) {
UpdateListOfLoadedSharedLibraries();
}
switch (res) {
case cling::DynamicLibraryManager::kLoadLibSuccess: return 0;
case cling::DynamicLibraryManager::kLoadLibAlreadyLoaded: return 1;
case llvm::orc::AutoLoadEPC::kLoadLibSuccess: return 0;
case llvm::orc::AutoLoadEPC::kLoadLibAlreadyLoaded: return 1;
default: break;
};
return -1;
Expand Down Expand Up @@ -6585,10 +6586,10 @@ bool TCling::LibraryLoadingFailed(const std::string& errmessage, const std::stri
// This branch is taken when the callback was from DynamicLibraryManager::loadLibrary
std::string mangled_name = std::string(errMsg.split("undefined symbol: ").second);
void* res = ((TCling*)gCling)->LazyFunctionCreatorAutoload(mangled_name);
cling::DynamicLibraryManager* DLM = fInterpreter->getDynamicLibraryManager();
if (res && DLM && (DLM->loadLibrary(libStem, permanent, resolved) == cling::DynamicLibraryManager::kLoadLibSuccess))
// Return success when LazyFunctionCreatorAutoload could find mangled_name
return true;
llvm::orc::AutoLoadEPC *EPC = fInterpreter->getClingEPC();
if (res && EPC && (EPC->loadDylib(libStem, permanent, resolved) == llvm::orc::AutoLoadEPC::kLoadLibSuccess))
// Return success when LazyFunctionCreatorAutoload could find mangled_name
return true;
} else {
// The callback is from IncrementalExecutor::diagnoseUnresolvedSymbols
if ( ((TCling*)gCling)->LazyFunctionCreatorAutoload(errmessage))
Expand All @@ -6608,7 +6609,7 @@ void* TCling::LazyFunctionCreatorAutoload(const std::string& mangled_name) {
if (void* Addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(dlsym_mangled_name))
return Addr;

const cling::DynamicLibraryManager &DLM = *GetInterpreterImpl()->getDynamicLibraryManager();
const llvm::orc::AutoLoadEPC &EPC = *GetInterpreterImpl()->getClingEPC();
R__LOCKGUARD(gInterpreterMutex);

auto LibLoader = [](const std::string& LibName) -> bool {
Expand All @@ -6620,8 +6621,8 @@ void* TCling::LazyFunctionCreatorAutoload(const std::string& mangled_name) {
return true; //success.
};

std::string libName = DLM.searchLibrariesForSymbol(mangled_name,
/*searchSystem=*/ true);
std::string libName = EPC.getDylibLookup().searchLibrariesForSymbol(mangled_name,
/*searchSystem=*/true);

assert(!llvm::StringRef(libName).startswith("libNew") &&
"We must not resolve symbols from libNew!");
Expand Down Expand Up @@ -7244,7 +7245,8 @@ static std::string GetSharedLibImmediateDepsSlow(std::string lib,
}

R__LOCKGUARD(gInterpreterMutex);
std::string found = interp->getDynamicLibraryManager()->searchLibrariesForSymbol(SymName, /*searchSystem*/false);
std::string found =
interp->getClingEPC()->getDylibLookup().searchLibrariesForSymbol(SymName, /*searchSystem*/ false);
// The expected output is just filename without the full path, which
// is not very accurate, because our Dyld implementation might find
// a match in location a/b/c.so and if we return just c.so ROOT might
Expand Down Expand Up @@ -7662,8 +7664,8 @@ int TCling::UnloadFile(const char* path) const
{
// Modifying the interpreter state needs locking.
R__LOCKGUARD(gInterpreterMutex);
cling::DynamicLibraryManager* DLM = fInterpreter->getDynamicLibraryManager();
std::string canonical = DLM->lookupLibrary(path);
llvm::orc::AutoLoadEPC *EPC = fInterpreter->getClingEPC();
std::string canonical = EPC->lookupDylib(path);
if (canonical.empty()) {
canonical = path;
}
Expand Down
81 changes: 8 additions & 73 deletions core/metacling/src/TClingCallbacks.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

#include <ROOT/FoundationUtils.hxx>

#include "cling/Interpreter/DynamicLibraryManager.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/Transaction.h"
Expand All @@ -35,7 +34,9 @@
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Basic/DiagnosticSema.h"

#include "llvm/ExecutionEngine/Orc/AutoLoadEPC.h"
#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"

#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
Expand Down Expand Up @@ -84,85 +85,19 @@ extern "C" {
void TCling__UnlockCompilationDuringUserCodeExecution(void *state);
}

class AutoloadLibraryGenerator : public llvm::orc::DefinitionGenerator {
const TClingCallbacks &fCallbacks;
cling::Interpreter *fInterpreter;
public:
AutoloadLibraryGenerator(cling::Interpreter *interp, const TClingCallbacks& cb)
: fCallbacks(cb), fInterpreter(interp) {}

llvm::Error tryToGenerate(llvm::orc::LookupState &LS, llvm::orc::LookupKind K, llvm::orc::JITDylib &JD,
llvm::orc::JITDylibLookupFlags JDLookupFlags,
const llvm::orc::SymbolLookupSet &Symbols) override
{
if (!fCallbacks.IsAutoLoadingEnabled())
return llvm::Error::success();

// If we get here, the symbols have not been found in the current process,
// so no need to check that again. Instead search for the library that
// provides the symbol and create one MaterializationUnit per library to
// actually load it if needed.
std::unordered_map<std::string, llvm::orc::SymbolNameVector> found;

// TODO: Do we need to take gInterpreterMutex?
// R__LOCKGUARD(gInterpreterMutex);

for (auto &&KV : Symbols) {
llvm::orc::SymbolStringPtr name = KV.first;

const cling::DynamicLibraryManager &DLM = *fInterpreter->getDynamicLibraryManager();

std::string libName = DLM.searchLibrariesForSymbol((*name).str(),
/*searchSystem=*/true);

// libNew overrides memory management functions; must never autoload that.
assert(libName.find("/libNew.") == std::string::npos && "We must not autoload libNew!");

// libCling symbols are intentionally hidden from the process, and libCling must not be
// dlopened. Instead, symbols must be resolved by specifically querying the dynlib handle of
// libCling, which by definition is loaded - else we could not call this code. The handle
// is made available as argument to `CreateInterpreter`.
assert(libName.find("/libCling.") == std::string::npos && "Must not autoload libCling!");

if (!libName.empty())
found[libName].push_back(name);
}

llvm::orc::SymbolMap loadedSymbols;
for (const auto &KV : found) {
// Try to load the library which should provide the symbol definition.
// TODO: Should this interface with the DynamicLibraryManager directly?
if (TCling__LoadLibrary(KV.first.c_str()) < 0) {
ROOT::TMetaUtils::Error("AutoloadLibraryMU", "Failed to load library %s", KV.first.c_str());
}

for (const auto &symbol : KV.second) {
std::string symbolStr = (*symbol).str();
std::string nameForDlsym = ROOT::TMetaUtils::DemangleNameForDlsym(symbolStr);

void *addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(nameForDlsym);
if (addr) {
loadedSymbols[symbol] = {llvm::orc::ExecutorAddr::fromPtr(addr), llvm::JITSymbolFlags::Exported};
}
}
}

if (!loadedSymbols.empty()) {
return JD.define(absoluteSymbols(std::move(loadedSymbols)));
}

return llvm::Error::success();
}
};

TClingCallbacks::TClingCallbacks(cling::Interpreter *interp, bool hasCodeGen) : InterpreterCallbacks(interp)
{
if (hasCodeGen) {
Transaction* T = nullptr;
m_Interpreter->declare("namespace __ROOT_SpecialObjects{}", &T);
fROOTSpecialNamespace = dyn_cast<NamespaceDecl>(T->getFirstDecl().getSingleDecl());

interp->addGenerator(std::make_unique<AutoloadLibraryGenerator>(interp, *this));
auto F = [&] () -> bool { return this->IsAutoLoadingEnabled(); };
if (auto DSG =
llvm::orc::AutoLoadDynamicLibrarySearchGenerator::GetForTargetProcess(
interp->getClingEPC()->getExecutionSession(), std::move(F)))
interp->addGenerator(std::move(*DSG));
// interp->addGenerator(std::make_unique<AutoloadLibraryGenerator>(interp, *this));
}
}

Expand Down
Loading