vtable layout

Jason Merrill jason at cygnus.com
Fri Aug 27 00:20:11 UTC 1999


I just sent this summary to a gcc discussion list.  Does this sound
accurate to y'all?  In particular, does assigning the slot to the vtable most
non-virtually derived from the introducing vtable make sense?

---------

Rather than per-function offsets, we have per-target type offsets.  These
offsets (if any) are stored at a negative index from the vptr.  When a
derived class D overrides a virtual function F from a base class B, if no
previously allocated offset slot can be reused, we add one to the
beginning of the vtable(s) of the closest base(s) which are non-virtually
derived from B.  In the case of non-virtual inheritance, that would be D's
vtable; in simple virtual inheritance, it would be B's.  The vtables are
written out in one large block, laid out like an object of the class, so if
B is a non-virtual base of D, we can find the D vtable from the B vptr.

D::f then recieves a B*, loads the offset from the vtable, and makes the
adjustment to get a D*.  The plan is to also have a non-adjusting vtable
entry in D's vtable, so we don't have to do two adjustments to call D::f
with a D*; the implementation of this is up to the compiler.  I expect that
for g++, we will do the adjustment in a thunk which just falls into the
main function.

The performance problems with classic thunks occur when the thunk is
not close enough to the function it jumps to for a pc-relative branch.
This cannot be avoided in certain cases of virtual inheritance, where a
derived class must whip up a thunk for a new adjustment to a method it
doesn't override.

In this case, we will only ever have one thunk per function, so we don't
even have to jump.  Except in the case of covariant returns, that is,
where we will have one per return adjustment.  But we know all necessary
adjustments at the point of definition of the function, so they can all be
within pc-relative branch range.

Jason




More information about the cxx-abi-dev mailing list