Do we need to reopen B1?

Jason Merrill jason at cygnus.com
Thu Feb 24 22:41:10 UTC 2000


>>>>> Christophe de Dinechin <ddd at cup.hp.com> writes:

 > In the absence of the "adjusting entry points" I proposed, you have to
 > use thunks. Within a same class, of course, you can use the 'AddAddAdd'
 > scheme, since you know the different offsets at compile time for the
 > various subobjects that compose the class. However, a derived class
 > cannot share this, because its vtable may very well be emitted in a
 > different .o.

I strongly disagree.  This is the primary goal of my design.

 > For instance, consider:

 > 	struct A { virtual a(); int aa; };
 > 	struct B { virtual b(); int bb; };
 > 	struct C { virtual c(); int cc; };

 > 	struct D : A, B { virtual b(); int dd; }
 > 	struct E : D { /* Does not override b() */ }

 > The primary vtable for D points to D::b, no adjustment required. The
 > secondary vtable for B in D points to D::b with, say, an 'Add'
 > adjustment, which would be of -16 (from the B* to the D*).

 > When you emit the vtable for E, the good news is that the adjustment is
 > the same (-16 from B* to D*). The bad news is that you don't know how to
 > locate the thunk that adds -16 (unless we all agree on the algorithm for
 > emitting this kind of "AddAddAdd" thunk, which we did not.)

Oh, come on.  Yes, we still need to define what entry point symbols will
be emitted with D::b, and how they are mangled, so that derived classes can
refer to them.  But we certainly can do that.

[snip two paragraphs arguing against this straw man]

 > So my proposal is simply that, for the non-virtual multiple inheritance
 > case, we have a this-pointer adjustment offset in each secondary vtable,
 > that adjusts form the secondary vtable class to the function's target
 > class.

 > The algorithm I proposed to allocate these offsets was the following:

 > - While defining class C, we allocate a single offset "convert_to_C",
 > that converts from the class of the secondary vtable in which it is
 > stored to the C class.

We allocate this in each secondary vtable where we refer to a function
overridden in C, correct?

This changes the size of the secondary vtables, but we've agreed that
doesn't matter.

 > - The convert_to_C in the C primary vtable is theoretically present, but
 > its value is zero, so it may be omitted.

 > - For all other classes, the offset of 'convert_to_C' relative to the
 > secondary vptr is constant. A naive algorithm to ensure that is that
 > this offset is the first negative offset not used by a 'convert_to_X' in
 > any of the bases. I acknoledge this generally may padding in the
 > vtables, but I did not see a better way to do it, short of using a
 > double indirection.

"in any of the bases where we want to allocate this value".  OK.

 > This 'convert_to_C' is used by an adjusting entry point emitted
 > immediatly prior to the main, non-adjusting entry point, which computes
 > this += convert_to_C. If I use this secondary entry point at all, I know
 > that the final overrider is C::f, and that the call was in the form
 > bptr->f(), where bptr is a non-primary non-virtual base of C.

 > The same 'convert_to_C' value is shared by different virtual functions
			   ^^^^^ you mean vptr offset?

 > overriden in C, no matter from which base they are overriden (the
 > interesting case, of course, being when they are overriden from multiple
 > bases). The reason is that if C::f override B::f, the delta is the same
 > than if C::g overrides B::g. It may be different than the delta between
 > C::g and B2::g, but then I am using B2's secondary vtable, which
 > contains the B2->C conversion.

OK.

 > This scheme has the following benefits:

 > - For each virtual function, you emit a secondary entry point with a
 > known size.  The best possible size is 48 bytes, unless some magic
 > predication thingie I did not think of can reduce that. No matter how
 > many secondary vbases or how many derived classes reuse that function,
 > the size is 48.

You don't need it at all if none of your bases need an adjustment.

 > - For each secondary base, you add 8 (or more if padding) bytes to the
 > table.

"each secondary base which refers to a funtion overridden in C".  Yes.

 > - This scheme works accross shared libraries, since the thunk used is
 > always "tied" to the function.

This is also true for my design, as mentioned above.

As you say above, this only applies to non-virtual inheritance.  This
scheme could be combined with the existing vcall offsets for virtual bases
such that you would get one additional entry point per virtual base that
refers to the function, or two if non-virtual bases of that virtual base
also refer to the function.  Is this what you had in mind?

If so, I agree that this is a feasible design.  I'm still unconvinced that
it's a big win; since you're allocating the convert_to_foo slots at the
other end of the vtable from the function pointer, I don't see how you can
expect d-cache locality.

Jason




More information about the cxx-abi-dev mailing list