Virtual function call stuff, again
Mark Mitchell
mark at codesourcery.com
Sat Feb 19 23:51:18 UTC 2000
Folks --
The virtual function call specification language is a disaster. A
random sample of one (me) show's that it's pretty much impossible for
anyone not actually been in all the meetings to implement. :-)
The discussion in the `callee' section on "Virtual Function Calling
Convention" is very unclear. For example, it's not explained which
classes are bases of which others. Here's an attempted rewrite.
Let's see if it's what y'all meant.
o Suppose a class `A' defines a virtual function `A::f'. The
primary vtable for `A' contains a pointer to an entry point
that performs no adjustment.
o Suppose that a class `A' declares a virtual function `A::f',
and suppose that `A' is a base class in a hierarchy dominated
by another class `B'. Suppose that the unique final overrider for
`A::f' in `B' is `C::f'. We must determine what entry point
is used for `f' in the `A-in-B' secondary vtable. Here is the
algorithm:
- Find any path from `B' to `C' in the inheritance graph for `B'.
- If there is no virtual base along the path, then create
an entry point which adjusts the `this' pointer from `A' to `C'.
This value can be computed statically when the `A-in-B' vtable
is created. Then transfer control to the non-adjusting entry
point for `C::f'.
- If there is a virtual base along this path, let `V' be the
virtual base nearest to `C' along the path. (In fact, `V'
will be `C' itself if `C' is a virtual base.)
(Note that the choice of `V' is independent of the choice of path.
If there was more than one path, then there must have been a
virtual base along all of the paths, and there is a unique one
closest to `C'.)
Now, create an entry point which first performs the adjustment
from `A' to `V'. (This value can be computed statically, when
the `A-in-B' vtable is created.) Then, adjust the `this'
pointer by the vcall offset stored in the secondary vtable for
`V' (i.e., the `V-in-B' vtable). (This adjustment will adjust
the `this' pointer from `V' to `C'.) Finally, transfer control
to the non-adjusting entry point for `C::f'.
Is that correct?
It seems like the scheme specified in the ABI is advantageous in a
situation where `C' is the same as `A', and `A' is the same as `V'.
(In other words, if `A' is a virtual base and `A::f' is not overriden
in `B'.) Then, by emitting the vcall-adjusting entry point right
before the main entry point for `C::f', calling `f' requires only one
branch (to the entry point specified in the vtable), rather than two
(to a thunk, and then from the thunk to the main function). Right?
I still can't see why it is a win to use vcall offsets in the case
where `A' and `V' are not the same class. You already have to do one
static adjustment in the entry point -- why not just adjust all the
way to `B' directly, without bothering to look up the vcall offset?
Furthermore, the actual algorithm used to perform the adjustments
does not seem necessarily to be part of the ABI. The layout of the
vtables is certainly part of the ABI. But, if one compiler wants to
completely ignore the vcall offset entries in the vtables, and compute
the entire adjustment statically, shouldn't that be permitted by the
ABI, even though it might require one extra branch? Surely that's
just a quality-of-implementation issue?
--
Mark Mitchell mark at codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
More information about the cxx-abi-dev
mailing list