B-1 writeup
Jason Merrill
jason at cygnus.com
Mon Nov 15 08:41:46 UTC 1999
<p><font color=blue>[991111 jason]</font>
We have decided that for virtual functions not inherited from a virtual base,
regular thunks will work fine, since we can emit them immediately before the
function to avoid the indirect branch penalty; we will use offsets in the
vtable for functions that come from a virtual base, because it is impossible
to predict what the offset between the current class and its virtual base will
be in classes derived from the current class.
<p>The calling convention is as follows:
<ul>
<li>vtable layout:<p>
For each virtual function defined in a class, we add an entry to the
primary vtable if one is not already there. In particular, a
definition which overrides a function inherited from a secondary base
gets a new slot in the primary vtable. We do this to avoid useless
adjustments when calling a virtual function through a pointer to the
most derived class.<p>
When a class is used as a virtual base, we add a vcall offset slot
to the beginning of its vtable for each of the virtual functions it
provides, whether in its primary or secondary vtables. Derived
classes which override these functions will use the slots to determine
the adjustment necessary.<p>
<li>Caller:<p>
As in Christophe's proposal above, the caller adjusts the 'this' argument to
point to the class which last overrode the function being called.
The result provides both the 'this' argument and the vtable pointer
for finding the function we want.<p>
<li>Callee:<p>
Each virtual function 'f' defined in a class 'A' has one entry point which
takes an A*, and performs no adjustment. The primary vtable for A
points to this entry point.<p>
For each secondary vtable from a non-virtual base class 'B' which defines
f, an additional entry point is generated which performs the constant
adjustment from B* to A*.<p>
For each secondary vtable from a virtual base class 'C' which defines f,
an additional entry point is generated which performs the adjustment
from C* to A* using the vcall offset for f stored in the secondary vtable
for C.<p>
For each secondary vtable from a base 'D' which is a non-virtual base of a
virtual base 'E', an additional entry point is generated which
first performs the constant adjustment from D* to E*, then the
adjustment from E* to A* using the vcall offset for f stored in the
secondary vtable for E.<p>
<li>Implementation<p>
Note that the ABI only specifies the multiple entry points; how those
entry points are provided is unspecified. An existing compiler which
uses thunks could be converted to use this ABI by only adding support
for the vcall offsets. A more efficient implementation would be to
emit all of the thunks immediately before the non-adjusting entry
point to the function. Another might use predication rather than
branches to reach the main function. Another might emit a new copy of
the function for each entry point; this is a quality of implementation
issue.
</ul>
More information about the cxx-abi-dev
mailing list