forked from OSchip/llvm-project
Add basic support for simple non-virtual 'this' pointer adjustments.
llvm-svn: 96136
This commit is contained in:
parent
0daaf13b97
commit
d3adb0ced9
|
@ -156,11 +156,22 @@ public:
|
||||||
return OverridersMap.lookup(std::make_pair(Base, MD));
|
return OverridersMap.lookup(std::make_pair(Base, MD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// getReturnAdjustmentOffset - Get the return adjustment offset for the
|
||||||
|
/// method decl in the given base subobject. Returns an empty base offset if
|
||||||
|
/// no adjustment is needed.
|
||||||
BaseOffset getReturnAdjustmentOffset(BaseSubobject Base,
|
BaseOffset getReturnAdjustmentOffset(BaseSubobject Base,
|
||||||
const CXXMethodDecl *MD) const {
|
const CXXMethodDecl *MD) const {
|
||||||
return ReturnAdjustments.lookup(std::make_pair(Base, MD));
|
return ReturnAdjustments.lookup(std::make_pair(Base, MD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// getThisAdjustmentOffset - Get the 'this' pointer adjustment offset for the
|
||||||
|
/// method decl in the given base subobject. Returns an empty base offset if
|
||||||
|
/// no adjustment is needed.
|
||||||
|
BaseOffset getThisAdjustmentOffset(BaseSubobject Base,
|
||||||
|
const CXXMethodDecl *MD) const {
|
||||||
|
return ThisAdjustments.lookup(std::make_pair(Base, MD));
|
||||||
|
}
|
||||||
|
|
||||||
/// dump - dump the final overriders.
|
/// dump - dump the final overriders.
|
||||||
void dump() const {
|
void dump() const {
|
||||||
dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0));
|
dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0));
|
||||||
|
@ -691,7 +702,7 @@ private:
|
||||||
/// AddressPoints - Address points for the vtable being built.
|
/// AddressPoints - Address points for the vtable being built.
|
||||||
CGVtableInfo::AddressPointsMapTy AddressPoints;
|
CGVtableInfo::AddressPointsMapTy AddressPoints;
|
||||||
|
|
||||||
/// ReturnAdjustment - A return adjustment thunk.
|
/// ReturnAdjustment - A return adjustment.
|
||||||
struct ReturnAdjustment {
|
struct ReturnAdjustment {
|
||||||
/// NonVirtual - The non-virtual adjustment from the derived object to its
|
/// NonVirtual - The non-virtual adjustment from the derived object to its
|
||||||
/// nearest virtual base.
|
/// nearest virtual base.
|
||||||
|
@ -710,13 +721,35 @@ private:
|
||||||
llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16>
|
llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16>
|
||||||
ReturnAdjustments;
|
ReturnAdjustments;
|
||||||
|
|
||||||
|
/// ThisAdjustment - A 'this' pointer adjustment thunk.
|
||||||
|
struct ThisAdjustment {
|
||||||
|
/// NonVirtual - The non-virtual adjustment from the derived object to its
|
||||||
|
/// nearest virtual base.
|
||||||
|
int64_t NonVirtual;
|
||||||
|
|
||||||
|
/// FIXME: Add VCallOffsetOffset here.
|
||||||
|
|
||||||
|
ThisAdjustment() : NonVirtual(0) { }
|
||||||
|
|
||||||
|
bool isEmpty() const { return !NonVirtual; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// ThisAdjustments - The 'this' pointer adjustments needed in this vtable.
|
||||||
|
llvm::SmallVector<std::pair<uint64_t, ThisAdjustment>, 16>
|
||||||
|
ThisAdjustments;
|
||||||
|
|
||||||
/// ComputeReturnAdjustment - Compute the return adjustment given a return
|
/// ComputeReturnAdjustment - Compute the return adjustment given a return
|
||||||
/// adjustment base offset.
|
/// adjustment base offset.
|
||||||
ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset);
|
ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset);
|
||||||
|
|
||||||
|
/// ComputeThisAdjustment - Compute the 'this' pointer adjustment given a
|
||||||
|
/// 'this' pointer adjustment base offset.
|
||||||
|
ThisAdjustment ComputeThisAdjustment(FinalOverriders::BaseOffset Offset);
|
||||||
|
|
||||||
/// AddMethod - Add a single virtual member function to the vtable
|
/// AddMethod - Add a single virtual member function to the vtable
|
||||||
/// components vector.
|
/// components vector.
|
||||||
void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
|
void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment,
|
||||||
|
ThisAdjustment ThisAdjustment);
|
||||||
|
|
||||||
/// AddMethods - Add the methods of this base subobject and all its
|
/// AddMethods - Add the methods of this base subobject and all its
|
||||||
/// primary bases to the vtable components vector.
|
/// primary bases to the vtable components vector.
|
||||||
|
@ -779,12 +812,33 @@ VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) {
|
||||||
return Adjustment;
|
return Adjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VtableBuilder::ThisAdjustment
|
||||||
|
VtableBuilder::ComputeThisAdjustment(FinalOverriders::BaseOffset Offset) {
|
||||||
|
ThisAdjustment Adjustment;
|
||||||
|
|
||||||
|
if (!Offset.isEmpty()) {
|
||||||
|
assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!");
|
||||||
|
Adjustment.NonVirtual = Offset.NonVirtualOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Adjustment;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VtableBuilder::AddMethod(const CXXMethodDecl *MD,
|
VtableBuilder::AddMethod(const CXXMethodDecl *MD,
|
||||||
ReturnAdjustment ReturnAdjustment) {
|
ReturnAdjustment ReturnAdjustment,
|
||||||
|
ThisAdjustment ThisAdjustment) {
|
||||||
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
|
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
|
||||||
assert(ReturnAdjustment.isEmpty() &&
|
assert(ReturnAdjustment.isEmpty() &&
|
||||||
"Destructor can't have return adjustment!");
|
"Destructor can't have return adjustment!");
|
||||||
|
// Add the 'this' pointer adjustments if necessary.
|
||||||
|
if (!ThisAdjustment.isEmpty()) {
|
||||||
|
ThisAdjustments.push_back(std::make_pair(Components.size(),
|
||||||
|
ThisAdjustment));
|
||||||
|
ThisAdjustments.push_back(std::make_pair(Components.size() + 1,
|
||||||
|
ThisAdjustment));
|
||||||
|
}
|
||||||
|
|
||||||
// Add both the complete destructor and the deleting destructor.
|
// Add both the complete destructor and the deleting destructor.
|
||||||
Components.push_back(VtableComponent::MakeCompleteDtor(DD));
|
Components.push_back(VtableComponent::MakeCompleteDtor(DD));
|
||||||
Components.push_back(VtableComponent::MakeDeletingDtor(DD));
|
Components.push_back(VtableComponent::MakeDeletingDtor(DD));
|
||||||
|
@ -794,6 +848,11 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD,
|
||||||
ReturnAdjustments.push_back(std::make_pair(Components.size(),
|
ReturnAdjustments.push_back(std::make_pair(Components.size(),
|
||||||
ReturnAdjustment));
|
ReturnAdjustment));
|
||||||
|
|
||||||
|
// Add the 'this' pointer adjustment if necessary.
|
||||||
|
if (!ThisAdjustment.isEmpty())
|
||||||
|
ThisAdjustments.push_back(std::make_pair(Components.size(),
|
||||||
|
ThisAdjustment));
|
||||||
|
|
||||||
// Add the function.
|
// Add the function.
|
||||||
Components.push_back(VtableComponent::MakeFunction(MD));
|
Components.push_back(VtableComponent::MakeFunction(MD));
|
||||||
}
|
}
|
||||||
|
@ -847,7 +906,13 @@ VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) {
|
||||||
ReturnAdjustment ReturnAdjustment =
|
ReturnAdjustment ReturnAdjustment =
|
||||||
ComputeReturnAdjustment(ReturnAdjustmentOffset);
|
ComputeReturnAdjustment(ReturnAdjustmentOffset);
|
||||||
|
|
||||||
AddMethod(Overrider.Method, ReturnAdjustment);
|
// Check if this overrider needs a 'this' pointer adjustment.
|
||||||
|
FinalOverriders::BaseOffset ThisAdjustmentOffset =
|
||||||
|
Overriders.getThisAdjustmentOffset(Base, MD);
|
||||||
|
|
||||||
|
ThisAdjustment ThisAdjustment = ComputeThisAdjustment(ThisAdjustmentOffset);
|
||||||
|
|
||||||
|
AddMethod(Overrider.Method, ReturnAdjustment, ThisAdjustment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -927,6 +992,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned NextReturnAdjustmentIndex = 0;
|
unsigned NextReturnAdjustmentIndex = 0;
|
||||||
|
unsigned NextThisAdjustmentIndex = 0;
|
||||||
for (unsigned I = 0, E = Components.size(); I != E; ++I) {
|
for (unsigned I = 0, E = Components.size(); I != E; ++I) {
|
||||||
uint64_t Index = I;
|
uint64_t Index = I;
|
||||||
|
|
||||||
|
@ -990,7 +1056,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
|
||||||
if (MD->isPure())
|
if (MD->isPure())
|
||||||
Out << " [pure]";
|
Out << " [pure]";
|
||||||
|
|
||||||
// If this function pointer has a return adjustment thunk, dump it.
|
// If this function pointer has a return adjustment, dump it.
|
||||||
if (NextReturnAdjustmentIndex < ReturnAdjustments.size() &&
|
if (NextReturnAdjustmentIndex < ReturnAdjustments.size() &&
|
||||||
ReturnAdjustments[NextReturnAdjustmentIndex].first == I) {
|
ReturnAdjustments[NextReturnAdjustmentIndex].first == I) {
|
||||||
const ReturnAdjustment Adjustment =
|
const ReturnAdjustment Adjustment =
|
||||||
|
@ -1005,6 +1071,20 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
|
||||||
|
|
||||||
NextReturnAdjustmentIndex++;
|
NextReturnAdjustmentIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this function pointer has a 'this' pointer adjustment, dump it.
|
||||||
|
if (NextThisAdjustmentIndex < ThisAdjustments.size() &&
|
||||||
|
ThisAdjustments[NextThisAdjustmentIndex].first == I) {
|
||||||
|
const ThisAdjustment Adjustment =
|
||||||
|
ThisAdjustments[NextThisAdjustmentIndex].second;
|
||||||
|
|
||||||
|
Out << "\n [this adjustment: ";
|
||||||
|
Out << Adjustment.NonVirtual << " non-virtual";
|
||||||
|
|
||||||
|
Out << ']';
|
||||||
|
|
||||||
|
NextThisAdjustmentIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s
|
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s
|
||||||
namespace Test1 {
|
|
||||||
|
|
||||||
|
// For now, just verify this doesn't crash.
|
||||||
|
namespace test0 {
|
||||||
|
struct Obj {};
|
||||||
|
|
||||||
|
struct Base { virtual const Obj *foo() = 0; };
|
||||||
|
struct Derived : Base { virtual Obj *foo() { return new Obj(); } };
|
||||||
|
|
||||||
|
void test(Derived *D) { D->foo(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Test1 {
|
||||||
// CHECK: Vtable for 'Test1::A' (3 entries).
|
// CHECK: Vtable for 'Test1::A' (3 entries).
|
||||||
// CHECK-NEXT: 0 | offset_to_top (0)
|
// CHECK-NEXT: 0 | offset_to_top (0)
|
||||||
// CHECK-NEXT: 1 | Test1::A RTTI
|
// CHECK-NEXT: 1 | Test1::A RTTI
|
||||||
|
@ -202,7 +212,7 @@ void F::g() { }
|
||||||
|
|
||||||
namespace Test5 {
|
namespace Test5 {
|
||||||
|
|
||||||
// Simple secondary vtables without this-adjustments.
|
// Simple secondary vtables without 'this' pointer adjustments.
|
||||||
struct A {
|
struct A {
|
||||||
virtual void f();
|
virtual void f();
|
||||||
virtual void g();
|
virtual void g();
|
||||||
|
@ -240,12 +250,33 @@ struct C : B1, B2 {
|
||||||
void C::h() { }
|
void C::h() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
// For now, just verify this doesn't crash.
|
namespace Test6 {
|
||||||
namespace test0 {
|
|
||||||
struct Obj {};
|
|
||||||
|
|
||||||
struct Base { virtual const Obj *foo() = 0; };
|
// Simple non-virtual 'this' pointer adjustments.
|
||||||
struct Derived : Base { virtual Obj *foo() { return new Obj(); } };
|
struct A1 {
|
||||||
|
virtual void f();
|
||||||
|
int a;
|
||||||
|
};
|
||||||
|
|
||||||
void test(Derived *D) { D->foo(); }
|
struct A2 {
|
||||||
}
|
virtual void f();
|
||||||
|
int a;
|
||||||
|
};
|
||||||
|
|
||||||
|
// CHECK: Vtable for 'Test6::C' (6 entries).
|
||||||
|
// CHECK-NEXT: 0 | offset_to_top (0)
|
||||||
|
// CHECK-NEXT: 1 | Test6::C RTTI
|
||||||
|
// CHECK-NEXT: -- (Test6::A1, 0) vtable address --
|
||||||
|
// CHECK-NEXT: -- (Test6::C, 0) vtable address --
|
||||||
|
// CHECK-NEXT: 2 | void Test6::C::f()
|
||||||
|
// CHECK-NEXT: 3 | offset_to_top (-16)
|
||||||
|
// CHECK-NEXT: 4 | Test6::C RTTI
|
||||||
|
// CHECK-NEXT: -- (Test6::A2, 16) vtable address --
|
||||||
|
// CHECK-NEXT: 5 | void Test6::C::f()
|
||||||
|
// CHECK-NEXT: [this adjustment: -16 non-virtual]
|
||||||
|
struct C : A1, A2 {
|
||||||
|
virtual void f();
|
||||||
|
};
|
||||||
|
void C::f() { }
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue