66th Cygnus<->FSF merge

From-SVN: r9418
This commit is contained in:
Mike Stump 1995-04-19 17:08:54 +00:00 committed by Mike Stump
parent 8a0e8d4dc4
commit 43f2999d1d
4 changed files with 268 additions and 8 deletions

View File

@ -1,3 +1,18 @@
Wed Apr 19 02:32:40 1995 Mike Stump <mrs@cygnus.com>
* search.c (virtual_context): New function to get the virtual
context of a function.
(expand_upcast_fixups): New function to generate runtime vtables.
(fixup_virtual_upcast_offsets): Ditto.
(expand_indirect_vtbls_init): Use fixup_virtual_upcast_offsets to
ensure that the this offsets for upcasts from virtual bases into
other virtual bases or non-virtual bases are correct at construction
time and destruction time.
* class.c (fixup_vtable_deltas): Modify to fixup all offsets in all
vtables in all virtual bases, instead of just one vtable in each
virtual base.
(fixup_vtable_deltas1): Ditto.
Tue Apr 18 03:57:35 1995 Michael Meissner (meissner@cygnus.com)
* Makefile.in (lex.o): Add dependency on c-pragma.h.

View File

@ -2342,12 +2342,9 @@ modify_all_direct_vtables (binfo, do_self, t, fndecl, pfn)
}
}
/* Fixup all the delta entries in this vtable that need updating.
This happens when we have non-overridden virtual functions from a
virtual base class, that are at a different offset, in the new
hierarchy, because the layout of the virtual bases has changed. */
/* Fixup all the delta entries in this one vtable that need updating. */
static void
fixup_vtable_deltas (binfo, t)
fixup_vtable_deltas1 (binfo, t)
tree binfo, t;
{
tree virtuals = BINFO_VIRTUALS (binfo);
@ -2418,6 +2415,33 @@ fixup_vtable_deltas (binfo, t)
}
}
/* Fixup all the delta entries in all the direct vtables that need updating.
This happens when we have non-overridden virtual functions from a
virtual base class, that are at a different offset, in the new
hierarchy, because the layout of the virtual bases has changed. */
static void
fixup_vtable_deltas (binfo, init_self, t)
tree binfo, t;
int init_self;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable =
i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
fixup_vtable_deltas (base_binfo, is_not_base_vtable, t);
}
/* Should we use something besides CLASSTYPE_VFIELDS? */
if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
fixup_vtable_deltas1 (binfo, t);
}
}
/* These are the ones that are through virtual base classes. */
static void
modify_all_indirect_vtables (binfo, do_self, via_virtual, t, fndecl, pfn)
@ -3707,7 +3731,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
only doing this for vtables that come from virtual bases
that have differing offsets, but don't want to miss any
entries. */
fixup_vtable_deltas (vbases, t);
fixup_vtable_deltas (vbases, 1, t);
vbases = TREE_CHAIN (vbases);
}
}

View File

@ -138,7 +138,7 @@ expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
}
#if 0
/* Before turning this on, make sure it is correct. */
if (can_elide && ! BINFO_MODIFIED (binfo))
if (can_elide && ! BINFO_MODIFIED (binfo))
return;
#endif
/* Should we use something besides CLASSTYPE_VFIELDS? */

View File

