parent
8a0e8d4dc4
commit
43f2999d1d
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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? */
|
||||
|
|
223
gcc/cp/search.c
223
gcc/cp/search.c
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue