aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2000-01-16 16:59:44 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2000-01-16 16:59:44 +0000
commit70ae32012466e09d67dd4eed3f74ea74f9c2629e (patch)
tree474362df55656c988b876cb23e1ad22cf0bc2401
parent2f4facc91eb1b0917f951bb0ff2571ed24d66e08 (diff)
downloadgcc-70ae32012466e09d67dd4eed3f74ea74f9c2629e.zip
gcc-70ae32012466e09d67dd4eed3f74ea74f9c2629e.tar.gz
gcc-70ae32012466e09d67dd4eed3f74ea74f9c2629e.tar.bz2
cp-tree.h (num_extra_vtbl_entries): New function.
* cp-tree.h (num_extra_vtbl_entries): New function. (size_extra_vtbl_entries): Likewise. (dfs_vtable_path_unmark): Likewise. (dfs_vtable_path_unmarked_real_bases_queue_p): Likewise. (dfs_vtable_path_marked_real_bases_queue_p): Likewise. * class.c (num_extra_vtbl_entries): New function. (size_extra_vtbl_entries): Likewise. (dfs_build_vbase_offset_vtbl_entries): New function. (build_vbase_offset_vtbl_entries): Likewise. (build_vtbl_initializer): Use it. (finish_struct_1): Adjust vtable sizes (using num_extra_vtbl_entries). * expr.c (cplus_expand_expr): Assert that the DECL_RTL for a THUNK_DECL is non-NULL before expanding it. * init.c (expand_virtual_init): Adjust the vtable pointer by size_extra_vtbl_entries before storing it. * search.c (get_shared_vase_if_not_primary): Adjust prototype. Handle TREE_LIST parameters here, not in the dfs_* functions. (dfs_unmarked_real_bases_queue_p): Adjust. (dfs_marked_real_bases_queue_p): Likewise. (dfs_vtable_path_unmarked_real_bases_queue_p): New function. (dfs_vtable_path_marked_real_bases_queue_p): New function. (dfs_vtable_path_unmark): Likewise. From-SVN: r31439
-rw-r--r--gcc/cp/ChangeLog26
-rw-r--r--gcc/cp/class.c163
-rw-r--r--gcc/cp/cp-tree.h7
-rw-r--r--gcc/cp/expr.c3
-rw-r--r--gcc/cp/init.c13
-rw-r--r--gcc/cp/search.c62
6 files changed, 247 insertions, 27 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 372f618..8915d02 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,29 @@
+2000-01-15 Mark Mitchell <mark@codesourcery.com>
+
+ * cp-tree.h (num_extra_vtbl_entries): New function.
+ (size_extra_vtbl_entries): Likewise.
+ (dfs_vtable_path_unmark): Likewise.
+ (dfs_vtable_path_unmarked_real_bases_queue_p): Likewise.
+ (dfs_vtable_path_marked_real_bases_queue_p): Likewise.
+ * class.c (num_extra_vtbl_entries): New function.
+ (size_extra_vtbl_entries): Likewise.
+ (dfs_build_vbase_offset_vtbl_entries): New function.
+ (build_vbase_offset_vtbl_entries): Likewise.
+ (build_vtbl_initializer): Use it.
+ (finish_struct_1): Adjust vtable sizes (using
+ num_extra_vtbl_entries).
+ * expr.c (cplus_expand_expr): Assert that the DECL_RTL for a
+ THUNK_DECL is non-NULL before expanding it.
+ * init.c (expand_virtual_init): Adjust the vtable pointer by
+ size_extra_vtbl_entries before storing it.
+ * search.c (get_shared_vase_if_not_primary): Adjust prototype.
+ Handle TREE_LIST parameters here, not in the dfs_* functions.
+ (dfs_unmarked_real_bases_queue_p): Adjust.
+ (dfs_marked_real_bases_queue_p): Likewise.
+ (dfs_vtable_path_unmarked_real_bases_queue_p): New function.
+ (dfs_vtable_path_marked_real_bases_queue_p): New function.
+ (dfs_vtable_path_unmark): Likewise.
+
2000-01-14 Mark Mitchell <mark@codesourcery.com>
* optimize.c (copy_body_r): Clear the operand three of a
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 23cd82c..2502b85 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -144,6 +144,8 @@ static void remove_base_field PROTO((tree, tree, tree *));
static void remove_base_fields PROTO((tree));
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));
/* Variables shared between class.c and call.c. */
@@ -2138,6 +2140,148 @@ duplicate_tag_error (t)
TYPE_NONCOPIED_PARTS (t) = NULL_TREE;
}
+/* Returns the number of extra entries (at negative indices) required
+ for BINFO's vtable. */
+
+tree
+num_extra_vtbl_entries (binfo)
+ tree binfo;
+{
+ tree type;
+ int entries;
+
+
+ /* Under the old ABI, there are no entries at negative offsets. */
+ if (!flag_new_abi)
+ 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));
+
+ return size_int (entries);
+}
+
+/* Returns the offset (in bytes) from the beginning of BINFO's vtable
+ where the vptr should actually point. */
+
+tree
+size_extra_vtbl_entries (binfo)
+ tree binfo;
+{
+ tree offset;
+
+ offset = size_binop (EXACT_DIV_EXPR,
+ TYPE_SIZE (vtable_entry_type),
+ size_int (BITS_PER_UNIT));
+ offset = size_binop (MULT_EXPR, offset, num_extra_vtbl_entries (binfo));
+ return fold (offset);
+}
+
+/* Called from build_vbase_offset_vtbl_entries via dfs_walk. */
+
+static tree
+dfs_build_vbase_offset_vtbl_entries (binfo, data)
+ tree binfo;
+ void *data;
+{
+ tree list = (tree) data;
+
+ if (TREE_TYPE (list) == binfo)
+ /* The TREE_TYPE of LIST is the base class from which we started
+ walking. If that BINFO is virtual it's not a virtual baseclass
+ of itself. */
+ ;
+ else if (TREE_VIA_VIRTUAL (binfo))
+ {
+ tree init;
+
+ init = BINFO_OFFSET (binfo);
+ init = build1 (NOP_EXPR, vtable_entry_type, init);
+ TREE_VALUE (list) = tree_cons (NULL_TREE, init, TREE_VALUE (list));
+ }
+
+ SET_BINFO_VTABLE_PATH_MARKED (binfo);
+
+ return NULL_TREE;
+}
+
+/* Returns the initializers for the vbase offset entries in the
+ vtable, in reverse order. */
+
+static tree
+build_vbase_offset_vtbl_entries (binfo)
+ tree binfo;
+{
+ tree type;
+ tree inits;
+ tree init;
+
+ type = BINFO_TYPE (binfo);
+ if (!TYPE_USES_VIRTUAL_BASECLASSES (type))
+ return NULL_TREE;
+
+ inits = NULL_TREE;
+
+ /* Under the new ABI, the vtable contains offsets to all virtual
+ bases. The ABI specifies different layouts depending on whether
+ or not *all* of the bases of this type are virtual. */
+ if (CLASSTYPE_N_BASECLASSES (type)
+ == list_length (CLASSTYPE_VBASECLASSES (type)))
+ {
+ /* In this case, the offsets are allocated from right to left of
+ the declaration order in which the virtual bases appear. */
+ int i;
+
+ for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
+ {
+ tree vbase = BINFO_BASETYPE (binfo, i);
+ init = BINFO_OFFSET (vbase);
+ init = build1 (NOP_EXPR, vtable_entry_type, init);
+ inits = tree_cons (NULL_TREE, init, inits);
+ }
+ }
+ else
+ {
+ tree list;
+
+ /* While in this case, the offsets are allocated in the reverse
+ order of a depth-first left-to-right traversal of the
+ hierarchy. We use BINFO_VTABLE_PATH_MARKED because we are
+ ourselves during a dfs_walk, and so BINFO_MARKED is already
+ in use. */
+ list = build_tree_list (type, NULL_TREE);
+ TREE_TYPE (list) = binfo;
+ dfs_walk (binfo,
+ dfs_build_vbase_offset_vtbl_entries,
+ dfs_vtable_path_unmarked_real_bases_queue_p,
+ list);
+ dfs_walk (binfo,
+ dfs_vtable_path_unmark,
+ dfs_vtable_path_marked_real_bases_queue_p,
+ list);
+ inits = nreverse (TREE_VALUE (list));
+ }
+
+ /* We've now got offsets in the right oder. 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))
+ {
+ tree exp = TREE_VALUE (init);
+
+ exp = ssize_binop (MINUS_EXPR, exp, BINFO_OFFSET (binfo));
+ exp = build1 (NOP_EXPR, vtable_entry_type, TREE_VALUE (init));
+ exp = fold (exp);
+ TREE_CONSTANT (exp) = 1;
+ TREE_VALUE (init) = exp;
+ }
+
+ return inits;
+}
+
/* Construct the initializer for BINFOs virtual function table. */
static tree
@@ -2146,13 +2290,16 @@ build_vtbl_initializer (binfo)
{
tree v = BINFO_VIRTUALS (binfo);
tree inits = NULL_TREE;
+ tree type = BINFO_TYPE (binfo);
+
+ if (flag_new_abi)
+ inits = build_vbase_offset_vtbl_entries (binfo);
/* 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
function, and we can process it just like the other virtual
function entries. */
- if (!CLASSTYPE_COM_INTERFACE (BINFO_TYPE (binfo))
- && flag_vtable_thunks)
+ if (!CLASSTYPE_COM_INTERFACE (type) && flag_vtable_thunks)
{
tree offset;
tree init;
@@ -4764,9 +4911,15 @@ finish_struct_1 (t)
if (has_virtual)
{
/* Use size_int so values are memoized in common cases. */
- tree itype = build_index_type (size_int (has_virtual));
- tree atype = build_cplus_array_type (vtable_entry_type, itype);
-
+ 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. */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8fe8f0b..2101cae 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3464,6 +3464,8 @@ extern void unreverse_member_declarations PROTO((tree));
extern void invalidate_class_lookup_cache PROTO((void));
extern void maybe_note_name_used_in_class PROTO((tree, tree));
extern void note_name_declared_in_class PROTO((tree, tree));
+extern tree num_extra_vtbl_entries PROTO((tree));
+extern tree size_extra_vtbl_entries PROTO((tree));
/* in cvt.c */
extern tree convert_to_reference PROTO((tree, tree, int, int, tree));
@@ -3961,12 +3963,17 @@ extern tree dfs_walk PROTO((tree,
void *));
extern tree dfs_unmark PROTO((tree, void *));
extern tree dfs_vbase_unmark PROTO((tree, void *));
+extern tree dfs_vtable_path_unmark PROTO((tree, void *));
extern tree markedp PROTO((tree, void *));
extern tree unmarkedp PROTO((tree, void *));
extern tree dfs_skip_nonprimary_vbases_unmarkedp PROTO((tree, void *));
extern tree dfs_skip_nonprimary_vbases_markedp PROTO((tree, void *));
extern tree dfs_unmarked_real_bases_queue_p PROTO((tree, void *));
extern tree dfs_marked_real_bases_queue_p PROTO((tree, void *));
+extern tree dfs_vtable_path_unmarked_real_bases_queue_p
+ PROTO((tree, void *));
+extern tree dfs_vtable_path_marked_real_bases_queue_p
+ PROTO((tree, void *));
extern tree dfs_skip_vbases PROTO((tree, void *));
extern void mark_primary_bases PROTO((tree));
extern tree convert_pointer_to_vbase PROTO((tree, tree));
diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c
index 2ac29f9..32838f4 100644
--- a/gcc/cp/expr.c
+++ b/gcc/cp/expr.c
@@ -1,6 +1,6 @@
/* Convert language-specific tree expression to rtl instructions,
for GNU compiler.
- Copyright (C) 1988, 92-97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1988, 92-97, 1998, 2000 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -131,6 +131,7 @@ cplus_expand_expr (exp, target, tmode, modifier)
}
case THUNK_DECL:
+ my_friendly_assert (DECL_RTL (exp) != NULL_RTX, 20000115);
return DECL_RTL (exp);
case THROW_EXPR:
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index ed2a3d7..12815e4 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -648,21 +648,26 @@ expand_virtual_init (binfo, decl)
tree vtbl, vtbl_ptr;
tree vtype, vtype_binfo;
- /* This code is crusty. Should be simple, like:
- vtbl = BINFO_VTABLE (binfo);
- */
+ /* Compute the location of the vtable. */
vtype = DECL_CONTEXT (TYPE_VFIELD (type));
vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0);
vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo));
assemble_external (vtbl);
TREE_USED (vtbl) = 1;
vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
+ /* Under the new ABI, we need to point into the middle of the
+ vtable. */
+ if (flag_new_abi)
+ vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
+ size_extra_vtbl_entries (binfo));
+
+ /* Compute the location of the vtpr. */
decl = convert_pointer_to_real (vtype_binfo, decl);
vtbl_ptr = build_vfield_ref (build_indirect_ref (decl, NULL_PTR), vtype);
if (vtbl_ptr == error_mark_node)
return;
- /* Have to convert VTBL since array sizes may be different. */
+ /* Assign the vtable to the vptr. */
vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
finish_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
}
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 1d6efed..697bf8b 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -150,7 +150,7 @@ static void setup_class_bindings PROTO ((tree, int));
static int template_self_reference_p PROTO ((tree, tree));
static void fixup_all_virtual_upcast_offsets PROTO ((tree, tree));
static tree dfs_mark_primary_bases PROTO((tree, void *));
-static tree get_shared_vbase_if_not_primary PROTO((tree, tree));
+static tree get_shared_vbase_if_not_primary PROTO((tree, void *));
static tree dfs_find_vbase_instance PROTO((tree, void *));
/* Allocate a level of searching. */
@@ -2240,12 +2240,17 @@ mark_primary_bases (type)
either a non-virtual base or a primary virtual base. */
static tree
-get_shared_vbase_if_not_primary (binfo, type)
+get_shared_vbase_if_not_primary (binfo, data)
tree binfo;
- tree type;
+ void *data;
{
if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
{
+ tree type = (tree) data;
+
+ if (TREE_CODE (type) == TREE_LIST)
+ type = TREE_PURPOSE (type);
+
/* This is a non-primary virtual base. If there is no primary
version, get the shared version. */
binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), type);
@@ -2271,11 +2276,7 @@ dfs_unmarked_real_bases_queue_p (binfo, data)
tree binfo;
void *data;
{
- tree type = (tree) data;
-
- if (TREE_CODE (type) == TREE_LIST)
- type = TREE_PURPOSE (type);
- binfo = get_shared_vbase_if_not_primary (binfo, type);
+ binfo = get_shared_vbase_if_not_primary (binfo, data);
return binfo ? unmarkedp (binfo, NULL) : NULL_TREE;
}
@@ -2287,14 +2288,34 @@ dfs_marked_real_bases_queue_p (binfo, data)
tree binfo;
void *data;
{
- tree type = (tree) data;
-
- if (TREE_CODE (type) == TREE_LIST)
- type = TREE_PURPOSE (type);
- binfo = get_shared_vbase_if_not_primary (binfo, type);
+ binfo = get_shared_vbase_if_not_primary (binfo, data);
return binfo ? markedp (binfo, NULL) : NULL_TREE;
}
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+ that are not BINFO_VTABLE_PATH_MARKED. */
+
+tree
+dfs_vtable_path_unmarked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ binfo = get_shared_vbase_if_not_primary (binfo, data);
+ return binfo ? unmarked_vtable_pathp (binfo, NULL): NULL_TREE;
+}
+
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+ that are BINFO_VTABLE_PATH_MARKED. */
+
+tree
+dfs_vtable_path_marked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ binfo = get_shared_vbase_if_not_primary (binfo, data);
+ return binfo ? marked_vtable_pathp (binfo, NULL): NULL_TREE;
+}
+
/* A queue function that skips all virtual bases (and their
bases). */
@@ -2546,16 +2567,23 @@ dfs_vbase_unmark (binfo, data)
return dfs_unmark (binfo, data);
}
+/* Clear BINFO_VTABLE_PATH_MARKED. */
+
+tree
+dfs_vtable_path_unmark (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
+ return NULL_TREE;
+}
+
#if 0
static void
dfs_mark_vtable_path (binfo) tree binfo;
{ SET_BINFO_VTABLE_PATH_MARKED (binfo); }
static void
-dfs_unmark_vtable_path (binfo) tree binfo;
-{ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); }
-
-static void
dfs_mark_new_vtable (binfo) tree binfo;
{ SET_BINFO_NEW_VTABLE_MARKED (binfo); }