Add preliminary support for MSVC-style vtables.

llvm-svn: 126865
This commit is contained in:
Tilmann Scheller 2011-03-02 19:38:28 +00:00
parent 6b4007dec6
commit a6c995dbb2
1 changed files with 61 additions and 2 deletions

View File

@ -2266,6 +2266,32 @@ void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
int64_t CurrentIndex = 0;
// The MSVC Win64 ABI uses a different ordering of the
// virtual function pointers:
//
// The order of the virtual function pointers in a virtual table is
// the reverse order of declaration of the corresponding member functions
// in the class except for overloaded member functions. Overloaded member
// functions are moved below the first declaration of the
// respective overloaded member function. All declarations for one
// overloaded member function are added in reverse order of declaration.
//
// E.g. for the following class:
// class A {
// virtual b();
// virtual a(int a);
// virtual c();
// virtual a(float a);
// };
//
// The vtable layout looks like this:
// c()
// a(float b)
// a(int a)
// b()
//
const bool IsWin64 = CGM.getContext().Target.isWin64();
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
@ -2285,6 +2311,9 @@ void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
const CXXDestructorDecl *ImplicitVirtualDtor = 0;
llvm::StringMap<llvm::SmallVector<const CXXMethodDecl *, 16> *> Methods;
llvm::SmallVector<llvm::SmallVector<const CXXMethodDecl *, 16> *, 16> Order;
for (CXXRecordDecl::method_iterator i = RD->method_begin(),
e = RD->method_end(); i != e; ++i) {
const CXXMethodDecl *MD = *i;
@ -2293,6 +2322,20 @@ void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
if (!MD->isVirtual())
continue;
if (IsWin64) {
if (Methods.count(MD->getNameAsString()) == 0) {
// No entry yet.
llvm::SmallVector<const CXXMethodDecl *, 16> *entry = new llvm::SmallVector<const CXXMethodDecl *, 16>();
entry->push_back(MD);
Methods[MD->getNameAsString()] = entry;
Order.push_back(entry);
} else {
// This is an overloaded method, add to already existing entry.
llvm::SmallVector<const CXXMethodDecl *, 16> *entry = Methods[MD->getNameAsString()];
entry->push_back(MD);
}
}
// Check if this method overrides a method in the primary base.
if (const CXXMethodDecl *OverriddenMD =
FindNearestOverriddenMethod(MD, PrimaryBases)) {
@ -2327,7 +2370,7 @@ void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
ImplicitVirtualDtor = DD;
continue;
}
assert(!IsWin64 && "Need support for dtor!");
// Add the complete dtor.
MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
@ -2335,11 +2378,14 @@ void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
} else {
// Add the entry.
MethodVTableIndices[MD] = CurrentIndex++;
if (!IsWin64) {
MethodVTableIndices[MD] = CurrentIndex++;
}
}
}
if (ImplicitVirtualDtor) {
assert(!IsWin64 && "Need support for implicit virtual dtor!");
// Itanium C++ ABI 2.5.2:
// If a class has an implicitly-defined virtual destructor,
// its entries come after the declared virtual function pointers.
@ -2353,6 +2399,19 @@ void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
CurrentIndex++;
}
if (IsWin64) {
for (llvm::SmallVector<llvm::SmallVector<const CXXMethodDecl *, 16> *, 16>::iterator i = Order.begin(),
e = Order.end(); i != e; ++i) {
llvm::SmallVector<const CXXMethodDecl *, 16> *elem = *i;
while (elem->size() > 0) {
const CXXMethodDecl *method = elem->pop_back_val();
// Add the entry.
MethodVTableIndices[method] = CurrentIndex++;
}
}
}
NumVirtualFunctionPointers[RD] = CurrentIndex;
}