Skip to content

Commit

Permalink
Merge pull request #661 from andreasfertig/fixCfrontVtable
Browse files Browse the repository at this point in the history
Fixed vtable initialization.
  • Loading branch information
andreasfertig authored Jul 19, 2024
2 parents 243312b + 5ecb45f commit 4f78c7d
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 16 deletions.
39 changes: 23 additions & 16 deletions CfrontCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,27 @@ void CfrontCodeGenerator::InsertArg(const CXXOperatorCallExpr* stmt)
}
//-----------------------------------------------------------------------------

static void InsertVtblPtr(const CXXMethodDecl* stmt, const CXXRecordDecl* cur, StmtsContainer& bodyStmts)
{
if(cur->isPolymorphic() and (0 == cur->getNumBases())) {
auto* fieldDecl = CfrontCodeGenerator::VtableData().VtblPtrField(cur);
auto* lhsMemberExpr = AccessMember(kwInternalThis, fieldDecl, Ptr(GetRecordDeclType(cur)));

// struct __mptr *__ptbl_vec__c___src_C_[]
auto* vtablAr = CfrontCodeGenerator::VtableData().VtblArrayVar(1);
auto* vtblArrayPos =
ArraySubscript(mkDeclRefExpr(vtablAr), GetGlobalVtablePos(stmt->getParent(), cur), fieldDecl->getType());

bodyStmts.AddBodyStmts(Assign(lhsMemberExpr, fieldDecl, vtblArrayPos));

} else if(cur->isPolymorphic() and (0 < cur->getNumBases()) and (cur != stmt->getParent())) {
for(const auto& base : cur->bases()) {
InsertVtblPtr(stmt, base.getType()->getAsCXXRecordDecl(), bodyStmts);
}
}
}
//-----------------------------------------------------------------------------

void CfrontCodeGenerator::InsertCXXMethodDecl(const CXXMethodDecl* stmt, SkipBody)
{
OutputFormatHelper initOutputFormatHelper{};
Expand Down Expand Up @@ -565,26 +586,12 @@ void CfrontCodeGenerator::InsertCXXMethodDecl(const CXXMethodDecl* stmt, SkipBod
insertFields(baseType->getAsRecordDecl());
}

auto insertVtblPtr = [&](const CXXRecordDecl* cur) {
if(cur->isPolymorphic() and (0 == cur->getNumBases())) {
auto* fieldDecl = VtableData().VtblPtrField(cur);
auto* lhsMemberExpr = AccessMember(kwInternalThis, fieldDecl, Ptr(GetRecordDeclType(cur)));

// struct __mptr *__ptbl_vec__c___src_C_[]
auto* vtablAr = VtableData().VtblArrayVar(1);
auto* vtblArrayPos = ArraySubscript(
mkDeclRefExpr(vtablAr), GetGlobalVtablePos(stmt->getParent(), cur), fieldDecl->getType());

bodyStmts.AddBodyStmts(Assign(lhsMemberExpr, fieldDecl, vtblArrayPos));
}
};

// insert our vtable pointer
insertVtblPtr(stmt->getParent());
InsertVtblPtr(stmt, stmt->getParent(), bodyStmts);

// in case of multi inheritance insert additional vtable pointers
for(const auto& base : parent->bases()) {
insertVtblPtr(base.getType()->getAsCXXRecordDecl());
InsertVtblPtr(stmt, base.getType()->getAsCXXRecordDecl(), bodyStmts);
}

// insert own fields
Expand Down
1 change: 1 addition & 0 deletions tests/EduCfrontTest7.expect
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ inline Derived * Constructor_Derived(Derived * __this)
Constructor_Type(&__this->mY, 5);
Constructor_BaseThird((BaseThird *)__this);
Constructor_Type(&__this->mZ, 5);
__this->__vptrBase = __vtbl_array[3];
__this->__vptrBaseThird = __vtbl_array[4];
/* dt // trivial type, maybe uninitialized */
__this->g = 4;
Expand Down
1 change: 1 addition & 0 deletions tests/EduCfrontVtable3Test.expect
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ inline C * Constructor_C(C * __this)
{
Constructor_B((B *)__this);
__this->mX = 5;
__this->__vptrA = __vtbl_array[2];
__this->mB = 8;
return __this;
}
Expand Down
1 change: 1 addition & 0 deletions tests/EduCfrontVtable4Test.expect
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ inline C * Constructor_C(C * __this)
{
Constructor_B((B *)__this);
__this->mX = 5;
__this->__vptrA = __vtbl_array[2];
__this->mB = 8;
return __this;
}
Expand Down
29 changes: 29 additions & 0 deletions tests/EduCfrontVtable7Test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// cmdlineinsights:-edu-show-cfront

#include <cstdio>

struct Fruit {
double md;
virtual ~Fruit() { puts("~Fruit"); }
virtual void Fun() { puts("Fruit's Fun"); }
};

struct Apple : Fruit {
int mX{5};
void Fun() override { printf("Apple's Fun: %d\n", mX); }
};

struct PinkLady : Apple {
int mApple{8};
void Fun() override { printf("Pink Ladies Fun: %d\n", mApple); }
};

int main()
{
PinkLady delicious{};
delicious.Fun();

Fruit* f{static_cast<Fruit*>(&delicious)};
f->Fun();
}

169 changes: 169 additions & 0 deletions tests/EduCfrontVtable7Test.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*************************************************************************************
* NOTE: This an educational hand-rolled transformation. Things can be incorrect or *
* buggy. *
*************************************************************************************/
void __cxa_start(void);
void __cxa_atexit(void);
typedef int (*__vptp)();

struct __mptr
{
short d;
short i;
__vptp f;
};

extern struct __mptr* __vtbl_array[];


#include <cstdio>

typedef struct Fruit
{
__mptr * __vptrFruit;
double md;
} Fruit;

inline void Destructor_Fruit(Fruit * __this)
{
puts("~Fruit");
}

inline void FunFruit(Fruit * __this)
{
puts("Fruit's Fun");
}

inline Fruit * operatorEqual(Fruit * __this, const Fruit * __rhs)
{
__this->md = __rhs->md;
return __this;
}

inline Fruit * Constructor_Fruit(Fruit * __this)
{
__this->__vptrFruit = __vtbl_array[0];
return __this;
}


typedef struct Apple
{
__mptr * __vptrFruit;
double md;
int mX;
} Apple;

inline void FunApple(Apple * __this)
{
printf("Apple's Fun: %d\n", __this->mX);
}

inline Apple * operatorEqual(Apple * __this, const Apple * __rhs)
{
__this->md = __rhs->md;
operatorEqual((Fruit *)__this, (Fruit *)__rhs);
__this->mX = __rhs->mX;
return __this;
}

inline Apple * operatorEqual(Apple * __this, Apple * __rhs)
{
__this->md = __rhs->md;
operatorEqual((Fruit *)__this, (Fruit *)__rhs);
__this->mX = __rhs->mX;
return __this;
}

inline void Destructor_Apple(Apple * __this)
{
Destructor_Fruit((Fruit *)__this);
}

inline Apple * Constructor_Apple(Apple * __this)
{
Constructor_Fruit((Fruit *)__this);
__this->__vptrFruit = __vtbl_array[1];
__this->mX = 5;
return __this;
}


typedef struct PinkLady
{
__mptr * __vptrFruit;
double md;
int mX;
int mApple;
} PinkLady;

inline void FunPinkLady(PinkLady * __this)
{
printf("Pink Ladies Fun: %d\n", __this->mApple);
}

inline PinkLady * operatorEqual(PinkLady * __this, const PinkLady * __rhs)
{
__this->mX = __rhs->mX;
operatorEqual((Apple *)__this, (Apple *)__rhs);
__this->mApple = __rhs->mApple;
return __this;
}

inline PinkLady * operatorEqual(PinkLady * __this, PinkLady * __rhs)
{
__this->mX = __rhs->mX;
operatorEqual((Apple *)__this, (Apple *)__rhs);
__this->mApple = __rhs->mApple;
return __this;
}

inline void Destructor_PinkLady(PinkLady * __this)
{
Destructor_Apple((Apple *)__this);
}

inline PinkLady * Constructor_PinkLady(PinkLady * __this)
{
Constructor_Apple((Apple *)__this);
__this->mX = 5;
__this->__vptrFruit = __vtbl_array[2];
__this->mApple = 8;
return __this;
}


int __main(void)
{
PinkLady delicious;
Constructor_PinkLady((PinkLady *)&delicious);
(*((void (*)(PinkLady *))((&delicious)->__vptrFruit[0]).f))((((PinkLady *)(char *)(&delicious)) + ((&delicious)->__vptrFruit[0]).d));
Fruit * f = (Fruit *)&delicious;
(*((void (*)(Fruit *))((f)->__vptrFruit[0]).f))((((Fruit *)(char *)(f)) + ((f)->__vptrFruit[0]).d));
return 0;
(*((void (*)(PinkLady *))((&delicious)->__vptrFruit[0]).f))((((PinkLady *)(char *)(&delicious)) + ((&delicious)->__vptrFruit[0]).d));
}

int main(void)
{
__cxa_start();
int ret = __main();
__cxa_atexit();
return ret;
/* ret // lifetime ends here */
}

__mptr __vtbl_Fruit[2] = {{0, 0, (__vptp)Destructor_Fruit}, {0, 0, (__vptp)FunFruit}};
__mptr __vtbl_Apple[2] = {{0, 0, (__vptp)Destructor_Apple}, {0, 0, (__vptp)FunApple}};
__mptr __vtbl_PinkLady[2] = {{0, 0, (__vptp)Destructor_PinkLady}, {0, 0, (__vptp)FunPinkLady}};

__mptr * __vtbl_array[3] = {__vtbl_Fruit, __vtbl_Apple, __vtbl_PinkLady};

void __cxa_start(void)
{
}

void __cxa_atexit(void)
{
}

0 comments on commit 4f78c7d

Please sign in to comment.