Determining the size of C++ vtables

Thomas Stüfe thomas.stuefe at gmail.com
Sat Feb 25 07:52:56 UTC 2017


Hi ioi,

On Fri, Feb 24, 2017 at 7:50 PM, Ioi Lam <ioi.lam at oracle.com> wrote:

>
>
> On 2/23/17 11:17 PM, Thomas Stüfe wrote:
>
> Hi Ioi,
>
> After reading through the original mailthread referenced in the bug
> report, the only reason the "just copy enough (200) slots from the vtable
> in libjvm.so to the vtable in the image" approach does not work for you is
> that you are afraid of hitting unmapped memory? If I understand it
> correctly.
>
> If that is the case, why not copy 200 slots with SafeFetch and stop at the
> first error? That should not incur much additional costs as long as you do
> not hit an unmapped area, in which case you'd stop anyway.
>
> Oh, that's a good simplification.I hadn't thought about using SafeFetch :-(
>
> One issue with it is the 200 slots are too big (ConstantPool needs just 10
> slots), so finding the exact size is a little more efficient and saves a
> few KBs.
>
>
How many vtables are you copying? Does it really matter?

As I said, I think your approach is quite elegant, but not terribly
portable. We already make some assumptions (that vtables are organized as
one continuous block of function pointers) and you add some more
assumptions about the order of the methods in the vtable.

I think even if you can make sure that it works now with our set of
platforms and compilers, this adds the risk that a future compiler update
may change the vtable layout and break the code. E.g. a vtable dumped with
a VM compilers by an older compiler could not be loaded with the newly
compiled VM.

Also, you set the bar a bit higher for future ports, because you add
requirements for the C++ compiler.

But I may be too cautious here and I am waiting for others to chime in.

As a side note, it would make sense to write a tiny C++ test which copies
vtables around using your technique and then checks if they still work;
such a test we could use on out platforms to check if our compilers can
cope. Such a test would also be a good sanity check to add to the VM
initialization if CDS is active.

Kind Regards, Thomas



> Thanks
> - Ioi
>
>
> That way you make yourself a bit less dependent on compiler internals. I
> agree that your approach is more elegant, though.
>
> Kind Regards, Thomas
>
> On Fri, Feb 24, 2017 at 4:55 AM, Ioi Lam <ioi.lam at oracle.com> 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 <Type>::_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   last_virtual_method() {return 1;}
>>> //   };
>>> //   class CppVtabTesterB: public InstanceKlass {
>>> //          virtual void* last_virtual_method() {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 &last_virtual_method, 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.
>>
>>
>>
>>
>
>


More information about the hotspot-dev mailing list