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
This commit is contained in:
Mark Mitchell 2000-06-23 01:14:40 +00:00 committed by Mark Mitchell
parent 11fc1858a0
commit 31f8e4f306
13 changed files with 357 additions and 152 deletions

View File

@ -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.

View File

@ -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;
}
fn = BV_FN (fn);
tree primary_base;
tree f;
/* Handle the case of a virtual function defined in BINFO itself. */
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;
}
/* 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

View File

@ -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));

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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 ('_');
}

View File

@ -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);
/* 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;
delta = THUNK_DELTA (thunk_fndecl);
vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
TREE_ADDRESSABLE (function) = 1;
mark_used (function);
if (current_function_decl)
abort ();
/* 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. */

View File

@ -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);
}

View File

@ -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. */

View File

@ -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 ();
}