* 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
+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.
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));
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));
{
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);
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;
}
build_primary_vtable (binfo, type)
tree binfo, type;
{
- tree virtuals, decl;
+ tree decl;
+ tree virtuals;
decl = get_vtable_decl (type, /*complete=*/0);
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;
}
/* 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)
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. */
{
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;
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
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. */
{
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;
}
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);
/* 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);
/* 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);
}
/* 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)
}
/* 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
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;
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);
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;
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);
/* 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);
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);
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;
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
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.
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)
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
/* 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. */
\f
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;
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
THUNK_VCALL_OFFSET. */
- HOST_WIDE_INT vcall_offset;
+ tree vcall_offset;
} u2;
};
#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. */
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));
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));
&& !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);
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);
}
}
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");
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))
}
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;
}
if (virtuals)
{
- dump_expr (TREE_VALUE (virtuals),
+ dump_expr (BV_FN (virtuals),
flags | TS_EXPR_PARENS);
break;
}
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
/* 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>
tree
mangle_thunk (fn_decl, offset, vcall_offset)
tree fn_decl;
- int offset;
- int vcall_offset;
+ tree offset;
+ tree vcall_offset;
{
const char *result;
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 ('_');
}
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 ();
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));
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;
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;
}
/* 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
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)
{
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);
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;
/* 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. */
BLOCK_VARS (DECL_INITIAL (thunk_fndecl))
= DECL_ARGUMENTS (thunk_fndecl);
expand_body (finish_function (0));
- pop_from_top_level ();
}
+
+ pop_from_top_level ();
}
\f
/* Code for synthesizing methods which have default semantics defined. */
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));
}
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);
}
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. */
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
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. */
--- /dev/null
+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 ();
+}