diff --git a/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h b/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h index 7e17db3ab6..e8f0d807ba 100644 --- a/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h +++ b/include/cling/Interpreter/DynamicLookupRuntimeUniverse.h @@ -21,7 +21,7 @@ namespace cling { /// \brief Contains declarations for cling's runtime. namespace runtime { - extern Interpreter* gCling; + extern Interpreter* const gCling; /// \brief Provides builtins, which are neccessary for the dynamic scopes /// and runtime bindings. These builtins should be used for other purposes. diff --git a/include/cling/Interpreter/Interpreter.h b/include/cling/Interpreter/Interpreter.h index 0c23a90519..9e91cda0a3 100644 --- a/include/cling/Interpreter/Interpreter.h +++ b/include/cling/Interpreter/Interpreter.h @@ -142,6 +142,11 @@ namespace cling { /// InvocationOptions m_Opts; + ///\brief Storage to hold parenting information, which is also used as a + /// a fixed address/location passed to the JIT's linker for gCling. + /// + Interpreter** m_Parenting; + ///\brief The llvm library state, a per-thread object. /// std::unique_ptr m_LLVMContext; @@ -332,6 +337,14 @@ namespace cling { /// bool isValid() const; + ///\brief Returns this interpreter's parent or null: while (P = parent()) + /// + Interpreter* parent(); + + ///\brief Returns greatest ancestor of this interpreter. Might be itself. + /// + Interpreter& ancestor(); + const InvocationOptions& getOptions() const { return m_Opts; } InvocationOptions& getOptions() { return m_Opts; } diff --git a/include/cling/Interpreter/RuntimeUniverse.h b/include/cling/Interpreter/RuntimeUniverse.h index c316fff2e7..db8f1abc46 100644 --- a/include/cling/Interpreter/RuntimeUniverse.h +++ b/include/cling/Interpreter/RuntimeUniverse.h @@ -21,7 +21,11 @@ #define __STDC_CONSTANT_MACROS // needed by System/DataTypes.h #endif -#ifdef __cplusplus +#ifndef __cplusplus + +extern const void* const gCling; + +#else #include @@ -36,7 +40,7 @@ namespace cling { /// \brief The interpreter provides itself as a builtin, i.e. it /// interprets itself. This is particularly important for implementing /// the dynamic scopes and the runtime bindings - extern Interpreter* gCling; + extern Interpreter* const gCling; namespace internal { /// \brief Some of clang's routines rely on valid source locations and @@ -177,15 +181,20 @@ namespace cling { using namespace cling::runtime; extern "C" { - ///\brief a function that throws InvalidDerefException. This allows to 'hide' - /// the definition of the exceptions from the RuntimeUniverse and allows us to - /// run cling in -no-rtti mode. - /// - - void* cling_runtime_internal_throwIfInvalidPointer(void* Sema, - void* Expr, - const void* Arg); -} + #endif // __cplusplus +///\brief a function that throws InvalidDerefException. This allows to 'hide' +/// the definition of the exceptions from the RuntimeUniverse and allows us to +/// run cling in -no-rtti mode. +/// + +void* cling_runtime_internal_throwIfInvalidPointer(void* Sema, + void* Expr, + const void* Arg); + +#ifdef __cplusplus +} // extern "C" +#endif + #endif // CLING_RUNTIME_UNIVERSE_H diff --git a/include/cling/Utils/AST.h b/include/cling/Utils/AST.h index 3b4fe50832..78d30ee689 100644 --- a/include/cling/Utils/AST.h +++ b/include/cling/Utils/AST.h @@ -50,14 +50,37 @@ namespace utils { /// bool IsWrapper(const clang::FunctionDecl* ND); + ///\brief Get the mangled name of a NamedDecl. + /// + ///\param [in] ND - Try to mangle this decl's name. + ///\param [in] GD - Provide the GlobalDecl if what is to be mangled is a + /// constructor or destructor. + /// + ///\returns The mangled or pure name (when ND should not be mangled) on + /// success or an empty string on failure. + /// + std::string maybeMangleDeclName(const clang::NamedDecl* ND, + const clang::GlobalDecl* GD = nullptr); + ///\brief Get the mangled name of a GlobalDecl. /// - ///\param [in] GD - try to mangle this decl's name. - ///\param [out] mangledName - put the mangled name in here. + ///\param [in] GD - Try to mangle this decl's name. /// - void maybeMangleDeclName(const clang::GlobalDecl& GD, - std::string& mangledName); + ///\returns The mangled or pure name (when ND should not be mangled) on + /// success or an empty string on failure. + /// + std::string maybeMangleDeclName(const clang::GlobalDecl& GD); + ///\brief Get the mangled name of a clang::Decl subclass. FunctionDecl, + /// VarDecl, ValueDecl, and NamedDecl are currently supported. + /// + ///\param [in] Decl - Try to mangle this decl's name. + /// + ///\returns The mangled or pure name (when ND should not be mangled) on + /// success or an empty string on failure. + /// + template + std::string maybeMangleDeclName(const T* Decl); ///\brief Retrieves the last expression of a function body. If it was a /// DeclStmt with a variable declaration, creates DeclRefExpr and adds it to diff --git a/lib/Interpreter/DeclUnloader.cpp b/lib/Interpreter/DeclUnloader.cpp index 83fd4b56ec..8b57d92a9c 100644 --- a/lib/Interpreter/DeclUnloader.cpp +++ b/lib/Interpreter/DeclUnloader.cpp @@ -853,17 +853,16 @@ bool DeclUnloader::VisitRedeclarable(clang::Redeclarable* R, DeclContext* DC) utils::DiagnosticsOverride IgnoreMangleErrors(m_Sema->getDiagnostics()); #endif #endif - utils::Analyze::maybeMangleDeclName(GD, mangledName); + utils::Analyze::maybeMangleDeclName(GD).swap(mangledName); } // Handle static locals. void func() { static int var; } is represented // in the llvm::Module is a global named @func.var if (const VarDecl* VD = dyn_cast(GD.getDecl())) { if (VD->isStaticLocal()) { - std::string functionMangledName; - GlobalDecl FDGD(cast(VD->getDeclContext())); - utils::Analyze::maybeMangleDeclName(FDGD, functionMangledName); - mangledName = functionMangledName + "." + mangledName; + mangledName = utils::Analyze::maybeMangleDeclName(GlobalDecl( + cast(VD->getDeclContext()))) + + "." + mangledName; } } diff --git a/lib/Interpreter/IncrementalExecutor.cpp b/lib/Interpreter/IncrementalExecutor.cpp index 1b1b2c79b7..a40027dd52 100644 --- a/lib/Interpreter/IncrementalExecutor.cpp +++ b/lib/Interpreter/IncrementalExecutor.cpp @@ -317,7 +317,7 @@ IncrementalExecutor::installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp) } bool -IncrementalExecutor::addSymbol(const char* Name, void* Addr, +IncrementalExecutor::addSymbol(llvm::StringRef Name, void* Addr, bool Jit) { return m_JIT->lookupSymbol(Name, Addr, Jit).second; } diff --git a/lib/Interpreter/IncrementalExecutor.h b/lib/Interpreter/IncrementalExecutor.h index 5b00ce627c..22e084a7be 100644 --- a/lib/Interpreter/IncrementalExecutor.h +++ b/lib/Interpreter/IncrementalExecutor.h @@ -209,7 +209,7 @@ namespace cling { /// @param[in] JIT - Add to the JIT injected symbol table /// @returns true if the symbol is successfully registered, false otherwise. /// - bool addSymbol(const char* Name, void* Address, bool JIT = false); + bool addSymbol(llvm::StringRef Name, void* Address, bool JIT = false); ///\brief Add a llvm::Module to the JIT. /// diff --git a/lib/Interpreter/Interpreter.cpp b/lib/Interpreter/Interpreter.cpp index 50965d7156..7b29488831 100644 --- a/lib/Interpreter/Interpreter.cpp +++ b/lib/Interpreter/Interpreter.cpp @@ -185,12 +185,19 @@ namespace cling { Interpreter::Interpreter(int argc, const char* const *argv, const char* llvmdir /*= 0*/, bool noRuntime, const Interpreter* parentInterp) : - m_Opts(argc, argv), + m_Opts(argc, argv), m_Parenting(nullptr), m_UniqueCounter(parentInterp ? parentInterp->m_UniqueCounter + 1 : 0), m_PrintDebug(false), m_DynamicLookupDeclared(false), m_DynamicLookupEnabled(false), m_RawInputEnabled(false), m_OptLevel(parentInterp ? parentInterp->m_OptLevel : -1) { + if (parentInterp) { + m_Parenting = new Interpreter*[2]; + m_Parenting[0] = this; + m_Parenting[1] = const_cast(parentInterp); + } else + m_Parenting = reinterpret_cast(this); + if (handleSimpleOptions(m_Opts)) return; @@ -222,9 +229,12 @@ namespace cling { return; } + const CompilerInstance* CI = getCI(); + const LangOptions& LangOpts = CI->getLangOpts(); + // Tell the diagnostic client that we are entering file parsing mode. - DiagnosticConsumer& DClient = getCI()->getDiagnosticClient(); - DClient.BeginSourceFile(getCI()->getLangOpts(), &PP); + DiagnosticConsumer& DClient = CI->getDiagnosticClient(); + DClient.BeginSourceFile(LangOpts, &PP); llvm::SmallVector IncrParserTransactions; @@ -259,12 +269,40 @@ namespace cling { #endif if (GV) { if (void* Addr = m_Executor->getPointerToGlobalFromJIT(*GV)) - m_Executor->addSymbol(Sym.str().c_str(), Addr, true); + m_Executor->addSymbol(Sym, Addr, true); else cling::errs() << Sym << " not defined\n"; } else cling::errs() << Sym << " not in Module!\n"; } + + const clang::Decl* Scope = + LangOpts.CPlusPlus + ? m_LookupHelper->findScope("cling::runtime", + LookupHelper::NoDiagnostics) + : CI->getSema().getASTContext().getTranslationUnitDecl(); + if (!Scope) { + cling::errs() << "Scope for gCling was not found\n"; + } else if (const clang::ValueDecl* gCling = + m_LookupHelper->findDataMember( + Scope, "gCling", LookupHelper::NoDiagnostics)) { + std::string Name = !LangOpts.CPlusPlus ? "gCling" : + utils::Analyze::maybeMangleDeclName(gCling); + if (!Name.empty()) { +#ifdef LLVM_ON_WIN32 + // MS mangling is purposely adding a prefix of '\x1'...why? + if (Name[0] == '\x1') + Name.erase(0, 1); +#endif + // gCling gets linked to top-most Interpreter. + if (!parent()) + m_Executor->addSymbol(Name, &m_Parenting, true); + else + m_Executor->addSymbol(Name, &m_Parenting[1], true); + } + } else { + cling::errs() << "gCling was not found\n"; + } } } } @@ -340,6 +378,21 @@ namespace cling { // explicitly, before the implicit destruction (through the unique_ptr) of // the callbacks. m_IncrParser.reset(0); + + if (m_Parenting != reinterpret_cast(this)) + delete [] m_Parenting; + } + + Interpreter* Interpreter::parent() { + if (m_Parenting == reinterpret_cast(this)) + return nullptr; + return m_Parenting[1]; + } + + Interpreter& Interpreter::ancestor() { + if (m_Parenting == reinterpret_cast(this)) + return *this; + return m_Parenting[1]->ancestor(); } Transaction* Interpreter::Initialize(bool NoRuntime, bool SyntaxOnly, @@ -356,26 +409,13 @@ namespace cling { // (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) { - if (LangOpts.CPlusPlus) { - Strm << "#include \"cling/Interpreter/RuntimeUniverse.h\"\n"; - if (EmitDefinitions) - Strm << "namespace cling { class Interpreter; namespace runtime { " - "Interpreter* gCling=(Interpreter*)" << ThisP << ";}}\n"; - } else { - Strm << "#include \"cling/Interpreter/CValuePrinter.h\"\n" - << "void* gCling"; - if (EmitDefinitions) - Strm << "=(void*)" << ThisP; - Strm << ";\n"; - } - } + // itself? + if (!NoRuntime) + Strm << "#include \"cling/Interpreter/RuntimeUniverse.h\"\n"; // Intercept all atexit calls, as the Interpreter and functions will be long // gone when the -native- versions invoke them. + const char* Linkage = LangOpts.CPlusPlus ? "extern \"C\"" : ""; #if defined(__GLIBCXX__) && !defined(__APPLE__) const char* LinkageCxx = "extern \"C++\""; const char* Attr = LangOpts.CPlusPlus ? " throw () " : ""; @@ -943,10 +983,8 @@ namespace cling { if (!FD) return kExeUnkownFunction; - std::string mangledNameIfNeeded; - utils::Analyze::maybeMangleDeclName(FD, mangledNameIfNeeded); IncrementalExecutor::ExecutionResult ExeRes = - m_Executor->executeWrapper(mangledNameIfNeeded, res); + m_Executor->executeWrapper(utils::Analyze::maybeMangleDeclName(FD), res); return ConvertExecutionResult(ExeRes); } @@ -1510,9 +1548,7 @@ namespace cling { void* Interpreter::getAddressOfGlobal(const GlobalDecl& GD, bool* fromJIT /*=0*/) const { // Return a symbol's address, and whether it was jitted. - std::string mangledName; - utils::Analyze::maybeMangleDeclName(GD, mangledName); - return getAddressOfGlobal(mangledName, fromJIT); + return getAddressOfGlobal(utils::Analyze::maybeMangleDeclName(GD), fromJIT); } void* Interpreter::getAddressOfGlobal(llvm::StringRef SymName, diff --git a/lib/Utils/AST.cpp b/lib/Utils/AST.cpp index 6d46522ab5..89a9cd1b76 100644 --- a/lib/Utils/AST.cpp +++ b/lib/Utils/AST.cpp @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ #include "cling/Utils/AST.h" +#include "cling/Utils/Output.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclarationName.h" @@ -57,53 +58,79 @@ namespace utils { .startswith(Synthesize::UniquePrefix); } - void Analyze::maybeMangleDeclName(const GlobalDecl& GD, - std::string& mangledName) { - // copied and adapted from CodeGen::CodeGenModule::getMangledName - - NamedDecl* D - = cast(const_cast(GD.getDecl())); - std::unique_ptr mangleCtx; - mangleCtx.reset(D->getASTContext().createMangleContext()); - if (!mangleCtx->shouldMangleDeclName(D)) { - IdentifierInfo *II = D->getIdentifier(); - assert(II && "Attempt to mangle unnamed decl."); - mangledName = II->getName(); - return; - } + namespace Analyze { + std::string maybeMangleDeclName(const NamedDecl *ND, const GlobalDecl* GD) { + // copied and adapted from CodeGen::CodeGenModule::getMangledName - llvm::raw_string_ostream RawStr(mangledName); - switch(D->getKind()) { - case Decl::CXXConstructor: - //Ctor_Complete, // Complete object ctor - //Ctor_Base, // Base object ctor - //Ctor_CompleteAllocating // Complete object allocating ctor (unused) - mangleCtx->mangleCXXCtor(cast(D), - GD.getCtorType(), RawStr); - break; - - case Decl::CXXDestructor: - //Dtor_Deleting, // Deleting dtor - //Dtor_Complete, // Complete object dtor - //Dtor_Base // Base object dtor -#if defined(LLVM_ON_WIN32) - // MicrosoftMangle.cpp:954 calls llvm_unreachable when mangling Dtor_Comdat - if (GD.getDtorType() == Dtor_Comdat) { - if (const IdentifierInfo* II = D->getIdentifier()) - RawStr << II->getName(); - } else -#endif - { - mangleCtx->mangleCXXDtor(cast(D), - GD.getDtorType(), RawStr); + std::unique_ptr mangleCtx; + mangleCtx.reset(ND->getASTContext().createMangleContext()); + if (!mangleCtx->shouldMangleDeclName(ND)) { + IdentifierInfo *II = ND->getIdentifier(); + assert(II && "Attempt to mangle unnamed decl."); + return II->getName(); } - break; - default : - mangleCtx->mangleName(D, RawStr); - break; + stdstrstream RawStr; + switch (ND->getKind()) { + case Decl::CXXConstructor: + //Ctor_Complete, // Complete object ctor + //Ctor_Base, // Base object ctor + //Ctor_CompleteAllocating // Complete object allocating ctor (unused) + if (GD) { + mangleCtx->mangleCXXCtor(cast(ND), + GD->getCtorType(), RawStr); + break; + } + + case Decl::CXXDestructor: + //Dtor_Deleting, // Deleting dtor + //Dtor_Complete, // Complete object dtor + //Dtor_Base // Base object dtor + if (GD) { + #if defined(LLVM_ON_WIN32) + // MicrosoftMangle.cpp:954 calls llvm_unreachable when mangling Dtor_Comdat + if (GD->getDtorType() == Dtor_Comdat) { + if (const IdentifierInfo* II = ND->getIdentifier()) + RawStr << II->getName(); + } else + #endif + { + mangleCtx->mangleCXXDtor(cast(ND), + GD->getDtorType(), RawStr); + } + break; + } + + default : + mangleCtx->mangleName(ND, RawStr); + break; + } + return RawStr.str(); + } + + std::string maybeMangleDeclName(const GlobalDecl& GD) { + return maybeMangleDeclName(cast(GD.getDecl()), &GD); + } + + template <> + std::string maybeMangleDeclName(const FunctionDecl* FD) { + return maybeMangleDeclName(GlobalDecl(FD)); + } + + template <> + std::string maybeMangleDeclName(const VarDecl* VD) { + return maybeMangleDeclName(GlobalDecl(VD)); + } + + template <> + std::string maybeMangleDeclName(const ValueDecl* VD) { + return maybeMangleDeclName(cast(VD), nullptr); + } + + template <> + std::string maybeMangleDeclName(const NamedDecl* ND) { + return maybeMangleDeclName(ND, nullptr); } - RawStr.flush(); } Expr* Analyze::GetOrCreateLastExpr(FunctionDecl* FD,