mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-07 22:57:26 +08:00
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:
parent
0534b8047e
commit
1a588ad752
@ -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
|
||||
|
269
gcc/cp/class.c
269
gcc/cp/class.c
@ -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. */
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user