diff --git a/include/cling/Interpreter/Transaction.h b/include/cling/Interpreter/Transaction.h index 3444b82c..a55616ef 100644 --- a/include/cling/Interpreter/Transaction.h +++ b/include/cling/Interpreter/Transaction.h @@ -139,9 +139,6 @@ namespace cling { unsigned m_IssuedDiags : 2; - /// If we still own the llvm::Module (m_Module) or it was taken by the EE. - unsigned m_OwnedLLVMModule : 1; - ///\brief Options controlling the transformers and code generator. /// CompilationOptions m_Opts; @@ -153,7 +150,7 @@ namespace cling { ///\brief The llvm Module containing the information that we will revert /// - llvm::Module* m_Module; + std::unique_ptr m_Module; ///\brief The Executor to use m_ExeUnload on. /// @@ -469,20 +466,12 @@ namespace cling { m_NestedTransactions->clear(); } - llvm::Module* getModule() const { return m_Module; } - std::unique_ptr takeModule() { - assert(m_Module && "No module"); - assert(m_OwnedLLVMModule && "No ownership to take"); - m_OwnedLLVMModule = false; - return std::unique_ptr(m_Module); - } - void setModule(std::unique_ptr M) { - if (m_Module && m_OwnedLLVMModule) { - delete m_Module; - } - m_Module = M.release(); - m_OwnedLLVMModule = true; + llvm::Module* getModule() const { return m_Module.get(); } + std::unique_ptr takeModule () { + assert(getModule()); + return std::move(m_Module); } + void setModule(std::unique_ptr M) { m_Module = std::move(M); } IncrementalExecutor* getExecutor() const { return m_Exe; } diff --git a/lib/Interpreter/IncrementalExecutor.cpp b/lib/Interpreter/IncrementalExecutor.cpp index 2ad9c246..4739e198 100644 --- a/lib/Interpreter/IncrementalExecutor.cpp +++ b/lib/Interpreter/IncrementalExecutor.cpp @@ -102,7 +102,13 @@ IncrementalExecutor::IncrementalExecutor(clang::DiagnosticsEngine& diags, CI.getTargetOpts(), CI.getLangOpts(), *TM)); - m_JIT.reset(new IncrementalJIT(*this, std::move(TM))); + auto RetainOwnership = + [this](llvm::orc::VModuleKey K, std::unique_ptr M) -> void { + assert (m_PendingModules.count(K) && "Unable to find the module"); + m_PendingModules[K]->setModule(std::move(M)); + m_PendingModules.erase(K); + }; + m_JIT.reset(new IncrementalJIT(*this, std::move(TM), RetainOwnership)); } // Keep in source: ~unique_ptr needs ClingJIT @@ -130,10 +136,10 @@ void IncrementalExecutor::runAtExitFuncs() { } void IncrementalExecutor::AddAtExitFunc(void (*func)(void*), void* arg, - const llvm::Module* M) { + const Transaction* T) { // Register a CXAAtExit function cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock); - m_AtExitFuncs[M].emplace_back(func, arg); + m_AtExitFuncs[T].emplace_back(func, arg); } void unresolvedSymbol() @@ -205,11 +211,24 @@ freeCallersOfUnresolvedSymbols(llvm::SmallVectorImpl& } #endif +static bool isPracticallyEmptyModule(const llvm::Module* M) { + return M->empty() && M->global_empty() && M->alias_empty(); +} + + IncrementalExecutor::ExecutionResult -IncrementalExecutor::runStaticInitializersOnce(const Transaction& T) const { +IncrementalExecutor::runStaticInitializersOnce(Transaction& T) { llvm::Module* m = T.getModule(); assert(m && "Module must not be null"); + if (isPracticallyEmptyModule(m)) + return kExeSuccess; + + llvm::orc::VModuleKey K = + emitModule(T.takeModule(), T.getCompilationOpts().OptLevel); + m_PendingModules[K] = &T; + + // We don't care whether something was unresolved before. m_unresolvedSymbols.clear(); @@ -303,7 +322,7 @@ void IncrementalExecutor::runAndRemoveStaticDestructors(Transaction* T) { AtExitFunctions::mapped_type Local; { cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock); - auto Itr = m_AtExitFuncs.find(T->getModule()); + auto Itr = m_AtExitFuncs.find(T); if (Itr == m_AtExitFuncs.end()) return; m_AtExitFuncs.erase(Itr, &Local); } // end of spin lock lifetime block. @@ -369,16 +388,15 @@ void* IncrementalExecutor::getAddressOfGlobal(llvm::StringRef symbolName, } void* -IncrementalExecutor::getPointerToGlobalFromJIT(const llvm::GlobalValue& GV) const { - // Get the function / variable pointer referenced by GV. +IncrementalExecutor::getPointerToGlobalFromJIT(llvm::StringRef name) const { + // Get the function / variable pointer referenced by name. // We don't care whether something was unresolved before. m_unresolvedSymbols.clear(); - void* addr = (void*)m_JIT->getSymbolAddress(GV.getName(), - false /*no dlsym*/); + void* addr = (void*)m_JIT->getSymbolAddress(name, false /*no dlsym*/); - if (diagnoseUnresolvedSymbols(GV.getName(), "symbol")) + if (diagnoseUnresolvedSymbols(name, "symbol")) return 0; return addr; } diff --git a/lib/Interpreter/IncrementalExecutor.h b/lib/Interpreter/IncrementalExecutor.h index 9ddc7981..e2a32def 100644 --- a/lib/Interpreter/IncrementalExecutor.h +++ b/lib/Interpreter/IncrementalExecutor.h @@ -114,12 +114,10 @@ namespace cling { std::atomic_flag m_AtExitFuncsSpinLock; // MSVC doesn't support = ATOMIC_FLAG_INIT; ///\brief Function registered via __cxa_atexit, atexit, or one of - /// it's C++ overloads that should be run when a module is unloaded. + /// it's C++ overloads that should be run when a transaction is unloaded. /// - // FIXME: We should probably try using a weak_ptr instead of a shared_ptr. - typedef utils::OrderedMap> - AtExitFunctions; + using AtExitFunctions = + utils::OrderedMap>; AtExitFunctions m_AtExitFuncs; ///\brief Modules to emit upon the next call to the JIT. @@ -141,7 +139,9 @@ namespace cling { clang::DiagnosticsEngine& m_Diags; #endif - + ///\brief The list of llvm::Module-s to return the transaction + /// after the JIT has emitted them. + std::map m_PendingModules; public: enum ExecutionResult { kExeSuccess, @@ -172,7 +172,7 @@ namespace cling { } ///\brief Run the static initializers of all modules collected to far. - ExecutionResult runStaticInitializersOnce(const Transaction& T) const; + ExecutionResult runStaticInitializersOnce(Transaction& T); ///\brief Runs all destructors bound to the given transaction and removes /// them from the list. @@ -196,18 +196,6 @@ namespace cling { /// bool addSymbol(const char* Name, void* Address, bool JIT = false) const; - ///\brief Emit a llvm::Module to the JIT. - /// - /// @param[in] module - The module to pass to the execution engine. - /// @param[in] optLevel - The optimization level to be used. - void - emitModule(std::unique_ptr module, int optLevel) const { - if (m_BackendPasses) - m_BackendPasses->runOnModule(*module, optLevel); - - m_JIT->addModule(std::move(module)); - } - ///\brief Tells the execution to run all registered atexit functions once. /// /// This rountine should be used with caution only when an external process @@ -227,7 +215,7 @@ namespace cling { /// JIT symbols might not be immediately convertible to e.g. a function /// pointer as their call setup is different. /// - ///\param[in] mangledName - the globa's name + ///\param[in] mangledName - the global's name ///\param[out] fromJIT - whether the symbol was JITted. /// void* @@ -237,18 +225,30 @@ namespace cling { /// 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) const; + ///param[in] name - the mangled name of the global. + void* getPointerToGlobalFromJIT(llvm::StringRef name) const; ///\brief Keep track of the entities whose dtor we need to call. /// - void AddAtExitFunc(void (*func)(void*), void* arg, const llvm::Module* M); + void AddAtExitFunc(void (*func)(void*), void* arg, const Transaction* T); ///\brief Try to resolve a symbol through our LazyFunctionCreators; /// print an error message if that fails. void* NotifyLazyFunctionCreators(const std::string&) const; private: + ///\brief Emit a llvm::Module to the JIT. + /// + /// @param[in] module - The module to pass to the execution engine. + /// @param[in] optLevel - The optimization level to be used. + llvm::orc::VModuleKey + emitModule(std::unique_ptr module, int optLevel) const { + if (m_BackendPasses) + m_BackendPasses->runOnModule(*module, optLevel); + + return m_JIT->addModule(std::move(module)); + } + ///\brief Report and empty m_unresolvedSymbols. ///\return true if m_unresolvedSymbols was non-empty. bool diagnoseUnresolvedSymbols(llvm::StringRef trigger, diff --git a/lib/Interpreter/IncrementalJIT.cpp b/lib/Interpreter/IncrementalJIT.cpp index 944b7de4..390194ce 100644 --- a/lib/Interpreter/IncrementalJIT.cpp +++ b/lib/Interpreter/IncrementalJIT.cpp @@ -272,7 +272,8 @@ public: }; // class Azog IncrementalJIT::IncrementalJIT(IncrementalExecutor& exe, - std::unique_ptr TM): + std::unique_ptr TM, + CompileLayerT::NotifyCompiledCallback NCC): m_Parent(exe), m_TM(std::move(TM)), m_TMDataLayout(m_TM->createDataLayout()), @@ -341,6 +342,9 @@ IncrementalJIT::IncrementalJIT(IncrementalExecutor& exe, m_NotifyObjectLoaded, NotifyFinalizedT(*this)), m_CompileLayer(m_ObjectLayer, llvm::orc::SimpleCompiler(*m_TM)), m_LazyEmitLayer(m_CompileLayer) { + + m_CompileLayer.setNotifyCompiled(NCC); + // Libraries might get exposed through ExposeHiddenSharedLibrarySymbols(), // make them available to the JIT, even though their symbols cannot be // resolved through the process. @@ -443,7 +447,8 @@ IncrementalJIT::getSymbolAddressWithoutMangling(const std::string& Name, return llvm::JITSymbol(nullptr); } -void IncrementalJIT::addModule(std::unique_ptr module) { +llvm::orc::VModuleKey +IncrementalJIT::addModule(std::unique_ptr module) { // If this module doesn't have a DataLayout attached then attach the // default. module->setDataLayout(m_TMDataLayout); @@ -466,6 +471,7 @@ void IncrementalJIT::addModule(std::unique_ptr module) { llvm::orc::VModuleKey K = m_ES.allocateVModule(); llvm::cantFail(m_LazyEmitLayer.addModule(K, std::move(module))); m_UnloadPoints[module.get()] = K; + return K; } llvm::Error diff --git a/lib/Interpreter/IncrementalJIT.h b/lib/Interpreter/IncrementalJIT.h index 4ba3b738..2cbe6e46 100644 --- a/lib/Interpreter/IncrementalJIT.h +++ b/lib/Interpreter/IncrementalJIT.h @@ -175,7 +175,8 @@ private: public: IncrementalJIT(IncrementalExecutor& exe, - std::unique_ptr TM); + std::unique_ptr TM, + CompileLayerT::NotifyCompiledCallback NCF); ///\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 @@ -203,7 +204,7 @@ public: llvm::JITSymbol getSymbolAddressWithoutMangling(const std::string& Name, bool AlsoInProcess); - void addModule(std::unique_ptr module); + llvm::orc::VModuleKey addModule(std::unique_ptr module); llvm::Error removeModule(const llvm::Module* module); IncrementalExecutor& getParent() const { return m_Parent; } diff --git a/lib/Interpreter/Interpreter.cpp b/lib/Interpreter/Interpreter.cpp index ae03c2d8..d542b8d5 100644 --- a/lib/Interpreter/Interpreter.cpp +++ b/lib/Interpreter/Interpreter.cpp @@ -88,10 +88,6 @@ namespace { } return cling::Interpreter::kExeSuccess; } - - static bool isPracticallyEmptyModule(const llvm::Module* M) { - return M->empty() && M->global_empty() && M->alias_empty(); - } } // unnamed namespace namespace cling { @@ -316,25 +312,13 @@ namespace cling { // Now that the transactions have been commited, force symbol emission // and overrides. if (!isInSyntaxOnlyMode() && !m_Opts.CompilerOpts.CUDADevice) { - if (const Transaction* T = getLastTransaction()) { - if (auto M = T->getModule()) { - for (const llvm::StringRef& Sym : Syms) { - const llvm::GlobalValue* GV = M->getNamedValue(Sym); - #if defined(__linux__) - // libstdc++ mangles at_quick_exit on Linux when g++ < 5 - if (!GV && Sym.equals("at_quick_exit")) - GV = M->getNamedValue("_Z13at_quick_exitPFvvE"); - #endif - if (GV) { - if (void* Addr = m_Executor->getPointerToGlobalFromJIT(*GV)) - m_Executor->addSymbol(Sym.str().c_str(), Addr, true); - else - cling::errs() << Sym << " not defined\n"; - } else - cling::errs() << Sym << " not in Module!\n"; - } - } - } + if (void* Addr = m_Executor->getPointerToGlobalFromJIT("at_quick_exit")) + m_Executor->addSymbol("at_quick_exit", Addr, true); + // libstdc++ mangles at_quick_exit on Linux when g++ < 5 + else if (void* Addr = m_Executor->getPointerToGlobalFromJIT("_Z13at_quick_exitPFvvE")) + m_Executor->addSymbol("_Z13at_quick_exitPFvvE", Addr, true); + else + cling::errs() << "'at_quick_exit' not defined\n"; } m_IncrParser->SetTransformers(parentInterp); @@ -1285,15 +1269,9 @@ namespace cling { const FunctionDecl* FD = DeclareCFunction(name, code, withAccessControl, T); if (!FD || !T) return 0; - // - // Get the wrapper function pointer - // from the ExecutionEngine (the JIT). - // - if (const llvm::GlobalValue* GV - = T->getModule()->getNamedValue(name)) - return m_Executor->getPointerToGlobalFromJIT(*GV); - return 0; + // Get the wrapper function pointer from the ExecutionEngine (the JIT). + return m_Executor->getPointerToGlobalFromJIT(name); } void* @@ -1685,13 +1663,10 @@ namespace cling { IncrementalExecutor::ExecutionResult ExeRes = IncrementalExecutor::kExeSuccess; - if (!isPracticallyEmptyModule(T.getModule())) { - m_Executor->emitModule(T.takeModule(), T.getCompilationOpts().OptLevel); - // Forward to IncrementalExecutor; should not be called by - // anyone except for IncrementalParser. - ExeRes = m_Executor->runStaticInitializersOnce(T); - } + // Forward to IncrementalExecutor; should not be called by + // anyone except for IncrementalParser. + ExeRes = m_Executor->runStaticInitializersOnce(T); return ConvertExecutionResult(ExeRes); } @@ -1736,7 +1711,7 @@ namespace cling { } void Interpreter::AddAtExitFunc(void (*Func) (void*), void* Arg) { - m_Executor->AddAtExitFunc(Func, Arg, getLatestTransaction()->getModule()); + m_Executor->AddAtExitFunc(Func, Arg, getLatestTransaction()); } void Interpreter::runAtExitFuncs() { diff --git a/lib/Interpreter/Transaction.cpp b/lib/Interpreter/Transaction.cpp index 77fa2dcc..2d628816 100644 --- a/lib/Interpreter/Transaction.cpp +++ b/lib/Interpreter/Transaction.cpp @@ -40,7 +40,6 @@ namespace cling { m_Parent = 0; m_State = kCollecting; m_IssuedDiags = kNone; - m_OwnedLLVMModule = false; m_Opts = CompilationOptions(); m_DefinitionShadowNS = 0; m_Module = 0; diff --git a/test/Pragmas/load.C b/test/Pragmas/load.C index ad01a687..99a304c6 100644 --- a/test/Pragmas/load.C +++ b/test/Pragmas/load.C @@ -10,8 +10,8 @@ // RUN: cat %s | %cling -L %T -Xclang -verify 2>&1 | FileCheck %s #pragma cling load("DoesNotExistPleaseRecover") -// expected-error@input_line_13:1{{expected is not a library; did you mean #include "DoesNotExistPleaseRecover"}} -// expected-error@input_line_13:1{{'DoesNotExistPleaseRecover' file not found}} +// expected-error@input_line_12:1{{expected is not a library; did you mean #include "DoesNotExistPleaseRecover"}} +// expected-error@input_line_12:1{{'DoesNotExistPleaseRecover' file not found}} #pragma cling load("libcall_lib") extern "C" int cling_testlibrary_function();