Determining the size of C++ vtables (original) (raw)
Ioi Lam ioi.lam at oracle.com
Fri Feb 24 18:56:02 UTC 2017
- Previous message: Determining the size of C++ vtables
- Next message: Non urgent question on https://bugs.openjdk.java.net/browse/JDK-4834738 (Adding which Object is null to an NPE)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On 2/23/17 7:55 PM, Ioi Lam wrote:
On 2/23/17 7:47 PM, Ioi Lam wrote: Hi,
I am working on https://bugs.openjdk.java.net/browse/JDK-8005165 (Remove CPU-dependent code in self-patching vtables), I need a way find out the size of a C++ vtable. I ended up doing this:
// Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables. // (In GCC this is the field ::vptr, i.e., first word in the object.) // // Addresses of the vtables and the methods may be different across JVM runs, // if libjvm.so is dynamically loaded at a different base address. // // To ensure that the Metadata objects in the CDS archive always have the correct vtable: // // + at dump time: we redirect the vptr to point to our own vtables inside // the CDS image // + at run time: we clone the actual contents of the vtables from libjvm.so // into our own tables. // // To determine the size of the vtable for each type, we use the following // trick by declaring 2 subclasses: // // class CppVtabTesterA: public InstanceKlass { // virtual int lastvirtualmethod() {return 1;} // }; // class CppVtabTesterB: public InstanceKlass { // virtual void* lastvirtualmethod() {return NULL}; // }; // // CppVtabTesterA and CppVtabTesterB's vtables have the following properties: // - Their size (N+1) is exactly one more than the size of InstanceKlass's vtable (N) // - The first N entries have are exactly the same as in InstanceKlass's vtable. // - Their last entry is different. // // So to determine the value of N, we just walk CppVtabTesterA and CppVtabTesterB's tables // and find the first entry that's different Could anyone comment if this is acceptable? I know it's not 100% portable (C++ doesn't specify where to find the vtable, or what's inside), but my assumptions is the same as the existing code. I.e., vptr is a pointer located at offset 0 of the object, and it points to a one-dimensional array. So at least it's not any worse than before? Thanks - Ioi By the way, I first tried having only a single "tester" class and walk the vtable to look for &lastvirtualmethod, but the C++ compiler told me that taking the address of a non-static function is not allowed ..... so I ended up creating two tester classes and checking their differences.
Just to clarify the above comments: taking a "reference" to a virtual function is allowed, but it's not specified what the "reference" is. With gcc, it's a 16-bit value:
#include <stdio.h>
class CppVtabTester {
public:
virtual int func1() {return 1;}
int func2() {return 2;}
};
int main() {
union {
int (CppVtabTester::*ptr)();
void* val[2];
} a, b;
a.ptr = &CppVtabTester::func1;
b.ptr = &CppVtabTester::func2;
printf("%d\n", (int)sizeof(a.ptr));
printf("ref: %p %p\n", a.val[0], a.val[1]);
printf("ref: %p %p\n", b.val[0], b.val[1]);
return 0;
}
ioimac ~/tmp$ gcc t.cpp
ioimac ~/tmp$ ./a.out
16
ref: 0x1 0x0
ref: 0x102d93f70 0x0
Unfortunately, the reference for a virtual function is just its vtable index :-(
Taking the "address" of a virtual function in some versions of gcc will give the real address (with a warning), and some versions of gcc will disallow it:
printf("ptr: %p\n", (void*)(&CppVtabTester::func1));
.....
t.cpp:21:35: error: cannot cast from type 'int (CppVtabTester::*)()'
to pointer
type 'void *'
printf("ptr : %p\n", (void*)(&CppVtabTester::func1));
- Previous message: Determining the size of C++ vtables
- Next message: Non urgent question on https://bugs.openjdk.java.net/browse/JDK-4834738 (Adding which Object is null to an NPE)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]