This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [C++ PATCH] ctor vtable vcall offsets
>>>>> "Nathan" == Nathan Sidwell <nathan@codesourcery.com> writes:
> Jason Merrill wrote:
>> Actually, I don't see why we ever need to emit thunks with the vtable. The
>> example in the ABI document is
>>
>> struct A { virtual void f(); };
>> struct B : virtual public A { int i; };
>> struct C : virtual public A { int j; };
>> struct D : public B, public C {};
>>
>> But here, calling A::f() means converting to A* then calling through the A
>> vtable, so the entry in the C vtable is never used.
> hm, maybe you're right.
> here's my thinking
> A is the (nearly empty virtual) primary base of C, so C's vtable contains
> an embedded A table.
Yes.
> From g++'s behaviour, it appears to be taking advantage of that for the
> virtual call dispatch - I've not checked.
Perhaps we do, but that would be a bug.
> If D overrode A::f, then D would emit a vcall thunk for A::f for the
> C-in-D vtable, and we'd be happy. I'm not sure what would be the case
> when D doesn't override A::f - should it emit a thunk?
No -- it doesn't matter what we put in there, as it will never be used.
It's just dead space. We might as well fill it with __pure_virtual. We
would only care about the C-in-D vtable if C declared any virtual functions
(whether overridden or new), and then only for the bits for those functions.
3.2.4 Caller
When calling a virtual function f, through a pointer of static type
B*, the caller
* Selects a (possibly improper) subobject A of B such that A
declares f. (In general, A may be the same as B.) (Note that A
need not define f; it may contain either a definition of f, or a
declaration of f as a pure virtual function.)
* Converts the B* to point to this subobject. (Call the resulting
pointer `a'.)
* Uses the virtual table pointer contained in the A subobject to
locate the function pointer through which to perform the call.
* Calls through this function pointer, passing `a' as the this
pointer.
So, given a C* (or D* or B*), since the only class that declares f is A, to
call f we must first convert to an A*. This gives us a pointer to the A in
B in D. We then call through that pointer, which requires no adjustment.
> I think you might be right about emitting too many thunks though. I think
> we can still have the above optimization (which I guess is important, as
> it is one of the major features of the nearly-empty base class
> optimization), AND emit fewer thunks, if we have C's vtable emission
> cause a vcall thunk for A::f to be emitted. Then D's vtable and ctor
> vtable emission can make use of it.
The above optimization is invalid; the vcall algorithm requires conversion
to A*, and we cannot assume in general that converting from a C* to an A*
requires no adjustment.
> I think what I'm saying is that whenever we have a virtual primary base
> we should emit vcall adjusting thunks for all functions inherited from
> the base heirarchy -- not just those that we overrode. Does that work for
> you?
No, that's not necessary.
Jason