@ -27,6 +27,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "cp-tree.h"
#include "obstack.h"
#include "flags.h"
#include "rtl.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
@ -2552,6 +2553,184 @@ init_vbase_pointers (type, decl_ptr)
return 0;
}
/* get the virtual context (the vbase that directly contains the
DECL_CLASS_CONTEXT of the FNDECL) that the given FNDECL is declared in,
or NULL_TREE if there is none.
FNDECL must come from a virtual table from a virtual base to ensure that
there is only one possible DECL_CLASS_CONTEXT.
We know that if there is more than one place (binfo) the fndecl that the
declared, they all refer to the same binfo. See get_class_offset_1 for
the check that ensures this. */
static tree
virtual_context (fndecl, t, vbase)
tree fndecl, t, vbase;
{
tree path;
if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), t, 0, &path) < 0)
{
/* This shouldn't happen, I don't want errors! */
warning ("recoverable compiler error, fixups for virtual function");
return vbase;
}
while (path)
{
if (TREE_VIA_VIRTUAL (path))
return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t));
path = BINFO_INHERITANCE_CHAIN (path);
}
return 0;
}
/* Fixups upcast offsets for one vtable.
Entries may stay within the VBASE given, or
they may upcast into a direct base, or
they may upcast into a different vbase.
We only need to do fixups in case 2 and 3.
This routine mirrors fixup_vtable_deltas in functionality, though
this one is runtime based, and the other is compile time based.
Conceivably that routine could be removed entirely, and all fixups
done at runtime.
VBASE_OFFSETS is an association list of virtual bases that contains
offset information, so the offsets are only calculated once. */
static void
expand_upcast_fixups (binfo, addr, orig_addr, vbase, t, vbase_offsets)
tree binfo, addr, orig_addr, vbase, t, *vbase_offsets;
{
tree virtuals = BINFO_VIRTUALS (binfo);
tree vc;
tree delta;
unsigned HOST_WIDE_INT n;
delta = purpose_member (vbase, *vbase_offsets);
if (! delta)
{
delta = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase));
delta = build (MINUS_EXPR, ptrdiff_type_node, delta, addr);
delta = save_expr (delta);
delta = tree_cons (vbase, delta, *vbase_offsets);
*vbase_offsets = delta;
}
/* Skip RTTI fake object. */
n = 1;
if (virtuals)
virtuals = TREE_CHAIN (virtuals);
while (virtuals)
{
tree current_fndecl = TREE_VALUE (virtuals);
current_fndecl = FNADDR_FROM_VTABLE_ENTRY (current_fndecl);
current_fndecl = TREE_OPERAND (current_fndecl, 0);
if (current_fndecl
&& (vc=virtual_context (current_fndecl, t, vbase)) != vbase)
{
/* This may in fact need a runtime fixup. */
tree idx = DECL_VINDEX (current_fndecl);
tree vtbl = BINFO_VTABLE (binfo);
tree nvtbl = lookup_name (DECL_NAME (vtbl), 0);
tree aref, ref, naref;
tree old_delta, new_delta;
tree init;
if (nvtbl == NULL_TREE
|| nvtbl == IDENTIFIER_GLOBAL_VALUE (DECL_NAME (vtbl)))
{
/* Dup it if it isn't in local scope yet. */
nvtbl = build_decl (VAR_DECL,
DECL_NAME (vtbl),
TYPE_MAIN_VARIANT (TREE_TYPE (BINFO_VTABLE (binfo))));
DECL_ALIGN (nvtbl) = MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (nvtbl));
TREE_READONLY (nvtbl) = 0;
nvtbl = pushdecl (nvtbl);
init = NULL_TREE;
finish_decl (nvtbl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
DECL_VIRTUAL_P (nvtbl) = 1;
DECL_CONTEXT (nvtbl) = t;
init = build (MODIFY_EXPR, TREE_TYPE (nvtbl),
nvtbl, vtbl);
TREE_SIDE_EFFECTS (init) = 1;
expand_expr_stmt (init);
/* Update the vtable pointers as necessary. */
ref = build_vfield_ref (build_indirect_ref (addr, NULL_PTR), DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))));
expand_expr_stmt (build_modify_expr (ref, NOP_EXPR,
build_unary_op (ADDR_EXPR, nvtbl, 0)));
}
assemble_external (vtbl);
aref = build_array_ref (vtbl, idx);
naref = build_array_ref (nvtbl, idx);
old_delta = build_component_ref (aref, delta_identifier, 0, 0);
new_delta = build_component_ref (naref, delta_identifier, 0, 0);
old_delta = build_binary_op (PLUS_EXPR, old_delta,
TREE_VALUE (delta), 0);
if (vc)
{
/* If this is set, we need to add in delta adjustments for
the other virtual base. */
tree vc_delta = purpose_member (vc, *vbase_offsets);
if (! vc_delta)
{
tree vc_addr = convert_pointer_to_real (vc, orig_addr);
vc_delta = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc));
vc_delta = build (MINUS_EXPR, ptrdiff_type_node,
vc_addr, vc_delta);
vc_delta = save_expr (vc_delta);
*vbase_offsets = tree_cons (vc, vc_delta, *vbase_offsets);
}
else
vc_delta = TREE_VALUE (vc_delta);
old_delta = build_binary_op (PLUS_EXPR, old_delta, vc_delta, 0);
}
TREE_READONLY (new_delta) = 0;
expand_expr_stmt (build_modify_expr (new_delta, NOP_EXPR,
old_delta));
}
++n;
virtuals = TREE_CHAIN (virtuals);
}
}
/* Fixup upcast offsets for all direct vtables. Patterned after
expand_direct_vtbls_init. */
static void
fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, orig_addr, type, vbase, vbase_offsets)
tree real_binfo, binfo, addr, orig_addr, type, vbase, *vbase_offsets;
int init_self, can_elide;
{
tree real_binfos = BINFO_BASETYPES (real_binfo);
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = real_binfos ? TREE_VEC_LENGTH (real_binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable =
i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
if (! TREE_VIA_VIRTUAL (real_base_binfo))
fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
is_not_base_vtable, can_elide, addr,
orig_addr, type, vbase, vbase_offsets);
}
#if 0
/* Before turning this on, make sure it is correct. */
if (can_elide && ! BINFO_MODIFIED (binfo))
return;
#endif
/* Should we use something besides CLASSTYPE_VFIELDS? */
if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (real_binfo)))
{
addr = convert_pointer_to_real (binfo, addr);
expand_upcast_fixups (real_binfo, addr, orig_addr, vbase, type, vbase_offsets);
}
}
/* Build a COMPOUND_EXPR which when expanded will generate the code
needed to initialize all the virtual function table slots of all
the virtual baseclasses. MAIN_BINFO is the binfo which determines
@ -2577,6 +2756,7 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
tree type = BINFO_TYPE (binfo);
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
rtx fixup_insns = NULL_RTX;
int old_flag = flag_this_is_variable;
tree vbases = CLASSTYPE_VBASECLASSES (type);
vbase_types = vbases;
@ -2587,9 +2767,10 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
{
/* This is an object of type IN_TYPE, */
flag_this_is_variable = -2;
dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep);
}
dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep);
/* Initialized with vtables of type TYPE. */
for (; vbases; vbases = TREE_CHAIN (vbases))
{
@ -2627,6 +2808,46 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
binfos. (in the CLASSTPE_VFIELD_PARENT sense) */
expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)),
1, 0, addr);
/* If we are using computed offsets we can skip fixups. */
if (use_computed_offsets)
continue;
/* Now we adjust the offsets for virtual functions that cross
virtual boundaries on an implicit upcast on vf call so that
the layout of the most complete type is used, instead of
assuming the layout of the virtual bases from our current type. */
if (flag_vtable_thunks)
{
/* We don't have dynamic thunks yet! So for now, just fail silently. */
}
else
{
tree vbase_offsets = NULL_TREE;
push_to_sequence (fixup_insns);
fixup_virtual_upcast_offsets (vbases,
TYPE_BINFO (BINFO_TYPE (vbases)),
1, 0, addr, vbase_decl_ptr,
type, vbases, &vbase_offsets);
fixup_insns = get_insns ();
end_sequence ();
}
}
if (fixup_insns)
{
extern tree in_charge_identifier;
tree in_charge_node = lookup_name (in_charge_identifier, 0);
if (! in_charge_node)
{
warning ("recoverable internal compiler error, nobody's in charge!");
in_charge_node = integer_zero_node;
}
in_charge_node = build_binary_op (EQ_EXPR, in_charge_node, integer_zero_node, 1);
expand_start_cond (in_charge_node, 0);
emit_insns (fixup_insns);
expand_end_cond ();
}
dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);