cp-tree.h (vcall_offset_in_vtable_p): New macro.

* cp-tree.h (vcall_offset_in_vtable_p): New macro.
	* class.c (build_vbase_offset_vtbl_entries): Fix typo in commment.
	(struct vcall_offset_data_s): New type.
	(dfs_vcall_offset_queue_p): New function.
	(dfs_build_vcall_offset_vtbl_entries): Likewise.
	(build_vcall_offset_vtbl_entries): Likewise.
	(layout_vtable_decl): Likewise.
	(num_vfun_entries): Likewise.
	(num_extra_vtbl_entries): Add the entries for vcall offsets.
	(build_vtbl_initializer): Likewise.
	(dfs_finish_vtabls): Use layout_vtable_decl.
	(modify_one_vtables): Always duplicate vtables under the new ABI.
	(finish_struct_1): Use layout_vtable_decl.

From-SVN: r31619
This commit is contained in:
Mark Mitchell 2000-01-25 23:26:21 +00:00 committed by Mark Mitchell
parent 0534b8047e
commit 1a588ad752
3 changed files with 254 additions and 36 deletions

View File

@ -1,3 +1,19 @@
2000-01-25 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (vcall_offset_in_vtable_p): New macro.
* class.c (build_vbase_offset_vtbl_entries): Fix typo in commment.
(struct vcall_offset_data_s): New type.
(dfs_vcall_offset_queue_p): New function.
(dfs_build_vcall_offset_vtbl_entries): Likewise.
(build_vcall_offset_vtbl_entries): Likewise.
(layout_vtable_decl): Likewise.
(num_vfun_entries): Likewise.
(num_extra_vtbl_entries): Add the entries for vcall offsets.
(build_vtbl_initializer): Likewise.
(dfs_finish_vtabls): Use layout_vtable_decl.
(modify_one_vtables): Always duplicate vtables under the new ABI.
(finish_struct_1): Use layout_vtable_decl.
2000-01-25 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* decl.c (member_function_or_else): Change third arg from a format

View File

