summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2000-01-25 23:26:21 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2000-01-25 23:26:21 +0000
commit1a588ad7522098037aaa4b5989824dfc2e1dd5a9 (patch)
treeac98c635afddd4791e9c8c208dfa2a653df0b4a1
parent0534b8047e8a12c4748f70a7bbb3267319c21216 (diff)
downloadgcc-1a588ad7522098037aaa4b5989824dfc2e1dd5a9.tar.gz
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
-rw-r--r--gcc/cp/ChangeLog16
-rw-r--r--gcc/cp/class.c269
-rw-r--r--gcc/cp/cp-tree.h5
3 files changed, 254 insertions, 36 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0b5c2ff527c..97231fb77af 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index aaa90cc429e..0085052d302 100644
--- a/gcc/cp/class.c
+++ b/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));
+
+ /* 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
@@ -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. */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 564cbe36bc2..0d83576c922 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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: