Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access parent from a child interpreter, and const correct gCling. #170

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion include/cling/Interpreter/DynamicLookupRuntimeUniverse.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
13 changes: 13 additions & 0 deletions include/cling/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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; }

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

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Up @@ -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
Expand Down
9 changes: 4 additions & 5 deletions lib/Interpreter/DeclUnloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Interpreter/IncrementalExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Interpreter/IncrementalExecutor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
90 changes: 63 additions & 27 deletions lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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";
}
}
}
}
Expand Down Expand Up @@ -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,
Expand All @@ -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 () " : "";
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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,
Expand Down
Loading