Skip to content
2 changes: 1 addition & 1 deletion include/cling/Interpreter/DynamicLookupRuntimeUniverse.h
Original file line number Diff line number Diff line change
@@ -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.
13 changes: 13 additions & 0 deletions include/cling/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
@@ -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<llvm::LLVMContext> 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; }

31 changes: 20 additions & 11 deletions include/cling/Interpreter/RuntimeUniverse.h
Original file line number Diff line number Diff line change
@@ -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 <new>

@@ -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
31 changes: 27 additions & 4 deletions include/cling/Utils/AST.h
Original file line number Diff line number Diff line change
@@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the change in interface style (returning the string rather than modifying a pass string)? For consistency sake we should only have one style (The existing style used to be more performance but nowadays with move semantic this is no longer the case).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was a separate PR as it had nothing to do with this, but pulled it in.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was a separate PR

Was or is? Is it still intended to be changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rolled it into this one d14e9b4

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I am a bit confused (i.e. I am missing something). d14e9b4 seems to be in the master for a long while, while this PR seems to not include it ... what am I missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh? Now I'm confused.
d14e9b4 is right below this comment section.
If it appears in any master it would be an interesting SHA1 collision.


///\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 <typename T>
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
9 changes: 4 additions & 5 deletions lib/Interpreter/DeclUnloader.cpp
Original file line number Diff line number Diff line change
@@ -853,17 +853,16 @@ bool DeclUnloader::VisitRedeclarable(clang::Redeclarable<T>* 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<VarDecl>(GD.getDecl())) {
if (VD->isStaticLocal()) {
std::string functionMangledName;
GlobalDecl FDGD(cast<FunctionDecl>(VD->getDeclContext()));
utils::Analyze::maybeMangleDeclName(FDGD, functionMangledName);
mangledName = functionMangledName + "." + mangledName;
mangledName = utils::Analyze::maybeMangleDeclName(GlobalDecl(
cast<FunctionDecl>(VD->getDeclContext()))) +
"." + mangledName;
}
}

2 changes: 1 addition & 1 deletion lib/Interpreter/IncrementalExecutor.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 1 addition & 1 deletion lib/Interpreter/IncrementalExecutor.h
Original file line number Diff line number Diff line change
@@ -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.
///
90 changes: 63 additions & 27 deletions lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
@@ -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<Interpreter*>(parentInterp);
} else
m_Parenting = reinterpret_cast<Interpreter**>(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<IncrementalParser::ParseResultTransaction, 2>
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<Interpreter**>(this))
delete [] m_Parenting;
}

Interpreter* Interpreter::parent() {
if (m_Parenting == reinterpret_cast<Interpreter**>(this))
return nullptr;
return m_Parenting[1];
}

Interpreter& Interpreter::ancestor() {
if (m_Parenting == reinterpret_cast<Interpreter**>(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,
113 changes: 70 additions & 43 deletions lib/Utils/AST.cpp
Original file line number Diff line number Diff line change
@@ -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<NamedDecl>(const_cast<Decl*>(GD.getDecl()));
std::unique_ptr<MangleContext> 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<CXXConstructorDecl>(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<CXXDestructorDecl>(D),
GD.getDtorType(), RawStr);
std::unique_ptr<MangleContext> 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<CXXConstructorDecl>(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<CXXDestructorDecl>(ND),
GD->getDtorType(), RawStr);
}
break;
}

default :
mangleCtx->mangleName(ND, RawStr);
break;
}
return RawStr.str();
}

std::string maybeMangleDeclName(const GlobalDecl& GD) {
return maybeMangleDeclName(cast<NamedDecl>(GD.getDecl()), &GD);
}

template <>
std::string maybeMangleDeclName<FunctionDecl>(const FunctionDecl* FD) {
return maybeMangleDeclName(GlobalDecl(FD));
}

template <>
std::string maybeMangleDeclName<VarDecl>(const VarDecl* VD) {
return maybeMangleDeclName(GlobalDecl(VD));
}

template <>
std::string maybeMangleDeclName<ValueDecl>(const ValueDecl* VD) {
return maybeMangleDeclName(cast<NamedDecl>(VD), nullptr);
}

template <>
std::string maybeMangleDeclName<NamedDecl>(const NamedDecl* ND) {
return maybeMangleDeclName(ND, nullptr);
}
RawStr.flush();
}

Expr* Analyze::GetOrCreateLastExpr(FunctionDecl* FD,