diff options
author | Mark Mitchell <mark@codesourcery.com> | 2000-06-23 01:14:40 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2000-06-23 01:14:40 +0000 |
commit | 31f8e4f306e9ef25c534afb1601fb9547801ae90 (patch) | |
tree | d353106ea48473adbbbe826b110e6044aa4595b7 | |
parent | 11fc1858a0850253a8487eae391b9ea3fd24ea5d (diff) | |
download | gcc-31f8e4f306e9ef25c534afb1601fb9547801ae90.zip gcc-31f8e4f306e9ef25c534afb1601fb9547801ae90.tar.gz gcc-31f8e4f306e9ef25c534afb1601fb9547801ae90.tar.bz2 |
cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
* cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
(BV_GENERATE_THUNK_WITH_VTABLE_P): Likewise.
(lang_decl_flags): Add generate_with_vtable_p. Make vcall_offset
a tree, not an int.
(THUNK_GENERATE_WITH_VTABLE_P): New macro.
(make_thunk): Change prototype.
(emit_thunk): Rename to use_thunk.
(mangle_thunk): Change prototype.
* class.c (get_derived_offset): Simplify.
(copy_virtuals): Clear BV_USE_VCALL_INDEX_P and
BV_GENERATE_THUNK_WITH_VTABLE_P.
(build_primary_vtable): Simplify.
(add_virtual_function): Use BV_FN, rather than TREE_VALUE.
(dfs_find_base): Remove.
(update_vtable_entry_for_fn): Correct bug in finding the base
where a virtual function was first declared. Figure out whether
or not to emit a vcall-thunk with the vtables in which it appears.
Correct logic for deciding whether to use an ordinary thunk, or a
vcall thunk.
(finish_struct_1): Remove unnecssary code.
(build_vtbl_initializer): Use ssize_int for the running counter of
negative indices.
(build_vtbl_initializer): Only use vcall thunks where necessary.
Mark thunks as needing to be emitted with their vtables, or not.
(build_vbase_offset_vtbl_entries): Adjust for use of ssize_int in
indices. Use size_binop.
(dfs_build_vcall_offset_vtbl_entries): Don't rely on
BINFO_PRIMARY_MARKED_P here. Use BV_FN consistently. Use
size_binop.
(build_rtti_vtbl_entries): Adjust call to build_vtable_entry.
(build_vtable_entry): Mark thunks as needing to be emitted with
their vtables, or not.
* decl.c (lang_mark_tree): Mark the vcall_offset in a thunk.
* decl2.c (mark_vtable_entries): Use use_thunk instead of
emit_thunk.
* dump.c (dequeue_and_dump): Remove dead code. Dump new thunk
information.
* error.c (dump_expr): Use BV_FN.
* mangle.c (mangle_thunk): Adjust now that vcall_offset is a tree,
not an int.
* method.c (make_thunk): Likewise.
(emit_thunk): Rename to use_thunk. Allow callers to decide
whether or not to actually emit the thunk. Adjust for changes in
representation of vcall offsets.
* search.c (dfs_get_pure_virtuals): Use BV_FN.
* semantics.c (emit_associated_thunks): New function.
(expand_body): Use it.
* ir.texi: Adjust decriptions of thunks.
From-SVN: r34656
-rw-r--r-- | gcc/cp/ChangeLog | 51 | ||||
-rw-r--r-- | gcc/cp/class.c | 208 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 30 | ||||
-rw-r--r-- | gcc/cp/decl.c | 2 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 11 | ||||
-rw-r--r-- | gcc/cp/dump.c | 13 | ||||
-rw-r--r-- | gcc/cp/error.c | 2 | ||||
-rw-r--r-- | gcc/cp/ir.texi | 4 | ||||
-rw-r--r-- | gcc/cp/mangle.c | 12 | ||||
-rw-r--r-- | gcc/cp/method.c | 86 | ||||
-rw-r--r-- | gcc/cp/search.c | 6 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 51 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/virtual8.C | 31 |
13 files changed, 356 insertions, 151 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1f655b3..0cebeac 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,54 @@ +2000-06-22 Mark Mitchell <mark@codesourcery.com> + + * cp-tree.h (BV_USE_VCALL_INDEX_P): New macro. + (BV_GENERATE_THUNK_WITH_VTABLE_P): Likewise. + (lang_decl_flags): Add generate_with_vtable_p. Make vcall_offset + a tree, not an int. + (THUNK_GENERATE_WITH_VTABLE_P): New macro. + (make_thunk): Change prototype. + (emit_thunk): Rename to use_thunk. + (mangle_thunk): Change prototype. + * class.c (get_derived_offset): Simplify. + (copy_virtuals): Clear BV_USE_VCALL_INDEX_P and + BV_GENERATE_THUNK_WITH_VTABLE_P. + (build_primary_vtable): Simplify. + (add_virtual_function): Use BV_FN, rather than TREE_VALUE. + (dfs_find_base): Remove. + (update_vtable_entry_for_fn): Correct bug in finding the base + where a virtual function was first declared. Figure out whether + or not to emit a vcall-thunk with the vtables in which it appears. + Correct logic for deciding whether to use an ordinary thunk, or a + vcall thunk. + (finish_struct_1): Remove unnecssary code. + (build_vtbl_initializer): Use ssize_int for the running counter of + negative indices. + (build_vtbl_initializer): Only use vcall thunks where necessary. + Mark thunks as needing to be emitted with their vtables, or not. + (build_vbase_offset_vtbl_entries): Adjust for use of ssize_int in + indices. Use size_binop. + (dfs_build_vcall_offset_vtbl_entries): Don't rely on + BINFO_PRIMARY_MARKED_P here. Use BV_FN consistently. Use + size_binop. + (build_rtti_vtbl_entries): Adjust call to build_vtable_entry. + (build_vtable_entry): Mark thunks as needing to be emitted with + their vtables, or not. + * decl.c (lang_mark_tree): Mark the vcall_offset in a thunk. + * decl2.c (mark_vtable_entries): Use use_thunk instead of + emit_thunk. + * dump.c (dequeue_and_dump): Remove dead code. Dump new thunk + information. + * error.c (dump_expr): Use BV_FN. + * mangle.c (mangle_thunk): Adjust now that vcall_offset is a tree, + not an int. + * method.c (make_thunk): Likewise. + (emit_thunk): Rename to use_thunk. Allow callers to decide + whether or not to actually emit the thunk. Adjust for changes in + representation of vcall offsets. + * search.c (dfs_get_pure_virtuals): Use BV_FN. + * semantics.c (emit_associated_thunks): New function. + (expand_body): Use it. + * ir.texi: Adjust decriptions of thunks. + 2000-06-22 Jason Merrill <jason@redhat.com> * pt.c (tsubst_decl, case FUNCTION_DECL): Clear DECL_SAVED_TREE. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 387451c..71a5aef 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -96,7 +96,7 @@ varray_type local_classes; static tree get_vfield_name PARAMS ((tree)); static void finish_struct_anon PARAMS ((tree)); static tree build_vbase_pointer PARAMS ((tree, tree)); -static tree build_vtable_entry PARAMS ((tree, tree, tree)); +static tree build_vtable_entry PARAMS ((tree, tree, tree, int)); static tree get_vtable_name PARAMS ((tree)); static tree get_derived_offset PARAMS ((tree, tree)); static tree get_basefndecls PARAMS ((tree, tree)); @@ -162,7 +162,6 @@ static void build_vcall_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *)) static void layout_vtable_decl PARAMS ((tree, int)); static tree dfs_find_final_overrider PARAMS ((tree, void *)); static tree find_final_overrider PARAMS ((tree, tree, tree)); -static tree dfs_find_base PARAMS ((tree, void *)); static int make_new_vtable PARAMS ((tree, tree)); static void dump_class_hierarchy_r PARAMS ((tree, tree, int)); extern void dump_class_hierarchy PARAMS ((tree)); @@ -685,16 +684,9 @@ get_derived_offset (binfo, type) { tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo))); tree offset2; - int i; - while (BINFO_BASETYPES (binfo) - && (i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1) - { - tree binfos = BINFO_BASETYPES (binfo); - if (BINFO_TYPE (binfo) == type) - break; - binfo = TREE_VEC_ELT (binfos, i); - } + while (!same_type_p (BINFO_TYPE (binfo), type)) + binfo = BINFO_PRIMARY_BINFO (binfo); offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo))); return size_binop (MINUS_EXPR, offset1, offset2); @@ -778,7 +770,11 @@ copy_virtuals (binfo) copies = copy_list (BINFO_VIRTUALS (binfo)); for (t = copies; t; t = TREE_CHAIN (t)) - BV_VCALL_INDEX (t) = NULL_TREE; + { + BV_VCALL_INDEX (t) = NULL_TREE; + BV_USE_VCALL_INDEX_P (t) = 0; + BV_GENERATE_THUNK_WITH_VTABLE_P (t) = 0; + } return copies; } @@ -793,7 +789,8 @@ static int build_primary_vtable (binfo, type) tree binfo, type; { - tree virtuals, decl; + tree decl; + tree virtuals; decl = get_vtable_decl (type, /*complete=*/0); @@ -825,9 +822,7 @@ build_primary_vtable (binfo, type) on our first approximation. */ TYPE_BINFO_VTABLE (type) = decl; TYPE_BINFO_VIRTUALS (type) = virtuals; - - binfo = TYPE_BINFO (type); - SET_BINFO_NEW_VTABLE_MARKED (binfo, type); + SET_BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (type), type); return 1; } @@ -1126,7 +1121,8 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p, /* We've already dealt with this function. */ return; - new_virtual = build_tree_list (NULL_TREE, fndecl); + new_virtual = make_node (TREE_LIST); + BV_FN (new_virtual) = fndecl; BV_DELTA (new_virtual) = integer_zero_node; if (DECL_VINDEX (fndecl) == error_mark_node) @@ -2590,18 +2586,6 @@ find_final_overrider (t, binfo, fn) return build_tree_list (ffod.overriding_fn, ffod.overriding_base); } -/* Called via dfs_walk. Returns BINFO if BINFO has the same type as - DATA (which is really an _TYPE node). */ - -static tree -dfs_find_base (binfo, data) - tree binfo; - void *data; -{ - return (same_type_p (BINFO_TYPE (binfo), (tree) data) - ? binfo : NULL_TREE); -} - /* Update a entry in the vtable for BINFO, which is in the hierarchy dominated by T. FN has been overridden in BINFO; VIRTUALS points to the corresponding position in the BINFO_VIRTUALS list. */ @@ -2615,26 +2599,36 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) { tree b; tree overrider; - tree vindex; tree delta; - HOST_WIDE_INT vindex_val; - HOST_WIDE_INT i; + tree virtual_base; + int generate_thunk_with_vtable_p; /* Find the function which originally caused this vtable entry to be present. */ - vindex = DECL_VINDEX (fn); - b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn)); - fn = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (b))); - i = first_vfun_index (BINFO_TYPE (b)); - vindex_val = tree_low_cst (vindex, 0); - while (i < vindex_val) + b = binfo; + while (1) { - fn = TREE_CHAIN (fn); - ++i; + tree primary_base; + tree f; + + primary_base = BINFO_PRIMARY_BINFO (b); + if (!primary_base) + break; + + for (f = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (primary_base))); + f; + f = TREE_CHAIN (f)) + if (same_signature_p (BV_FN (f), fn)) + break; + + if (!f) + break; + + fn = BV_FN (f); + b = primary_base; } - fn = BV_FN (fn); - /* Handle the case of a virtual function defined in BINFO itself. */ + /* Find the final overrider. */ overrider = find_final_overrider (t, b, fn); if (overrider == error_mark_node) return; @@ -2646,27 +2640,53 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) get_derived_offset (binfo, DECL_VIRTUAL_CONTEXT (fn)), BINFO_OFFSET (binfo)); + + /* Assume that we will produce a thunk that convert all the way to + the final overrider, and not to an intermediate virtual base. */ + virtual_base = NULL_TREE; + + /* Assume that we will always generate thunks with the vtables that + reference them. */ + generate_thunk_with_vtable_p = 1; + + /* Under the new ABI, we will convert to an intermediate virtual + base first, and then use the vcall offset located there to finish + the conversion. */ if (flag_new_abi) { - /* Under the new ABI, we only need to adjust as far as the - nearest virtual base. Then we use the vcall offset in the - virtual bases vtable. */ - for (b = binfo; b; b = BINFO_INHERITANCE_CHAIN (b)) + while (b) { - if (TREE_VIA_VIRTUAL (b)) - break; + /* If we find BINFO, then the final overrider is in a class + derived from BINFO, so the thunks can be generated with + the final overrider. */ + if (same_type_p (BINFO_TYPE (b), BINFO_TYPE (binfo))) + generate_thunk_with_vtable_p = 0; + + /* If we find the final overrider, then we can stop + walking. */ if (same_type_p (BINFO_TYPE (b), BINFO_TYPE (TREE_VALUE (overrider)))) break; + + /* If we find a virtual base, and we haven't yet found the + overrider, then there is a virtual base between the + declaring base and the final overrider. */ + if (!virtual_base && TREE_VIA_VIRTUAL (b)) + { + generate_thunk_with_vtable_p = 1; + virtual_base = b; + } + + b = BINFO_INHERITANCE_CHAIN (b); } } else - b = NULL_TREE; + virtual_base = NULL_TREE; - if (b && TREE_VIA_VIRTUAL (b)) + if (virtual_base) /* The `this' pointer needs to be adjusted to the nearest virtual base. */ - delta = size_diffop (BINFO_OFFSET (b), delta); + delta = size_diffop (BINFO_OFFSET (virtual_base), delta); else /* The `this' pointer needs to be adjusted from pointing to BINFO to pointing at the base where the final overrider @@ -2678,6 +2698,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) TREE_PURPOSE (overrider), delta, virtuals); + + if (virtual_base) + BV_USE_VCALL_INDEX_P (*virtuals) = 1; + if (generate_thunk_with_vtable_p) + BV_GENERATE_THUNK_WITH_VTABLE_P (*virtuals) = 1; } /* Called from modify_all_vtables via dfs_walk. */ @@ -5074,17 +5099,9 @@ finish_struct_1 (t) { tree binfo = CLASSTYPE_PRIMARY_BINFO (t); - /* This class contributes nothing new to the virtual function - table. However, it may have declared functions which - went into the virtual function table "inherited" from the - base class. If so, we grab a copy of those updated functions, - and pretend they are ours. */ - - /* See if we should steal the virtual info from base class. */ - if (TYPE_BINFO_VTABLE (t) == NULL_TREE) - TYPE_BINFO_VTABLE (t) = BINFO_VTABLE (binfo); - if (TYPE_BINFO_VIRTUALS (t) == NULL_TREE) - TYPE_BINFO_VIRTUALS (t) = BINFO_VIRTUALS (binfo); + /* If this class uses a different vtable than its primary base + then when we will need to initialize our vptr after the base + class constructor runs. */ if (TYPE_BINFO_VTABLE (t) != BINFO_VTABLE (binfo)) CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1; } @@ -6992,7 +7009,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) vod.last_init = &vod.inits; vod.primary_p = (binfo == TYPE_BINFO (t)); /* The first vbase or vcall offset is at index -3 in the vtable. */ - vod.index = build_int_2 (-3, -1); + vod.index = ssize_int (-3); /* Add entries to the vtable for RTTI. */ build_rtti_vtbl_entries (binfo, rtti_binfo, &vod); @@ -7023,7 +7040,15 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) /* Pull the offset for `this', and the function to call, out of the list. */ delta = BV_DELTA (v); - vcall_index = BV_VCALL_INDEX (v); + + if (BV_USE_VCALL_INDEX_P (v)) + { + vcall_index = BV_VCALL_INDEX (v); + my_friendly_assert (vcall_index != NULL_TREE, 20000621); + } + else + vcall_index = NULL_TREE; + fn = BV_FN (v); my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727); my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727); @@ -7039,7 +7064,8 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) /* The address of a function can't change. */ TREE_CONSTANT (pfn) = 1; /* Enter it in the vtable. */ - init = build_vtable_entry (delta, vcall_index, pfn); + init = build_vtable_entry (delta, vcall_index, pfn, + BV_GENERATE_THUNK_WITH_VTABLE_P (v)); /* And add it to the chain of initializers. */ vfun_inits = tree_cons (NULL_TREE, init, vfun_inits); } @@ -7125,7 +7151,7 @@ build_vbase_offset_vtbl_entries (binfo, vod) /* Figure out where we can find this vbase offset. */ delta = size_binop (MULT_EXPR, - convert (ssizetype, vod->index), + vod->index, convert (ssizetype, TYPE_SIZE_UNIT (vtable_entry_type))); if (vod->primary_p) @@ -7146,8 +7172,7 @@ build_vbase_offset_vtbl_entries (binfo, vod) } /* The next vbase will come at a more negative offset. */ - vod->index = fold (build (MINUS_EXPR, integer_type_node, - vod->index, integer_one_node)); + vod->index = size_binop (MINUS_EXPR, vod->index, ssize_int (1)); /* The initializer is the delta from BINFO to this virtual base. The vbase offsets go in reverse inheritance-graph order, and @@ -7174,8 +7199,11 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) tree derived_virtuals; tree base_virtuals; tree binfo_inits; + /* If BINFO is a primary base, this is the least derived class of + BINFO that is not a primary base. */ tree non_primary_binfo; - tree b; + /* The primary base of BINFO. */ + tree primary_binfo; int i; vod = (vcall_offset_data *) data; @@ -7185,16 +7213,21 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) hierarchy until we find the class of which we are a primary base: it is the BINFO_VIRTUALS there that we need to consider. */ non_primary_binfo = binfo; - while (BINFO_PRIMARY_MARKED_P (non_primary_binfo)) - non_primary_binfo = BINFO_INHERITANCE_CHAIN (non_primary_binfo); + while (BINFO_INHERITANCE_CHAIN (non_primary_binfo)) + { + tree b = BINFO_INHERITANCE_CHAIN (non_primary_binfo); + if (BINFO_PRIMARY_BINFO (b) != non_primary_binfo) + break; + non_primary_binfo = b; + } /* Skip virtuals that we have already handled in a primary base class. */ base_virtuals = BINFO_VIRTUALS (binfo); derived_virtuals = BINFO_VIRTUALS (non_primary_binfo); - b = BINFO_PRIMARY_BINFO (binfo); - if (b) - for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i) + primary_binfo = BINFO_PRIMARY_BINFO (binfo); + if (primary_binfo) + for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (primary_binfo)); ++i) { base_virtuals = TREE_CHAIN (base_virtuals); derived_virtuals = TREE_CHAIN (derived_virtuals); @@ -7206,7 +7239,7 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) base_virtuals = TREE_CHAIN (base_virtuals)) { /* Figure out what function we're looking at. */ - tree fn = TREE_VALUE (derived_virtuals); + tree fn = BV_FN (derived_virtuals); tree base; tree base_binfo; size_t i; @@ -7220,7 +7253,7 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) tree derived_entry; derived_entry = VARRAY_TREE (vod->fns, i); - if (same_signature_p (TREE_VALUE (derived_entry), fn)) + if (same_signature_p (BV_FN (derived_entry), fn)) { BV_VCALL_INDEX (derived_virtuals) = BV_VCALL_INDEX (derived_entry); @@ -7259,8 +7292,7 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) /* The next vcall offset will be found at a more negative offset. */ - vod->index = fold (build (MINUS_EXPR, integer_type_node, - vod->index, integer_one_node)); + vod->index = size_binop (MINUS_EXPR, vod->index, ssize_int (1)); /* Keep track of this function. */ VARRAY_PUSH_TREE (vod->fns, derived_virtuals); @@ -7383,7 +7415,8 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod) vtable. */ init = build1 (ADDR_EXPR, vfunc_ptr_type_node, decl); TREE_CONSTANT (init) = 1; - init = build_vtable_entry (offset, integer_zero_node, init); + init = build_vtable_entry (offset, NULL_TREE, init, + /*generate_with_vtable_p=*/0); } *vod->last_init = build_tree_list (NULL_TREE, init); vod->last_init = &TREE_CHAIN (*vod->last_init); @@ -7410,28 +7443,23 @@ build_rtti_vtbl_entries (binfo, rtti_binfo, vod) ABI.) */ static tree -build_vtable_entry (delta, vcall_index, entry) +build_vtable_entry (delta, vcall_index, entry, generate_with_vtable_p) tree delta; tree vcall_index; tree entry; + int generate_with_vtable_p; { - if (!vcall_index) - vcall_index = integer_zero_node; - if (flag_vtable_thunks) { - HOST_WIDE_INT idelta; - HOST_WIDE_INT ivindex; tree fn; - idelta = tree_low_cst (delta, 0); - ivindex = tree_low_cst (vcall_index, 0); fn = TREE_OPERAND (entry, 0); - if ((idelta || ivindex) + if ((!integer_zerop (delta) || vcall_index != NULL_TREE) && fn != abort_fndecl && !DECL_TINFO_FN_P (fn)) { - entry = make_thunk (entry, idelta, ivindex); + entry = make_thunk (entry, delta, vcall_index, + generate_with_vtable_p); entry = build1 (ADDR_EXPR, vtable_entry_type, entry); TREE_READONLY (entry) = 1; TREE_CONSTANT (entry) = 1; @@ -7449,7 +7477,7 @@ build_vtable_entry (delta, vcall_index, entry) tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems); /* We don't use vcall offsets when not using vtable thunks. */ - my_friendly_assert (integer_zerop (vcall_index), 20000125); + my_friendly_assert (vcall_index == NULL_TREE, 20000125); /* DELTA used to be constructed by `size_int' and/or size_binop, which caused overflow problems when it was negative. That should diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b93a29e..89e637e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -45,6 +45,7 @@ Boston, MA 02111-1307, USA. */ SCOPE_BEGIN_P (in SCOPE_STMT) CTOR_BEGIN_P (in CTOR_STMT) DECL_PRETTY_FUNCTION_P (in VAR_DECL) + BV_USE_VCALL_INDEX_P (in the BINFO_VIRTUALS TREE_LIST) 1: IDENTIFIER_VIRTUAL_P. TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. @@ -57,6 +58,7 @@ Boston, MA 02111-1307, USA. */ ICS_ELLIPSIS_FLAG (in _CONV) STMT_IS_FULL_EXPR_P (in _STMT) BINFO_ACCESS (in BINFO) + BV_GENERATE_THUNK_WITH_VTABLE_P (in TREE_LIST) 2: IDENTIFIER_OPNAME_P. TYPE_POLYMORHPIC_P (in _TYPE) ICS_THIS_FLAG (in _CONV) @@ -128,7 +130,9 @@ Boston, MA 02111-1307, USA. */ the this pointer points to an object of the base class. The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable - index of the vcall offset for this entry. + index of the vcall offset for this entry. If + BV_USE_VCALL_INDEX_P then the corresponding vtable entry should + use a virtual thunk, as opposed to an ordinary thunk. The BV_FN is the declaration for the virtual function itself. When CLASSTYPE_COM_INTERFACE_P does not hold, the first entry @@ -1841,6 +1845,15 @@ struct lang_type /* The function to call. */ #define BV_FN(NODE) (TREE_VALUE (NODE)) +/* Nonzero if we should use a virtual thunk for this entry. */ +#define BV_USE_VCALL_INDEX_P(NODE) \ + (TREE_LANG_FLAG_0 (NODE)) + +/* Nonzero if we should generate this thunk when the vtable that + references it is emitted, rather than with the final overrider. */ +#define BV_GENERATE_THUNK_WITH_VTABLE_P(NODE) \ + (TREE_LANG_FLAG_1 (NODE)) + /* The most derived class. */ @@ -1901,7 +1914,8 @@ struct lang_decl_flags unsigned tinfo_fn_p : 1; unsigned assignment_operator_p : 1; unsigned anticipated_p : 1; - unsigned dummy : 2; + unsigned generate_with_vtable_p : 1; + unsigned dummy : 1; tree context; @@ -1924,7 +1938,7 @@ struct lang_decl_flags /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is THUNK_VCALL_OFFSET. */ - HOST_WIDE_INT vcall_offset; + tree vcall_offset; } u2; }; @@ -3141,6 +3155,10 @@ extern int flag_new_for_scope; #define THUNK_VCALL_OFFSET(DECL) \ (DECL_LANG_SPECIFIC (DECL)->decl_flags.u2.vcall_offset) +/* Nonzero if this thunk should be generated with the vtable that + references it. */ +#define THUNK_GENERATE_WITH_VTABLE_P(DECL) \ + (DECL_LANG_SPECIFIC (DECL)->decl_flags.generate_with_vtable_p) /* These macros provide convenient access to the various _STMT nodes created when parsing template declarations. */ @@ -4244,8 +4262,8 @@ extern tree build_overload_with_type PARAMS ((tree, tree)); extern tree build_destructor_name PARAMS ((tree)); extern tree build_opfncall PARAMS ((enum tree_code, int, tree, tree, tree)); extern tree hack_identifier PARAMS ((tree, tree)); -extern tree make_thunk PARAMS ((tree, int, int)); -extern void emit_thunk PARAMS ((tree)); +extern tree make_thunk PARAMS ((tree, tree, tree, int)); +extern void use_thunk PARAMS ((tree, int)); extern void synthesize_method PARAMS ((tree)); extern tree get_id_2 PARAMS ((const char *, tree)); extern tree implicitly_declare_fn PARAMS ((special_function_kind, tree, int)); @@ -4718,7 +4736,7 @@ extern tree mangle_typeinfo_string_for_type PARAMS ((tree)); extern tree mangle_vtbl_for_type PARAMS ((tree)); extern tree mangle_vtt_for_type PARAMS ((tree)); extern tree mangle_ctor_vtbl_for_type PARAMS ((tree, tree)); -extern tree mangle_thunk PARAMS ((tree, int, int)); +extern tree mangle_thunk PARAMS ((tree, tree, tree)); extern tree mangle_conv_op_name_for_type PARAMS ((tree)); extern tree mangle_guard_variable PARAMS ((tree)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 5451306..10d9d08 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -15063,6 +15063,8 @@ lang_mark_tree (t) && !DECL_GLOBAL_DTOR_P (t) && !DECL_THUNK_P (t)) ggc_mark_tree (ld->decl_flags.u2.access); + else if (DECL_THUNK_P (t)) + ggc_mark_tree (ld->decl_flags.u2.vcall_offset); ggc_mark_tree (ld->decl_flags.context); if (TREE_CODE (t) != NAMESPACE_DECL) ggc_mark_tree (ld->decl_flags.u.template_info); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index b034d78..8fe160e 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2425,11 +2425,12 @@ mark_vtable_entries (decl) fn = TREE_OPERAND (fnaddr, 0); TREE_ADDRESSABLE (fn) = 1; - if (DECL_THUNK_P (fn) && DECL_EXTERNAL (fn)) - { - DECL_EXTERNAL (fn) = 0; - emit_thunk (fn); - } + /* When we don't have vcall offsets, we output thunks whenever + we output the vtables that contain them. With vcall offsets, + we know all the thunks we'll need when we emit a virtual + function, so we emit the thunks there instead. */ + if (DECL_THUNK_P (fn)) + use_thunk (fn, THUNK_GENERATE_WITH_VTABLE_P (fn)); mark_used (fn); } } diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c index ca3baa0..9b71106 100644 --- a/gcc/cp/dump.c +++ b/gcc/cp/dump.c @@ -566,7 +566,7 @@ dequeue_and_dump (di) dump_string(di, "extern"); else dump_string (di, "static"); - if (TREE_CODE (t) == FUNCTION_DECL) + if (!DECL_THUNK_P (t)) { if (DECL_FUNCTION_MEMBER_P (t)) dump_string (di, "member"); @@ -578,13 +578,6 @@ dequeue_and_dump (di) dump_string (di, "operator"); if (DECL_CONV_FN_P (t)) dump_string (di, "conversion"); - if (DECL_THUNK_P (t)) - { - dump_string (di, "thunk"); - dump_int (di, "dlta", THUNK_DELTA (t)); - dump_int (di, "vcll", THUNK_VCALL_OFFSET (t)); - dump_child ("fn", DECL_INITIAL (t)); - } if (DECL_GLOBAL_CTOR_P (t) || DECL_GLOBAL_DTOR_P (t)) { if (DECL_GLOBAL_CTOR_P (t)) @@ -600,8 +593,10 @@ dequeue_and_dump (di) } else { + dump_string (di, "thunk"); dump_int (di, "dlta", THUNK_DELTA (t)); - dump_child ("init", DECL_INITIAL (t)); + dump_child ("vcll", THUNK_VCALL_OFFSET (t)); + dump_child ("fn", DECL_INITIAL (t)); } break; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 8d2ad61..37c8dd6 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1867,7 +1867,7 @@ dump_expr (t, flags) } if (virtuals) { - dump_expr (TREE_VALUE (virtuals), + dump_expr (BV_FN (virtuals), flags | TS_EXPR_PARENS); break; } diff --git a/gcc/cp/ir.texi b/gcc/cp/ir.texi index 429c155..343dfc8 100644 --- a/gcc/cp/ir.texi +++ b/gcc/cp/ir.texi @@ -1040,8 +1040,8 @@ returning to the thunk. The first parameter to the thunk is always the value. (The @code{THUNK_DELTA} is an @code{int}, not an @code{INTEGER_CST}.) -Then, if @code{THUNK_VCALL_OFFSET} (also an @code{int}) is non-zero the -adjusted @code{this} pointer must be adjusted again. The complete +Then, if @code{THUNK_VCALL_OFFSET} (an @code{INTEGER_CST}) is non-zero +the adjusted @code{this} pointer must be adjusted again. The complete calculation is given by the following pseudo-code: @example diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index d6c7181..a1d1d55 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2076,7 +2076,7 @@ mangle_ctor_vtbl_for_type (type, binfo) /* Return an identifier for the mangled name of a thunk to FN_DECL. OFFSET is the initial adjustment to this used to find the vptr. If - VCALL_OFFSET is non-zero, this is a virtual thunk, and it is the + VCALL_OFFSET is non-NULL, this is a virtual thunk, and it is the vtbl offset in bytes. <special-name> ::= Th <offset number> _ <base encoding> @@ -2087,8 +2087,8 @@ mangle_ctor_vtbl_for_type (type, binfo) tree mangle_thunk (fn_decl, offset, vcall_offset) tree fn_decl; - int offset; - int vcall_offset; + tree offset; + tree vcall_offset; { const char *result; @@ -2104,14 +2104,14 @@ mangle_thunk (fn_decl, offset, vcall_offset) write_char ('h'); /* For either flavor, write the offset to this. */ - write_signed_number (offset); + write_integer_cst (offset); write_char ('_'); /* For a virtual thunk, add the vcall offset. */ - if (vcall_offset != 0) + if (vcall_offset) { /* Virtual thunk. Write the vcall offset and base type name. */ - write_signed_number (vcall_offset); + write_integer_cst (vcall_offset); write_char ('_'); } diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 04685d4..33ad29a 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -2063,15 +2063,29 @@ hack_identifier (value, name) DELTA is the offset to this and VCALL_INDEX is zero. */ tree -make_thunk (function, delta, vcall_index) +make_thunk (function, delta, vcall_index, generate_with_vtable_p) tree function; - int delta; - int vcall_index; + tree delta; + tree vcall_index; + int generate_with_vtable_p; { tree thunk_id; tree thunk; tree func_decl; - int vcall_offset = vcall_index * int_size_in_bytes (vtable_entry_type); + tree vcall_offset; + HOST_WIDE_INT d; + + /* Scale the VCALL_INDEX to be in terms of bytes. */ + if (vcall_index) + vcall_offset + = size_binop (MULT_EXPR, + vcall_index, + convert (ssizetype, + TYPE_SIZE_UNIT (vtable_entry_type))); + else + vcall_offset = NULL_TREE; + + d = tree_low_cst (delta, 0); if (TREE_CODE (function) != ADDR_EXPR) abort (); @@ -2080,22 +2094,23 @@ make_thunk (function, delta, vcall_index) abort (); if (flag_new_abi) - thunk_id = mangle_thunk (TREE_OPERAND (function, 0), delta, vcall_offset); + thunk_id = mangle_thunk (TREE_OPERAND (function, 0), + delta, vcall_offset); else { OB_INIT (); OB_PUTS ("__thunk_"); - if (delta > 0) + if (d > 0) { OB_PUTC ('n'); - icat (delta); + icat (d); } else - icat (-delta); + icat (-d); OB_PUTC ('_'); if (vcall_index) { - icat (vcall_index); + icat (tree_low_cst (vcall_index, 0)); OB_PUTC ('_'); } OB_PUTID (DECL_ASSEMBLER_NAME (func_decl)); @@ -2121,8 +2136,9 @@ make_thunk (function, delta, vcall_index) comdat_linkage (thunk); SET_DECL_THUNK_P (thunk); DECL_INITIAL (thunk) = function; - THUNK_DELTA (thunk) = delta; + THUNK_DELTA (thunk) = d; THUNK_VCALL_OFFSET (thunk) = vcall_offset; + THUNK_GENERATE_WITH_VTABLE_P (thunk) = generate_with_vtable_p; /* The thunk itself is not a constructor or destructor, even if the thing it is thunking to is. */ DECL_INTERFACE_KNOWN (thunk) = 1; @@ -2142,6 +2158,8 @@ make_thunk (function, delta, vcall_index) DECL_DEFERRED_FN (thunk) = 0; /* So that finish_file can write out any thunks that need to be: */ pushdecl_top_level (thunk); + /* Create RTL for this thunk so that its address can be taken. */ + make_function_rtl (thunk); } return thunk; } @@ -2149,17 +2167,20 @@ make_thunk (function, delta, vcall_index) /* Emit the definition of a C++ multiple inheritance vtable thunk. */ void -emit_thunk (thunk_fndecl) +use_thunk (thunk_fndecl, emit_p) tree thunk_fndecl; + int emit_p; + { tree fnaddr; tree function; - int delta; - int vcall_offset; + tree vcall_offset; + HOST_WIDE_INT delta; if (TREE_ASM_WRITTEN (thunk_fndecl)) return; - + + fnaddr = DECL_INITIAL (thunk_fndecl); if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR) /* We already turned this thunk into an ordinary function. There's no need to process this thunk again. (We can't just @@ -2167,16 +2188,25 @@ emit_thunk (thunk_fndecl) FNADDR_FROM_VTABLE_ENTRY and friends.) */ return; - fnaddr = DECL_INITIAL (thunk_fndecl); - function = TREE_OPERAND (fnaddr, 0); - delta = THUNK_DELTA (thunk_fndecl); - vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl); + /* Thunks are always addressable; they only appear in vtables. */ + TREE_ADDRESSABLE (thunk_fndecl) = 1; + /* Figure out what function is being thunked to. It's referenced in + this translation unit. */ + function = TREE_OPERAND (fnaddr, 0); TREE_ADDRESSABLE (function) = 1; mark_used (function); + TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1; + if (!emit_p) + return; - if (current_function_decl) - abort (); + delta = THUNK_DELTA (thunk_fndecl); + vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl); + + /* And, if we need to emit the thunk, it's used. */ + mark_used (thunk_fndecl); + /* This thunk is actually defined. */ + DECL_EXTERNAL (thunk_fndecl) = 0; if (flag_syntax_only) { @@ -2184,14 +2214,13 @@ emit_thunk (thunk_fndecl) return; } + push_to_top_level (); + #ifdef ASM_OUTPUT_MI_THUNK - if (vcall_offset == 0) + if (!vcall_offset) { const char *fnname; current_function_decl = thunk_fndecl; - /* Make sure we build up its RTL before we go onto the - temporary obstack. */ - make_function_rtl (thunk_fndecl); DECL_RESULT (thunk_fndecl) = build_decl (RESULT_DECL, 0, integer_type_node); fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0); @@ -2230,17 +2259,15 @@ emit_thunk (thunk_fndecl) DECL_ARGUMENTS (thunk_fndecl) = a; DECL_RESULT (thunk_fndecl) = NULL_TREE; - push_to_top_level (); start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED); store_parm_decls (); /* Adjust the this pointer by the constant. */ t = ssize_int (delta); - TREE_TYPE (t) = signed_type (sizetype); t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t)); /* If there's a vcall offset, look up that value in the vtable and adjust the `this' pointer again. */ - if (vcall_offset != 0) + if (!integer_zerop (vcall_offset)) { tree orig_this; @@ -2254,7 +2281,7 @@ emit_thunk (thunk_fndecl) /* Form the vtable address. */ t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t); /* Find the entry with the vcall offset. */ - t = build (PLUS_EXPR, TREE_TYPE (t), t, ssize_int (vcall_offset)); + t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset); /* Calculate the offset itself. */ t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t); /* Adjust the `this' pointer. */ @@ -2281,8 +2308,9 @@ emit_thunk (thunk_fndecl) BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = DECL_ARGUMENTS (thunk_fndecl); expand_body (finish_function (0)); - pop_from_top_level (); } + + pop_from_top_level (); } /* Code for synthesizing methods which have default semantics defined. */ diff --git a/gcc/cp/search.c b/gcc/cp/search.c index efb8e6a..78fb5a4 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -2295,9 +2295,9 @@ dfs_get_pure_virtuals (binfo, data) for (virtuals = BINFO_VIRTUALS (binfo); virtuals; virtuals = TREE_CHAIN (virtuals)) - if (DECL_PURE_VIRTUAL_P (TREE_VALUE (virtuals))) + if (DECL_PURE_VIRTUAL_P (BV_FN (virtuals))) CLASSTYPE_PURE_VIRTUALS (type) - = tree_cons (NULL_TREE, TREE_VALUE (virtuals), + = tree_cons (NULL_TREE, BV_FN (virtuals), CLASSTYPE_PURE_VIRTUALS (type)); } @@ -2341,7 +2341,7 @@ get_pure_virtuals (type) virtuals; virtuals = TREE_CHAIN (virtuals)) { - tree base_fndecl = TREE_VALUE (virtuals); + tree base_fndecl = BV_FN (virtuals); if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl)) cp_error ("`%#D' needs a final overrider", base_fndecl); } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 5cebea6..68dac42 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -50,6 +50,7 @@ static tree expand_cond PARAMS ((tree)); static tree maybe_convert_cond PARAMS ((tree)); static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *)); static void deferred_type_access_control PARAMS ((void)); +static void emit_associated_thunks PARAMS ((tree)); /* Record the fact that STMT was the last statement added to the statement tree. */ @@ -2962,6 +2963,53 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data) return NULL_TREE; } +/* Emit all thunks to FN that should be emitted when FN is emitted. */ + +static void +emit_associated_thunks (fn) + tree fn; +{ + /* When we use vcall offsets, we emit thunks with the virtual + functions to which they thunk. The whole point of vcall offsets + is so that you can know statically the entire set of thunks that + will ever be needed for a given virtual function, thereby + enabling you to output all the thunks with the function itself. */ + if (vcall_offsets_in_vtable_p () && DECL_VIRTUAL_P (fn)) + { + tree binfo; + tree v; + + for (binfo = TYPE_BINFO (DECL_CONTEXT (fn)); + binfo; + binfo = TREE_CHAIN (binfo)) + for (v = BINFO_VIRTUALS (binfo); v; v = TREE_CHAIN (v)) + if (BV_FN (v) == fn + && (!integer_zerop (BV_DELTA (v)) + || BV_VCALL_INDEX (v))) + { + tree thunk; + tree vcall_index; + + if (BV_USE_VCALL_INDEX_P (v)) + { + vcall_index = BV_VCALL_INDEX (v); + my_friendly_assert (vcall_index != NULL_TREE, 20000621); + } + else + vcall_index = NULL_TREE; + + thunk = make_thunk (build1 (ADDR_EXPR, + vfunc_ptr_type_node, + fn), + BV_DELTA (v), + vcall_index, + /*generate_with_vtable_p=*/0); + use_thunk (thunk, /*emit_p=*/1); + } + } +} + + /* Generate RTL for FN. */ void @@ -3037,6 +3085,9 @@ expand_body (fn) return; } + /* Emit any thunks that should be emitted at the same time as FN. */ + emit_associated_thunks (fn); + timevar_push (TV_INTEGRATION); /* Optimize the body of the function before expanding it. */ diff --git a/gcc/testsuite/g++.old-deja/g++.other/virtual8.C b/gcc/testsuite/g++.old-deja/g++.other/virtual8.C new file mode 100644 index 0000000..9f32ca0 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/virtual8.C @@ -0,0 +1,31 @@ +extern "C" void printf (const char*, ...); + +struct A +{ + virtual void f () { + printf ("%x\n", this); + } +}; + +struct B : public A +{ +}; + +struct C : public A +{ +}; + +struct D : virtual public B, public C +{ +}; + +int main () +{ + D d; + + A* a1 = (A*) (B*) &d; + A* a2 = (A*) (C*) &d; + + a1->f (); + a2->f (); +} |