diff options
author | Mike Stump <mrs@cygnus.com> | 1995-04-19 17:08:54 +0000 |
---|---|---|
committer | Mike Stump <mrs@gcc.gnu.org> | 1995-04-19 17:08:54 +0000 |
commit | 43f2999d1da07cb6f487524991d85ac74ed733d5 (patch) | |
tree | e977a5f4a27b532d6c3e55982e9034aaf6097b78 /gcc | |
parent | 8a0e8d4dc4cff5cd0293a6bbef3ed77003d598e1 (diff) | |
download | gcc-43f2999d1da07cb6f487524991d85ac74ed733d5.zip gcc-43f2999d1da07cb6f487524991d85ac74ed733d5.tar.gz gcc-43f2999d1da07cb6f487524991d85ac74ed733d5.tar.bz2 |
66th Cygnus<->FSF merge
From-SVN: r9418
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/cp/class.c | 36 | ||||
-rw-r--r-- | gcc/cp/init.c | 2 | ||||
-rw-r--r-- | gcc/cp/search.c | 223 |
4 files changed, 268 insertions, 8 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f8268ec..bbe5cd7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index a4d9b6b..03754bd 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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); } } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index b601d3d..3ed845c 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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? */ diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 7d7d2ff..dfa2315 100644 --- a/gcc/cp/search.c +++ b/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); |