Commit 1a588ad7 by Mark Mitchell Committed by Mark Mitchell

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
parent 0534b804
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> 2000-01-25 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* decl.c (member_function_or_else): Change third arg from a format * decl.c (member_function_or_else): Change third arg from a format
......
...@@ -146,7 +146,13 @@ static tree dfs_set_offset_for_shared_vbases PROTO((tree, void *)); ...@@ -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_set_offset_for_unshared_vbases PROTO((tree, void *));
static tree dfs_build_vbase_offset_vtbl_entries 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 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 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. */ /* Variables shared between class.c and call.c. */
...@@ -324,7 +330,7 @@ build_vbase_offset_vtbl_entries (binfo, t) ...@@ -324,7 +330,7 @@ build_vbase_offset_vtbl_entries (binfo, t)
list); list);
inits = nreverse (TREE_VALUE (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 we've stored are offsets from the beginning of the complete
object, and we need offsets from this BINFO. */ object, and we need offsets from this BINFO. */
for (init = inits; init; init = TREE_CHAIN (init)) for (init = inits; init; init = TREE_CHAIN (init))
...@@ -345,6 +351,140 @@ build_vbase_offset_vtbl_entries (binfo, t) ...@@ -345,6 +351,140 @@ build_vbase_offset_vtbl_entries (binfo, t)
return inits; 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 /* Returns a pointer to the virtual base class of EXP that has the
indicated TYPE. EXP is of class type, not a pointer type. */ indicated TYPE. EXP is of class type, not a pointer type. */
...@@ -2321,6 +2461,68 @@ duplicate_tag_error (t) ...@@ -2321,6 +2461,68 @@ duplicate_tag_error (t)
TYPE_NONCOPIED_PARTS (t) = NULL_TREE; 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 /* Returns the number of extra entries (at negative indices) required
for BINFO's vtable. */ for BINFO's vtable. */
...@@ -2331,17 +2533,29 @@ num_extra_vtbl_entries (binfo) ...@@ -2331,17 +2533,29 @@ num_extra_vtbl_entries (binfo)
tree type; tree type;
int entries; 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); type = BINFO_TYPE (binfo);
entries = 0; entries = 0;
/* There is an entry for the offset to each virtual base. */ /* 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));
/* 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;
return size_int (entries); 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 /* Returns the offset (in bytes) from the beginning of BINFO's vtable
...@@ -2372,8 +2586,13 @@ build_vtbl_initializer (binfo, t) ...@@ -2372,8 +2586,13 @@ build_vtbl_initializer (binfo, t)
tree inits = NULL_TREE; tree inits = NULL_TREE;
tree type = BINFO_TYPE (binfo); 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. */ /* 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 /* 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 using vtable thunks, then the RTTI entry is just an ordinary
...@@ -2451,6 +2670,7 @@ dfs_finish_vtbls (binfo, data) ...@@ -2451,6 +2670,7 @@ dfs_finish_vtbls (binfo, data)
tree decl; tree decl;
tree context; tree context;
layout_vtable_decl (binfo, list_length (BINFO_VIRTUALS (binfo)));
decl = BINFO_VTABLE (binfo); decl = BINFO_VTABLE (binfo);
context = DECL_CONTEXT (decl); context = DECL_CONTEXT (decl);
DECL_CONTEXT (decl) = 0; DECL_CONTEXT (decl) = 0;
...@@ -2675,8 +2895,10 @@ modify_one_vtable (binfo, t, fndecl) ...@@ -2675,8 +2895,10 @@ modify_one_vtable (binfo, t, fndecl)
tree virtuals; tree virtuals;
unsigned HOST_WIDE_INT n; unsigned HOST_WIDE_INT n;
/* update rtti entry */ /* If we're support RTTI then we always need a new vtable to point
if (flag_rtti) 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)) if (binfo == TYPE_BINFO (t))
build_vtable (TYPE_BINFO (DECL_CONTEXT (TYPE_VFIELD (t))), t); build_vtable (TYPE_BINFO (DECL_CONTEXT (TYPE_VFIELD (t))), t);
...@@ -5010,32 +5232,7 @@ finish_struct_1 (t) ...@@ -5010,32 +5232,7 @@ finish_struct_1 (t)
/* Now lay out the virtual function table. */ /* Now lay out the virtual function table. */
if (has_virtual) if (has_virtual)
{ layout_vtable_decl (TYPE_BINFO (t), 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)));
}
}
/* If we created a new vtbl pointer for this class, add it to the /* If we created a new vtbl pointer for this class, add it to the
list. */ list. */
......
...@@ -213,6 +213,11 @@ extern int flag_rtti; ...@@ -213,6 +213,11 @@ extern int flag_rtti;
stored in the object itself. */ stored in the object itself. */
#define vbase_offsets_in_vtable_p() (flag_new_abi) #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, /* 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, even if a non-primary base class already has one. For example,
given: given:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment