diff --git a/interpreter/cling/include/cling/Interpreter/Interpreter.h b/interpreter/cling/include/cling/Interpreter/Interpreter.h index fb1f76a53ce3dabfe277ac592f821624755ce12f..79a3fae954d58e6bd8b945e5cad479927a7d203d 100644 --- a/interpreter/cling/include/cling/Interpreter/Interpreter.h +++ b/interpreter/cling/include/cling/Interpreter/Interpreter.h @@ -274,17 +274,16 @@ namespace cling { llvm::StringRef code, bool withAccessControl); - ///\brief Include C++ runtime headers and definitions. + ///\brief Initialize runtime and C/C++ level overrides /// - void IncludeCXXRuntime(); - - ///\brief Include C runtime headers and definitions. + ///\param[in] NoRuntime - Don't include the runtime headers / gCling + ///\param[in] SyntaxOnly - In SyntaxOnly mode + ///\param[out] Globals - Global symbols that need to be emitted /// - void IncludeCRuntime(); - - ///\brief Init atexit runtime delegation. + ///\returns The resulting Transation of initialization. /// - void InitAExit(); + Transaction* Initialize(bool NoRuntime, bool SyntaxOnly, + llvm::SmallVectorImpl<llvm::StringRef>& Globals); ///\brief The target constructor to be called from both the delegating /// constructors. parentInterp might be nullptr. diff --git a/interpreter/cling/lib/Interpreter/IncrementalExecutor.cpp b/interpreter/cling/lib/Interpreter/IncrementalExecutor.cpp index da1e59221a9741c9e459be3b3177ad27b47ca50b..71f3dde1cc12219917a205f492c5977b3f1156b2 100644 --- a/interpreter/cling/lib/Interpreter/IncrementalExecutor.cpp +++ b/interpreter/cling/lib/Interpreter/IncrementalExecutor.cpp @@ -38,8 +38,7 @@ namespace cling { IncrementalExecutor::IncrementalExecutor(clang::DiagnosticsEngine& diags, const clang::CompilerInstance& CI): - m_externalIncrementalExecutor(nullptr), - m_CurrentAtExitModule(0) + m_externalIncrementalExecutor(nullptr) #if 0 : m_Diags(diags) #endif @@ -123,10 +122,11 @@ void IncrementalExecutor::shuttingDown() { } } -void IncrementalExecutor::AddAtExitFunc(void (*func) (void*), void* arg) { +void IncrementalExecutor::AddAtExitFunc(void (*func) (void*), void* arg, + llvm::Module* M) { // Register a CXAAtExit function cling::internal::SpinLockGuard slg(m_AtExitFuncsSpinLock); - m_AtExitFuncs.push_back(CXAAtExitElement(func, arg, m_CurrentAtExitModule)); + m_AtExitFuncs.push_back(CXAAtExitElement(func, arg, M)); } void unresolvedSymbol() @@ -206,14 +206,6 @@ 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(); @@ -333,14 +325,15 @@ IncrementalExecutor::installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp) } bool -IncrementalExecutor::addSymbol(const char* symbolName, void* symbolAddress) { - return IncrementalJIT::searchLibraries(symbolName, symbolAddress).second; +IncrementalExecutor::addSymbol(const char* Name, void* Addr, + bool Jit) { + return m_JIT->lookupSymbol(Name, Addr, Jit).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; + void* address = m_JIT->lookupSymbol(symbolName).first; // It's not from the JIT if it's in a dylib. if (fromJIT) diff --git a/interpreter/cling/lib/Interpreter/IncrementalExecutor.h b/interpreter/cling/lib/Interpreter/IncrementalExecutor.h index 1e717ff6b34f2abefabed4cad99c2d84899b33a5..25a56dd4ba53cd182e8482ed69dc69fe783b7a4d 100644 --- a/interpreter/cling/lib/Interpreter/IncrementalExecutor.h +++ b/interpreter/cling/lib/Interpreter/IncrementalExecutor.h @@ -114,10 +114,6 @@ namespace cling { /// AtExitFunctions m_AtExitFuncs; - ///\brief Module for which registration of static destructors currently - /// takes place. - llvm::Module* m_CurrentAtExitModule; - ///\brief Modules to emit upon the next call to the JIT. /// std::vector<llvm::Module*> m_ModulesToJIT; @@ -208,12 +204,13 @@ namespace cling { /// Allows runtime declaration of a function passing its pointer for being /// used by JIT generated code. /// - /// @param[in] symbolName - The name of the symbol as required by the + /// @param[in] Name - The name of the symbol as required by the /// linker (mangled if needed) - /// @param[in] symbolAddress - The function pointer to register + /// @param[in] Address - The function pointer to register + /// @param[in] JIT - Add to the JIT injected symbol table /// @returns true if the symbol is successfully registered, false otherwise. /// - bool addSymbol(const char* symbolName, void* symbolAddress); + bool addSymbol(const char* Name, void* Address, bool JIT = false); ///\brief Add a llvm::Module to the JIT. /// @@ -251,7 +248,7 @@ namespace cling { ///\brief Keep track of the entities whose dtor we need to call. /// - void AddAtExitFunc(void (*func) (void*), void* arg); + void AddAtExitFunc(void (*func) (void*), void* arg, llvm::Module* M); ///\brief Try to resolve a symbol through our LazyFunctionCreators; /// print an error message if that fails. diff --git a/interpreter/cling/lib/Interpreter/IncrementalJIT.cpp b/interpreter/cling/lib/Interpreter/IncrementalJIT.cpp index 686bad20363c698245b675112c643f21dfbc3fbf..961e9922af0832fb644bfb1d50b8772b217b4295 100644 --- a/interpreter/cling/lib/Interpreter/IncrementalJIT.cpp +++ b/interpreter/cling/lib/Interpreter/IncrementalJIT.cpp @@ -25,12 +25,6 @@ using namespace llvm; namespace { -// Forward cxa_atexit for global d'tors. -static int local_cxa_atexit(void (*func) (void*), void* arg, void* dso) { - cling::IncrementalExecutor* exe = (cling::IncrementalExecutor*)dso; - exe->AddAtExitFunc(func, arg); - return 0; -} ///\brief Memory manager providing the lop-level link to the /// IncrementalExecutor, handles missing or special / replaced symbols. @@ -195,17 +189,6 @@ IncrementalJIT::IncrementalJIT(IncrementalExecutor& exe, llvm::orc::JITSymbol IncrementalJIT::getInjectedSymbols(const std::string& Name) const { using JITSymbol = llvm::orc::JITSymbol; - if (Name == MANGLE_PREFIX "__cxa_atexit") { - // Rewire __cxa_atexit to ~Interpreter(), thus also global destruction - // coming from the JIT. - return JITSymbol((uint64_t)&local_cxa_atexit, - llvm::JITSymbolFlags::Exported); - } else if (Name == MANGLE_PREFIX "__dso_handle") { - // Provide IncrementalExecutor as the third argument to __cxa_atexit. - return JITSymbol((uint64_t)&m_Parent, - llvm::JITSymbolFlags::Exported); - } - auto SymMapI = m_SymbolMap.find(Name); if (SymMapI != m_SymbolMap.end()) return JITSymbol(SymMapI->second, llvm::JITSymbolFlags::Exported); @@ -214,7 +197,7 @@ IncrementalJIT::getInjectedSymbols(const std::string& Name) const { } std::pair<void*, bool> -IncrementalJIT::searchLibraries(llvm::StringRef Name, void *InAddr) { +IncrementalJIT::lookupSymbol(llvm::StringRef Name, void *InAddr, bool Jit) { // FIXME: See comments on DLSym below. #if !defined(LLVM_ON_WIN32) void* Addr = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(Name); @@ -222,7 +205,12 @@ IncrementalJIT::searchLibraries(llvm::StringRef Name, void *InAddr) { void* Addr = const_cast<void*>(platform::DLSym(Name)); #endif - if (InAddr && !Addr) { + if (InAddr && (!Addr || Jit)) { + if (Jit) { + std::string Key(Name); + Key.insert(0, MANGLE_PREFIX); + m_SymbolMap[Key] = llvm::orc::TargetAddress(InAddr); + } llvm::sys::DynamicLibrary::AddSymbol(Name, InAddr); return std::make_pair(InAddr, true); } diff --git a/interpreter/cling/lib/Interpreter/IncrementalJIT.h b/interpreter/cling/lib/Interpreter/IncrementalJIT.h index 185d26b9982cc967a7fbdd6ffb3246390efbf4d1..fcb4af150ac423af32785f8625920b12e4726328 100644 --- a/interpreter/cling/lib/Interpreter/IncrementalJIT.h +++ b/interpreter/cling/lib/Interpreter/IncrementalJIT.h @@ -215,9 +215,10 @@ public: ///\brief Get the address of a symbol from the process' loaded libraries. /// \param Name - symbol to look for /// \param Addr - known address of the symbol that can be cached later use + /// \param Jit - add to the injected symbols cache /// \returns The address of the symbol and whether it was cached - static std::pair<void*, bool> - searchLibraries(llvm::StringRef Name, void* Addr = nullptr); + std::pair<void*, bool> + lookupSymbol(llvm::StringRef Name, void* Addr = nullptr, bool Jit = false); }; } // end cling #endif // CLING_INCREMENTAL_EXECUTOR_H diff --git a/interpreter/cling/lib/Interpreter/Interpreter.cpp b/interpreter/cling/lib/Interpreter/Interpreter.cpp index d57e467037df77b46f5186210a53bb0dad0e8cb1..2803b2ada4ef5ac5efae31147cb48d98ac7a94cf 100644 --- a/interpreter/cling/lib/Interpreter/Interpreter.cpp +++ b/interpreter/cling/lib/Interpreter/Interpreter.cpp @@ -57,6 +57,13 @@ using namespace clang; namespace { + // Forward cxa_atexit for global d'tors. + static int local_cxa_atexit(void (*func) (void*), void* arg, + cling::Interpreter* Interp) { + Interp->AddAtExitFunc(func, arg); + return 0; + } + static cling::Interpreter::ExecutionResult ConvertExecutionResult(cling::IncrementalExecutor::ExecutionResult ExeRes) { switch (ExeRes) { @@ -188,16 +195,30 @@ namespace cling { handleFrontendOptions(); - if (!noRuntime) { - if (getCI()->getLangOpts().CPlusPlus) - IncludeCXXRuntime(); - else - IncludeCRuntime(); - } + llvm::SmallVector<llvm::StringRef, 6> Syms; + Initialize(noRuntime, isInSyntaxOnlyMode(), Syms); + // Commit the transactions, now that gCling is set up. It is needed for // static initialization in these transactions through local_cxa_atexit(). for (auto&& I: IncrParserTransactions) m_IncrParser->commitTransaction(I); + + // Now that the transactions have been commited, force symbol emission + // and overrides. + if (const Transaction* T = getLastTransaction()) { + if (llvm::Module* M = T->getModule()) { + for (const llvm::StringRef& Sym : Syms) { + if (const llvm::GlobalValue* GV = M->getNamedValue(Sym)) { + 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"; + } + } + } + // Disable suggestions for ROOT bool showSuggestions = !llvm::StringRef(ClingStringify(CLING_VERSION)).startswith("ROOT"); @@ -216,8 +237,6 @@ namespace cling { // Prevents stripping the symbol due to dead-code optimization. internal::symbol_requester(); } - - InitAExit(); } ///\brief Constructor for the child Interpreter. @@ -278,63 +297,93 @@ namespace cling { } } - void Interpreter::InitAExit() { - if (isInSyntaxOnlyMode()) - return; - - const char* Linkage = getCI()->getLangOpts().CPlusPlus ? "extern \"C\"" : ""; - llvm::SmallString<512> Buf; + Transaction* Interpreter::Initialize(bool NoRuntime, bool SyntaxOnly, + llvm::SmallVectorImpl<llvm::StringRef>& Globals) { + llvm::SmallString<1024> Buf; llvm::raw_svector_ostream Strm(Buf); - Strm << Linkage << " int __cxa_atexit(void (*f) (void*), void*, void*);\n" - << Linkage << " int atexit(void(*f)()) {" - "return __cxa_atexit((void(*)(void*))f, nullptr, (void*)" - << m_Executor.get() << "); }\n"; - Transaction *T = nullptr; - declare(Strm.str(), &T); - if (llvm::Module* M = T ? T->getModule() : nullptr) { - if (const llvm::GlobalValue* GV = M->getNamedValue("atexit")) - m_Executor->getPointerToGlobalFromJIT(*GV); + const clang::LangOptions& LangOpts = getCI()->getLangOpts(); + const void* thisP = static_cast<void*>(this); + + // FIXME: gCling should be const so assignemnt is a compile time error. + // Currently the name mangling is coming up wrong for the const version + // (on OS X at least, so probably Linux too) and the JIT thinks the symbol + // is undefined in a child Interpreter. And speaking of children, should + // gCling actually be thisCling, so a child Interpreter can only access + // itself? One could use a macro (simillar to __dso_handle) to block + // assignemnt and get around the mangling issue. + const char* Linkage = LangOpts.CPlusPlus ? "extern \"C\"" : ""; + if (!NoRuntime && !SyntaxOnly) { + if (LangOpts.CPlusPlus) { + Strm << "#include \"cling/Interpreter/RuntimeUniverse.h\"\n" + "namespace cling { class Interpreter; namespace runtime { " + "Interpreter* gCling=(Interpreter*)" << thisP << "; }}\n"; + } else { + Strm << "#include \"cling/Interpreter/CValuePrinter.h\"\n" + "void* gCling=(void*)" << thisP << ";\n"; + } } - } - void Interpreter::IncludeCXXRuntime() { - // Set up common declarations which are going to be available - // only at runtime - // Make sure that the universe won't be included to compile time by using - // -D __CLING__ as CompilerInstance's arguments + // Intercept all atexit calls, as the Interpreter and functions will be long + // gone when the -native- versions invoke them. + if (!SyntaxOnly) { + // While __dso_handle is still overriden in the JIT below, + // #define __dso_handle is used to mitigate the following problems: + // 1. Type of __dso_handle is void* making assignemnt to it legal + // 2. Making it void* const in cling would mean possible type mismatch + // 3. Cannot override void* __dso_handle in child Interpreter + // 4. On Unix where the symbol actually exists, __dso_handle will be + // linked into the code before the JIT can say otherwise, so: + // [cling] __dso_handle // codegened __dso_handle always printed + // [cling] __cxa_atexit(f, 0, __dso_handle) // seg-fault + // 5. Code that actually uses __dso_handle will fail as a declaration is + // needed which is not possible with the macro. + // 6. Assuming 4 is sorted out in user code, calling __cxa_atexit through + // atexit below isn't linking to the __dso_handle symbol. + + Strm << "#define __dso_handle ((void*)" << thisP << ")\n"; + + // Use __cxa_atexit to intercept all of the following routines + Strm << Linkage << " int __cxa_atexit(void (*f)(void*), void*, void*);\n"; + + // C atexit, std::atexit + Strm << Linkage << " int atexit(void(*f)()) { " + "return __cxa_atexit((void(*)(void*))f, nullptr, __dso_handle); }\n"; + Globals.push_back("atexit"); + + // C++ 11 at_quick_exit, std::at_quick_exit + if (LangOpts.CPlusPlus && LangOpts.CPlusPlus11) { + Strm << Linkage << " int at_quick_exit(void(*f)()) { " + "return __cxa_atexit((void(*)(void*))f, nullptr, __dso_handle); }\n"; + Globals.push_back("at_quick_exit"); + } - std::stringstream initializer; -#ifdef _WIN32 - // We have to use the #defined __CLING__ on windows first. - //FIXME: Find proper fix. - initializer << "#ifdef __CLING__ \n#endif\n"; +#if defined(LLVM_ON_WIN32) + // Windows specific: _onexit, _onexit_m, __dllonexit + Strm << Linkage << " _onexit_t _onexit(_onexit_t f) { " + "__cxa_atexit((void(*)(void*))f, nullptr, __dso_handle); return f;}\n"; + Globals.push_back("_onexit"); + Strm << Linkage << " _onexit_t __dllonexit(_onexit_t f, PVFV**, PVFV**) { " + "__cxa_atexit((void(*)(void*))f, nullptr, __dso_handle); return f;}\n"; + Globals.push_back("__dllonexit"); + #ifdef _M_CEE + Strm << Linkage << " _onexit_t_m _onexit_m(_onexit_t f) { " + "__cxa_atexit((void(*)(void*))f, nullptr, __dso_handle); return f;}\n"; + Globals.push_back("_onexit_m"); + #endif #endif - initializer << "#include \"cling/Interpreter/RuntimeUniverse.h\"\n"; - - if (!isInSyntaxOnlyMode()) { - // Set up the gCling variable if it can be used - initializer << "namespace cling {namespace runtime { " - "cling::Interpreter *gCling=(cling::Interpreter*)" - << "0x" << std::hex << (uintptr_t)this << " ;} }"; + // Override the native symbols now, before anything can be emitted. + m_Executor->addSymbol("__cxa_atexit", (void*)&local_cxa_atexit, true); + // __dso_handle is inserted for the link phase, as macro is useless then + m_Executor->addSymbol("__dso_handle", this, true); } - declare(initializer.str()); - } - void Interpreter::IncludeCRuntime() { - // Set up the gCling variable if it can be used - std::stringstream initializer; - initializer << "void* gCling=(void*)" << (uintptr_t)this << ';'; - declare(initializer.str()); - // declare("void setValueNoAlloc(void* vpI, void* vpSVR, void* vpQT);"); - // declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, float value);"); - // declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, double value);"); - // declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, long double value);"); - // declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, unsigned long long value);"); - // declare("void setValueNoAlloc(void* vpI, void* vpV, void* vpQT, const void* value);"); - // declare("void* setValueWithAlloc(void* vpI, void* vpV, void* vpQT);"); + if (m_Opts.Verbose()) + llvm::errs() << Strm.str(); - declare("#include \"cling/Interpreter/CValuePrinter.h\""); + Transaction *T; + declare(Strm.str(), &T); + return T; } void Interpreter::AddIncludePaths(llvm::StringRef PathStr, const char* Delm) { @@ -1248,7 +1297,15 @@ namespace cling { } void Interpreter::AddAtExitFunc(void (*Func) (void*), void* Arg) { - m_Executor->AddAtExitFunc(Func, Arg); + const Transaction* T = getCurrentTransaction(); + // Should this be ROOT only? + if (!T) { + // IncrementalParser::commitTransaction will call + // Interpreter::executeTransaction if transaction has no parent. + T = getLastTransaction(); + } + assert(T && "No Transaction for Interpreter::AddAtExitFunc"); + m_Executor->AddAtExitFunc(Func, Arg, T->getModule()); } void Interpreter::GenerateAutoloadingMap(llvm::StringRef inFile,