This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]