Virtual function calls

Christophe de Dinechin ddd at cup.hp.com
Thu Feb 24 20:01:06 UTC 2000


Here were my notes...


struct vtable_entry
{
#ifdef SHARED_LIBS
	void (*fptr) ();
	uint64 GP_value;
#else
	void (*fptr) ();
#endif
}


CASE 1:

struct A {
	virtual f();
}

A* ptr;
ptr->f();

struct vtbl<A> {
	ptrdiff_t	offset_to_top = 0;
	typeinfo *	typeinfo = typeinfo<A>;
VPTR->	vtable_entry	f = A::f;
};



CASE 2:

struct B : A { }

struct vtbl<B> {
	ptrdiff_t	offset_to_top = 0;
	typeinfo *	typeinfo = typeinfo<B>;
VPTR->	vtable_entry	f = A::f;
};


CASE 3:

struct C : A {
	virtual f();
}

struct vtbl<C> {
	ptrdiff_t	offset_to_top = 0;
	typeinfo *	typeinfo = typeinfo<C>;
VPTR->	vtable_entry	f = C::f;


CASE 4:

struct X { virtual unique(); };

struct D : X, A { }

struct vtbl<D> {
	ptrdiff_t	offset_to_top<X,D> = 0
	typeinfo *	typeinfo = typeinfo<D>
VPTR<D,X>->vtable_entry	unique = X::unique;

	ptrdiff_t	offset_to_top<A> = -sizeof(vptr);
	typeinfo *	typeinfo = typeinfo<D>
VPTR<A>-> vtable_entry	f = A::f;
}

Calling A::f():
	with an A*: No adjustment
	with a D*: Adjustment to an A* at call-site.
	A* -> D* adjustmnent is known at compile time.


CASE 5:

struct E : X, A { virtual f(); }

E::f receives an E* as the this pointer, not an A*.

struct vtbl<E> {
	ptrdiff_t	offset_to_top<X,D> = 0
	typeinfo *	typeinfo = typeinfo<E>
VPTR<E,X>->vtable_entry	unique = X::unique;
	vtable_entry	f = E::f

	ptrdiff_t	offset_to_top<A> = -sizeof(vptr);
	typeinfo *	typeinfo = typeinfo<E>
VPTR<A>-> vtable_entry	f = E::f_thunk<A, E>;	// Thunk converting from A to E
};


Calling E::f():
	With an A*: Call site: no adjustment.
		Adjustment done by E::f_thunk<A, E>
	With an E*: Call site: no adjustment, calls through the vptr<E>->f.


CASE 6:

struct G : virtual A { }

struct vtbl<G> {
	ptrdiff_t	G_to_A_offset = 0;

	ptrdiff_t	offset_to_top<X,D> = 0
	typeinfo *	typeinfo = typeinfo<G>
VPTR<G>->

	ptrdiff_t	offset_to_top<A> = -sizeof(vptr);
	typeinfo *	typeinfo = typeinfo<G>
VPTR<A>-> vtable_entry	f = A::f
};

Calling G::f:
	Through an A*: as case 1
	Throught a G*: Magically convert G* to A* (by adding the G_to_A_offset),
		then use the A* to call A::f.

The "magical" conversion to be specified later, using a vbase offset.


CASE 7:

struct H : virtual A { virtual f(); }

struct vtbl<H> {

};


CASE 8:

struct I : H { }



CASE 9:

struct J : H { virtual f(); }




More information about the cxx-abi-dev mailing list