@ -146,7 +146,13 @@ static tree dfs_set_offset_for_shared_vbases PROTO((tree, void *));
static tree dfs_set_offset_for_unshared_vbases PROTO((tree, void *));
static tree dfs_build_vbase_offset_vtbl_entries PROTO((tree, void *));
static tree build_vbase_offset_vtbl_entries PROTO((tree, tree));
static tree dfs_vcall_offset_queue_p PROTO((tree, void *));
static tree dfs_build_vcall_offset_vtbl_entries PROTO((tree, void *));
static tree build_vcall_offset_vtbl_entries PROTO((tree, tree));
static tree dfs_count_virtuals PROTO((tree, void *));
static void start_vtable PROTO((tree, int *));
static void layout_vtable_decl PROTO((tree, int));
static int num_vfun_entries PROTO((tree));
/* Variables shared between class.c and call.c. */
@ -324,7 +330,7 @@ build_vbase_offset_vtbl_entries (binfo, t)
list);
inits = nreverse (TREE_VALUE (list));
/* We've now got offsets in the right oder. However, the offsets
/* We've now got offsets in the right order. However, the offsets
we've stored are offsets from the beginning of the complete
object, and we need offsets from this BINFO. */
for (init = inits; init; init = TREE_CHAIN (init))
@ -345,6 +351,140 @@ build_vbase_offset_vtbl_entries (binfo, t)
return inits;
}
typedef struct vcall_offset_data_s
{
/* The binfo for the most-derived type. */
tree derived;
/* The binfo for the virtual base for which we're building
initializers. */
tree vbase;
/* The vcall offset initializers built up so far. */
tree inits;
/* The number of vcall offsets accumulated. */
int offsets;
} vcall_offset_data;
/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
static tree
dfs_vcall_offset_queue_p (binfo, data)
tree binfo;
void *data;
{
vcall_offset_data* vod = (vcall_offset_data *) data;
return (binfo == vod->vbase) ? binfo : dfs_skip_vbases (binfo, NULL);
}
/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
static tree
dfs_build_vcall_offset_vtbl_entries (binfo, data)
tree binfo;
void *data;
{
vcall_offset_data* vod;
tree virtuals;
tree binfo_inits;
/* Primary bases are not interesting; all of the virtual
function table entries have been overridden. */
if (BINFO_PRIMARY_MARKED_P (binfo))
return NULL_TREE;
vod = (vcall_offset_data *) data;
binfo_inits = NULL_TREE;
/* We chain the offsets on in reverse order. That's correct --
build_vtbl_initializer will straighten them out. */
for (virtuals = skip_rtti_stuff (binfo,
BINFO_TYPE (binfo),
NULL);
virtuals;
virtuals = TREE_CHAIN (virtuals))
{
tree fn;
tree base;
tree base_binfo;
tree offset;
/* Figure out what function we're looking at. */
fn = TREE_VALUE (virtuals);
base = DECL_CLASS_CONTEXT (fn);
/* The FN is comes from BASE. So, we must caculate the
adjustment from the virtual base that derived from BINFO to
BASE. */
base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
offset = ssize_binop (MINUS_EXPR,
BINFO_OFFSET (base_binfo),
BINFO_OFFSET (vod->vbase));
offset = build1 (NOP_EXPR, vtable_entry_type, offset);
offset = fold (offset);
TREE_CONSTANT (offset) = 1;
binfo_inits = tree_cons (NULL_TREE, offset, binfo_inits);
}
/* Now add the initializers we've just created to the list that will
be returned to our caller. */
vod->inits = chainon (vod->inits, binfo_inits);
return NULL_TREE;
}
/* Returns the initializers for the vcall offset entries in the vtable
for BINFO (which is part of the class hierarchy dominated by T), in
reverse order. */
static tree
build_vcall_offset_vtbl_entries (binfo, t)
tree binfo;
tree t;
{
vcall_offset_data vod;
/* Under the old ABI, the adjustments to the `this' pointer were made
elsewhere. */
if (!vcall_offsets_in_vtable_p ())
return NULL_TREE;
/* We only need these entries if this base is a virtual base. */
if (!TREE_VIA_VIRTUAL (binfo))
return NULL_TREE;
/* We need a vcall offset for each of the virtual functions in this
vtable. For example:
class A { virtual void f (); };
class B : virtual public A { };
class C: virtual public A, public B {};
Now imagine:
B* b = new C;
b->f();
The location of `A' is not at a fixed offset relative to `B'; the
offset depends on the complete object derived from `B'. So,
`B' vtable contains an entry for `f' that indicates by what
amount the `this' pointer for `B' needs to be adjusted to arrive
at `A'.
We need entries for all the functions in our primary vtable and
in our non-virtual bases vtables. For each base, the entries
appear in the same order as in the base; but the bases themselves
appear in reverse depth-first, left-to-right order. */
vod.derived = t;
vod.vbase = binfo;
vod.inits = NULL_TREE;
dfs_walk (binfo,
dfs_build_vcall_offset_vtbl_entries,
dfs_vcall_offset_queue_p,
&vod);
return vod.inits;
}
/* Returns a pointer to the virtual base class of EXP that has the
indicated TYPE. EXP is of class type, not a pointer type. */
@ -2321,6 +2461,68 @@ duplicate_tag_error (t)
TYPE_NONCOPIED_PARTS (t) = NULL_TREE;
}
/* Make the BINFO's vtablehave N entries, including RTTI entries, but
not including vbase and vcall offsets. Set its type and call the
backend to lay it out. */
static void
layout_vtable_decl (binfo, n)
tree binfo;
int n;
{
tree itype;
tree atype;
itype = size_int (n);
itype = size_binop (PLUS_EXPR,
itype,
num_extra_vtbl_entries (binfo));
atype = build_cplus_array_type (vtable_entry_type,
build_index_type (itype));
layout_type (atype);
/* We may have to grow the vtable. */
if (!same_type_p (TREE_TYPE (BINFO_VTABLE (binfo)), atype))
{
TREE_TYPE (BINFO_VTABLE (binfo)) = atype;
DECL_SIZE (BINFO_VTABLE (binfo)) = 0;
layout_decl (BINFO_VTABLE (binfo), 0);
/* At one time the vtable info was grabbed 2 words at a time. This
fails on sparc unless you have 8-byte alignment. (tiemann) */
DECL_ALIGN (BINFO_VTABLE (binfo))
= MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (BINFO_VTABLE (binfo)));
}
}
/* Returns the number of virtual function table entries (excluding
RTTI information, vbase and vcall offests, etc.) in the vtable for
BINFO. */
static int
num_vfun_entries (binfo)
tree binfo;
{
return list_length (skip_rtti_stuff (binfo,
BINFO_TYPE (binfo),
NULL));
}
/* Called from num_extra_vtbl_entries via dfs_walk. */
static tree
dfs_count_virtuals (binfo, data)
tree binfo;
void *data;
{
/* Non-primary bases are not interesting; all of the virtual
function table entries have been overridden. */
if (!BINFO_PRIMARY_MARKED_P (binfo))
((vcall_offset_data *) data)->offsets += num_vfun_entries (binfo);
return NULL_TREE;
}
/* Returns the number of extra entries (at negative indices) required
for BINFO's vtable. */
@ -2331,17 +2533,29 @@ num_extra_vtbl_entries (binfo)
tree type;
int entries;
/* Under the old ABI, there are no entries at negative offsets. */
if (!vbase_offsets_in_vtable_p ())
return size_zero_node;
type = BINFO_TYPE (binfo);
entries = 0;
/* There is an entry for the offset to each virtual base. */
entries += list_length (CLASSTYPE_VBASECLASSES (type));
if (vbase_offsets_in_vtable_p ())
entries += list_length (CLASSTYPE_VBASECLASSES (type));
return size_int (entries);
/* If this is a virtual base, there are entries for each virtual
function defined in this class or its bases. */
if (vcall_offsets_in_vtable_p () && TREE_VIA_VIRTUAL (binfo))
{
vcall_offset_data vod;
vod.vbase = binfo;
vod.offsets = 0;
dfs_walk (binfo,
dfs_count_virtuals,
dfs_vcall_offset_queue_p,
&vod);
entries += vod.offsets;
}
return entries ? size_int (entries) : size_zero_node;
}
/* Returns the offset (in bytes) from the beginning of BINFO's vtable
@ -2372,8 +2586,13 @@ build_vtbl_initializer (binfo, t)
tree inits = NULL_TREE;
tree type = BINFO_TYPE (binfo);
/* Add entries to the vtable that indicate how to adjust the this
pointer when calling a virtual function in this class. */
inits = build_vcall_offset_vtbl_entries (binfo, t);
/* Add entries to the vtable for offsets to our virtual bases. */
inits = build_vbase_offset_vtbl_entries (binfo, t);
inits = chainon (build_vbase_offset_vtbl_entries (binfo, t),
inits);
/* Process the RTTI stuff at the head of the list. If we're not
using vtable thunks, then the RTTI entry is just an ordinary
@ -2451,6 +2670,7 @@ dfs_finish_vtbls (binfo, data)
tree decl;
tree context;
layout_vtable_decl (binfo, list_length (BINFO_VIRTUALS (binfo)));
decl = BINFO_VTABLE (binfo);
context = DECL_CONTEXT (decl);
DECL_CONTEXT (decl) = 0;
@ -2675,8 +2895,10 @@ modify_one_vtable (binfo, t, fndecl)
tree virtuals;
unsigned HOST_WIDE_INT n;
/* update rtti entry */
if (flag_rtti)
/* If we're support RTTI then we always need a new vtable to point
to the RTTI information. Under the new ABI we may need a new
vtable to contain vcall and vbase offsets. */
if (flag_rtti || flag_new_abi)
{
if (binfo == TYPE_BINFO (t))
build_vtable (TYPE_BINFO (DECL_CONTEXT (TYPE_VFIELD (t))), t);
@ -5010,32 +5232,7 @@ finish_struct_1 (t)
/* Now lay out the virtual function table. */
if (has_virtual)
{
/* Use size_int so values are memoized in common cases. */
tree itype;
tree atype;
itype = size_int (has_virtual);
itype = size_binop (PLUS_EXPR,
itype,
num_extra_vtbl_entries (TYPE_BINFO (t)));
atype = build_cplus_array_type (vtable_entry_type,
build_index_type (itype));
layout_type (atype);
/* We may have to grow the vtable. */
if (TREE_TYPE (TYPE_BINFO_VTABLE (t)) != atype)
{
TREE_TYPE (TYPE_BINFO_VTABLE (t)) = atype;
DECL_SIZE (TYPE_BINFO_VTABLE (t)) = 0;
layout_decl (TYPE_BINFO_VTABLE (t), 0);
/* At one time the vtable info was grabbed 2 words at a time. This
fails on sparc unless you have 8-byte alignment. (tiemann) */
DECL_ALIGN (TYPE_BINFO_VTABLE (t))
= MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (TYPE_BINFO_VTABLE (t)));
}
}
layout_vtable_decl (TYPE_BINFO (t), has_virtual);
/* If we created a new vtbl pointer for this class, add it to the
list. */

View File

@ -213,6 +213,11 @@ extern int flag_rtti;
stored in the object itself. */
#define vbase_offsets_in_vtable_p() (flag_new_abi)
/* Nonzero if displacements to the `this' pointer to use when calling
virtual functions in a virtual base class are present in the
vtable. */
#define vcall_offsets_in_vtable_p() (flag_new_abi)
/* Nonzero if a derived class that needs a vptr should always get one,
even if a non-primary base class already has one. For example,
given: