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

Fix multiple generations of function for offset calculation of virtual b... #32

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions core/meta/src/TCling.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -4884,8 +4884,7 @@ Long_t TCling::ClassInfo_GetBaseOffset(ClassInfo_t* derived, ClassInfo_t* target
if (TClinginfo->GetDecl() == TClinginfoTarget->GetDecl()) {
return 0;
}
TClingBaseClassInfo binfo(fInterpreter, TClinginfo, TClinginfoTarget);
return binfo.Offset(address);
return TClinginfo->GetBaseOffset(TClinginfoTarget, address);
}

//______________________________________________________________________________
Expand Down
171 changes: 92 additions & 79 deletions core/meta/src/TClingBaseClassInfo.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ using namespace std;
static const string indent_string(" ");

TClingBaseClassInfo::TClingBaseClassInfo(cling::Interpreter* interp,
const TClingClassInfo* ci)
TClingClassInfo* ci)
: fInterp(interp), fClassInfo(0), fFirstTime(true), fDescend(false),
fDecl(0), fIter(0), fBaseInfo(0), fOffset(0L), fClassInfoOwnership(true)
{
Expand All @@ -86,7 +86,7 @@ TClingBaseClassInfo::TClingBaseClassInfo(cling::Interpreter* interp,
}

TClingBaseClassInfo::TClingBaseClassInfo(cling::Interpreter* interp,
const TClingClassInfo* derived,
TClingClassInfo* derived,
TClingClassInfo* base)
: fInterp(interp), fClassInfo(0), fFirstTime(true), fDescend(false),
fDecl(0), fIter(0), fBaseInfo(0), fOffset(0L), fClassInfoOwnership(false)
Expand Down Expand Up @@ -165,34 +165,7 @@ OffsetPtrFunc_t TClingBaseClassInfo::GenerateBaseOffsetFunction(const TClingClas
// from the parameter derived class to the parameter target class for the
// address.

// Get the class or namespace name.
string derived_class_name;
if (derivedClass->GetType()) {
// This is a class, struct, or union member.
clang::QualType QTDerived(derivedClass->GetType(), 0);
ROOT::TMetaUtils::GetFullyQualifiedTypeName(derived_class_name, QTDerived, *fInterp);
}
else if (const clang::NamedDecl* ND =
dyn_cast<clang::NamedDecl>(derivedClass->GetDecl()->getDeclContext())) {
// This is a namespace member.
raw_string_ostream stream(derived_class_name);
ND->getNameForDiagnostic(stream, ND->getASTContext().getPrintingPolicy(), /*Qualified=*/true);
stream.flush();
}
string target_class_name;
if (targetClass->GetType()) {
// This is a class, struct, or union member.
clang::QualType QTTarget(targetClass->GetType(), 0);
ROOT::TMetaUtils::GetFullyQualifiedTypeName(target_class_name, QTTarget, *fInterp);
}
else if (const clang::NamedDecl* ND =
dyn_cast<clang::NamedDecl>(targetClass->GetDecl()->getDeclContext())) {
// This is a namespace member.
raw_string_ostream stream(target_class_name);
ND->getNameForDiagnostic(stream, ND->getASTContext().getPrintingPolicy(), /*Qualified=*/true);
stream.flush();
}

// Get the dedcls for the two classes.
const clang::Decl* derivedDecl = derivedClass->GetDecl();
const clang::Decl* targetDecl = targetClass->GetDecl();

Expand All @@ -205,59 +178,94 @@ OffsetPtrFunc_t TClingBaseClassInfo::GenerateBaseOffsetFunction(const TClingClas
buf << "h" << targetDecl;
wrapper_name = buf.str();
}
// Write the wrapper code.
string wrapperFwdDecl = "long " + wrapper_name + "(void* address)";
ostringstream buf;
buf << wrapperFwdDecl << "{\n";
buf << indent_string << derived_class_name << " *object = (" << derived_class_name << "*)address;";
buf << "\n";
buf << indent_string << target_class_name << " *target = object;";
buf << "\n";
buf << indent_string << "return ((long)target - (long)object);";
buf << "\n";
buf << "}\n";
string wrapper = "extern \"C\" " + wrapperFwdDecl + ";\n"
+ buf.str();
// Check whether the unction was already generated.
const GlobalValue* GV = fInterp->getModule()->getNamedValue(wrapper_name);

// Compile the wrapper code.
const FunctionDecl* WFD = 0;
{
cling::Transaction* Tp = 0;
cling::Interpreter::CompilationResult CR = fInterp->declare(wrapper, &Tp);
if (CR != cling::Interpreter::kSuccess) {
Error("TClingBaseClassInfo::GenerateBaseOffsetFunction", "Wrapper compile failed!");
return 0;
if (!GV) {
// Get the class or namespace name.
string derived_class_name;
if (derivedClass->GetType()) {
// This is a class, struct, or union member.
clang::QualType QTDerived(derivedClass->GetType(), 0);
ROOT::TMetaUtils::GetFullyQualifiedTypeName(derived_class_name, QTDerived, *fInterp);
}
else if (const clang::NamedDecl* ND =
dyn_cast<clang::NamedDecl>(derivedClass->GetDecl()->getDeclContext())) {
// This is a namespace member.
raw_string_ostream stream(derived_class_name);
ND->getNameForDiagnostic(stream, ND->getASTContext().getPrintingPolicy(), /*Qualified=*/true);
stream.flush();
}
string target_class_name;
if (targetClass->GetType()) {
// This is a class, struct, or union member.
clang::QualType QTTarget(targetClass->GetType(), 0);
ROOT::TMetaUtils::GetFullyQualifiedTypeName(target_class_name, QTTarget, *fInterp);
}
for (cling::Transaction::const_iterator I = Tp->decls_begin(),
E = Tp->decls_end(); !WFD && I != E; ++I) {
if (I->m_Call == cling::Transaction::kCCIHandleTopLevelDecl) {
if (const FunctionDecl* createWFD = dyn_cast<FunctionDecl>(*I->m_DGR.begin())) {
if (createWFD && isa<TranslationUnitDecl>(createWFD->getDeclContext())) {
DeclarationName FName = createWFD->getDeclName();
if (const IdentifierInfo* FII = FName.getAsIdentifierInfo()) {
if (FII->getName() == wrapper_name) {
WFD = createWFD;
else if (const clang::NamedDecl* ND =
dyn_cast<clang::NamedDecl>(targetClass->GetDecl()->getDeclContext())) {
// This is a namespace member.
raw_string_ostream stream(target_class_name);
ND->getNameForDiagnostic(stream, ND->getASTContext().getPrintingPolicy(), /*Qualified=*/true);
stream.flush();
}


// Write the wrapper code.
string wrapperFwdDecl = "long " + wrapper_name + "(void* address)";
ostringstream buf;
buf << wrapperFwdDecl << "{\n";
buf << indent_string << derived_class_name << " *object = (" << derived_class_name << "*)address;";
buf << "\n";
buf << indent_string << target_class_name << " *target = object;";
buf << "\n";
buf << indent_string << "return ((long)target - (long)object);";
buf << "\n";
buf << "}\n";
string wrapper = "extern \"C\" " + wrapperFwdDecl + ";\n"
+ buf.str();

// Compile the wrapper code.
const FunctionDecl* WFD = 0;
{
cling::Transaction* Tp = 0;
cling::Interpreter::CompilationResult CR = fInterp->declare(wrapper, &Tp);
if (CR != cling::Interpreter::kSuccess) {
Error("TClingBaseClassInfo::GenerateBaseOffsetFunction", "Wrapper compile failed!");
return 0;
}
for (cling::Transaction::const_iterator I = Tp->decls_begin(),
E = Tp->decls_end(); !WFD && I != E; ++I) {
if (I->m_Call == cling::Transaction::kCCIHandleTopLevelDecl) {
if (const FunctionDecl* createWFD = dyn_cast<FunctionDecl>(*I->m_DGR.begin())) {
if (createWFD && isa<TranslationUnitDecl>(createWFD->getDeclContext())) {
DeclarationName FName = createWFD->getDeclName();
if (const IdentifierInfo* FII = FName.getAsIdentifierInfo()) {
if (FII->getName() == wrapper_name) {
WFD = createWFD;
}
}
}
}
}
}
if (!WFD) {
Error("TClingBaseClassInfo::GenerateBaseOffsetFunction",
"Wrapper compile did not return a function decl!");
return 0;
}
}
if (!WFD) {

// Get the wrapper function pointer
// from the ExecutionEngine (the JIT).
GV = fInterp->getModule()->getNamedValue(wrapper_name);
if (!GV) {
Error("TClingBaseClassInfo::GenerateBaseOffsetFunction",
"Wrapper compile did not return a function decl!");
"Wrapper function name not found in Module!");
return 0;
}
}

// Get the wrapper function pointer
// from the ExecutionEngine (the JIT).
const GlobalValue* GV = fInterp->getModule()->getNamedValue(wrapper_name);
if (!GV) {
Error("TClingBaseClassInfo::GenerateBaseOffsetFunction",
"Wrapper function name not found in Module!");
return 0;
}
ExecutionEngine* EE = fInterp->getExecutionEngine();
OffsetPtrFunc_t f = (OffsetPtrFunc_t)EE->getPointerToGlobalIfAvailable(GV);
if (!f) {
Expand Down Expand Up @@ -435,7 +443,7 @@ static clang::CharUnits computeOffsetHint(clang::ASTContext &Context,
return Offset;
}

long TClingBaseClassInfo::Offset(void * address) const
ptrdiff_t TClingBaseClassInfo::Offset(void * address) const
{
// Compute the offset of the derived class to the base class.

Expand Down Expand Up @@ -490,18 +498,23 @@ long TClingBaseClassInfo::Offset(void * address) const
}
clang_val = -1;
}
fClassInfo->AddBaseOffsetValue(fBaseInfo->GetDecl(), clang_val);
return clang_val;
}
// Virtual inheritance case
OffsetPtrFunc_t executableFunc = fClassInfo->FindBaseOffsetFunction(fBaseInfo->GetDecl());
if (!executableFunc) {
// Error generated already by GenerateBaseOffsetFunction if executableFunc = 0.
executableFunc = GenerateBaseOffsetFunction(fClassInfo, fBaseInfo, address);
const_cast<TClingClassInfo*>(fClassInfo)->AddBaseOffsetFunction(fBaseInfo->GetDecl(), executableFunc);
// Verify the address of the instatiated object
if (!address) {
Error("TClingBaseClassInfo::Offset", "The address of the object for virtual base offset calculation is not valid.");
return -1;
}
if (address && executableFunc)

// Virtual inheritance case
OffsetPtrFunc_t executableFunc = GenerateBaseOffsetFunction(fClassInfo, fBaseInfo, address);
if (executableFunc) {
fClassInfo->AddBaseOffsetFunction(fBaseInfo->GetDecl(), executableFunc);
return (*executableFunc)(address);
return -1;
}

return -1;
}


Expand Down
8 changes: 4 additions & 4 deletions core/meta/src/TClingBaseClassInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class TClingBaseClassInfo {
private:

cling::Interpreter *fInterp; // Cling interpreter, we do *not* own.
const TClingClassInfo *fClassInfo; // Class we were intialized with, we own.
TClingClassInfo *fClassInfo; // Class we were intialized with, we own.
bool fFirstTime; // Flag to provide Cint semantics for iterator advancement (not first time)
bool fDescend; // Flag for signaling the need to descend on this advancement.
const clang::Decl *fDecl; // Current class whose bases we are iterating through, we do *not* own.
Expand All @@ -61,8 +61,8 @@ class TClingBaseClassInfo {
delete fBaseInfo;
}

TClingBaseClassInfo(cling::Interpreter*, const TClingClassInfo*);
TClingBaseClassInfo(cling::Interpreter*, const TClingClassInfo* derived, TClingClassInfo* base);
TClingBaseClassInfo(cling::Interpreter*, TClingClassInfo*);
TClingBaseClassInfo(cling::Interpreter*, TClingClassInfo* derived, TClingClassInfo* base);
TClingBaseClassInfo(const TClingBaseClassInfo&);
TClingBaseClassInfo& operator=(const TClingBaseClassInfo&);

Expand All @@ -71,7 +71,7 @@ class TClingBaseClassInfo {
bool IsValid() const;
int Next();
int Next(int onlyDirect);
long Offset(void * address = 0) const;
ptrdiff_t Offset(void * address = 0) const;
long Property() const;
long Tagnum() const;
void FullName(std::string &output, const ROOT::TMetaUtils::TNormalizedCtxt &normCtxt) const;
Expand Down
49 changes: 34 additions & 15 deletions core/meta/src/TClingClassInfo.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ static std::string FullyQualifiedName(const Decl *decl) {
}

TClingClassInfo::TClingClassInfo(cling::Interpreter *interp)
: fInterp(interp), fFirstTime(true), fDescend(false), fDecl(0), fType(0), fOffsetFunctions(0)
: fInterp(interp), fFirstTime(true), fDescend(false), fDecl(0), fType(0), fOffsetCache(0)
{
TranslationUnitDecl *TU =
interp->getCI()->getASTContext().getTranslationUnitDecl();
Expand All @@ -98,7 +98,7 @@ TClingClassInfo::TClingClassInfo(cling::Interpreter *interp)

TClingClassInfo::TClingClassInfo(cling::Interpreter *interp, const char *name)
: fInterp(interp), fFirstTime(true), fDescend(false), fDecl(0), fType(0),
fTitle(""), fOffsetFunctions(0)
fTitle(""), fOffsetCache(0)
{
const cling::LookupHelper& lh = fInterp->getLookupHelper();
const Type *type = 0;
Expand All @@ -120,17 +120,18 @@ TClingClassInfo::TClingClassInfo(cling::Interpreter *interp, const char *name)
TClingClassInfo::TClingClassInfo(cling::Interpreter *interp,
const Type &tag)
: fInterp(interp), fFirstTime(true), fDescend(false), fDecl(0), fType(0),
fTitle(""), fOffsetFunctions(0)
fTitle(""), fOffsetCache(0)
{
Init(tag);
}

void TClingClassInfo::AddBaseOffsetFunction(const clang::Decl* decl, OffsetPtrFunc_t func)
void TClingClassInfo::AddBaseOffsetValue(const clang::Decl* decl, long offset)
Copy link
Owner

Choose a reason for hiding this comment

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

inline in header?

{
// Add a function pointer for the offset from this class to the base class
// Add the offset value from this class to the non-virtual base class
// determined by the parameter decl.

fOffsetFunctions[decl] = func;

OffsetPtrFunc_t executableFunc = 0;
fOffsetCache[decl] = std::make_pair(offset, executableFunc);
}

long TClingClassInfo::ClassProperty() const
Expand Down Expand Up @@ -234,14 +235,6 @@ void TClingClassInfo::Destruct(void *arena) const
cf.ExecDestructor(this, arena, /*nary=*/0, /*withFree=*/false);
}

OffsetPtrFunc_t TClingClassInfo::FindBaseOffsetFunction(const clang::Decl* decl) const
{
// Find a pointer function for computing the offset to the base class determined
// by the parameter decl.

return fOffsetFunctions.lookup(decl);
}

const FunctionTemplateDecl *TClingClassInfo::GetFunctionTemplate(const char *fname) const
{
// Return any method or function in this scope with the name 'fname'.
Expand Down Expand Up @@ -533,6 +526,32 @@ long TClingClassInfo::GetOffset(const CXXMethodDecl* md) const
return offset;
}

ptrdiff_t TClingClassInfo::GetBaseOffset(TClingClassInfo* base, void* address)
{
// Check for the offset in the cache.
llvm::DenseMapIterator<const clang::Decl *, std::pair<ptrdiff_t, long (*)(void *)>, llvm::DenseMapInfo<const clang::Decl *>, true> iter
= fOffsetCache.find(base->GetDecl());
if (iter != fOffsetCache.end()) {
std::pair<ptrdiff_t, OffsetPtrFunc_t> offsetCache = (*iter).second;
if (OffsetPtrFunc_t executableFunc = offsetCache.second) {
if (address) {
return (*executableFunc)(address);
Copy link
Owner

Choose a reason for hiding this comment

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

else we know its a virtual base but we don't have an object - generating the offset function (as will happen here) won't help! I.e. we are missing an error message and a return -1 or whatever you return in these cases.

}
else {
Error("TClingBaseClassInfo::Offset", "The address of the object for virtual base offset calculation is not valid.");
return -1;
}
}
else {
return offsetCache.first;
}
}

// Compute the offset.
TClingBaseClassInfo binfo(fInterp, this, base);
return binfo.Offset(address);
}

static bool HasBody(const clang::FunctionDecl &decl, const cling::Interpreter &interp)
{
if (decl.hasBody()) return true;
Expand Down
9 changes: 5 additions & 4 deletions core/meta/src/TClingClassInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ namespace ROOT {
}
}

extern "C" typedef long (*OffsetPtrFunc_t)(void*);
extern "C" typedef ptrdiff_t (*OffsetPtrFunc_t)(void*);

class TClingClassInfo {

Expand All @@ -62,7 +62,7 @@ class TClingClassInfo {
std::vector<clang::DeclContext::decl_iterator> fIterStack; // Recursion stack for traversing nested scopes.
std::string fTitle; // The meta info for the class.
std::string fDeclFileName; // Name of the file where the underlying entity is declared.
llvm::DenseMap<const clang::Decl*, OffsetPtrFunc_t> fOffsetFunctions; // Functions already generated for offsets.
llvm::DenseMap<const clang::Decl*, std::pair<ptrdiff_t, OffsetPtrFunc_t> > fOffsetCache; // Functions already generated for offsets.

explicit TClingClassInfo() /* = delete */; // NOT IMPLEMENTED
TClingClassInfo &operator=(const TClingClassInfo &) /* = delete */; // NOT IMPLEMENTED
Expand All @@ -78,12 +78,12 @@ class TClingClassInfo {
explicit TClingClassInfo(cling::Interpreter *);
explicit TClingClassInfo(cling::Interpreter *, const char *);
explicit TClingClassInfo(cling::Interpreter *, const clang::Type &);
void AddBaseOffsetFunction(const clang::Decl* decl, OffsetPtrFunc_t func);
void AddBaseOffsetFunction(const clang::Decl* decl, OffsetPtrFunc_t func) { fOffsetCache[decl] = std::make_pair(0L, func); }
void AddBaseOffsetValue(const clang::Decl* decl, ptrdiff_t offset);
long ClassProperty() const;
void Delete(void *arena) const;
void DeleteArray(void *arena, bool dtorOnly) const;
void Destruct(void *arena) const;
OffsetPtrFunc_t FindBaseOffsetFunction(const clang::Decl* decl) const;
const clang::Decl *GetDecl() const { return fDecl; } // Underlying representation without Double32_t
TDictionary::DeclId_t GetDeclId() const { return (const clang::Decl*)(fDecl->getCanonicalDecl()); }
const clang::FunctionTemplateDecl *GetFunctionTemplate(const char *fname) const;
Expand All @@ -108,6 +108,7 @@ class TClingClassInfo {
InheritanceMode imode = WithInheritance) const;
int GetMethodNArg(const char *method, const char *proto, Bool_t objectIsConst, ROOT::EFunctionMatchMode mode = ROOT::kConversionMatch) const;
long GetOffset(const clang::CXXMethodDecl* md) const;
ptrdiff_t GetBaseOffset(TClingClassInfo* base, void* address);
const clang::Type *GetType() const { return fType; } // Underlying representation with Double32_t
bool HasDefaultConstructor() const;
bool HasMethod(const char *name) const;
Expand Down