From b485e15bf861b6eb5680c3a268036b2cdeacd656 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Mon, 21 Aug 2000 04:39:29 +0000 Subject: [PATCH] class.c (build_vtbl_initializer): Clear the entire vtbl_init_data. * class.c (build_vtbl_initializer): Clear the entire vtbl_init_data. Start keeping track of the functions for which we have created vcall offsets here. (dfs_build_vcall_offset_vtbl_entries): Remove. (build_vcall_offset_vtbl_entries): Reimplement. (add_vcall_offset_vtbl_entries_r): New function. (add_vcall_offset_vtbl_entries_1): Likewise. Tweak logic for computing when vcall offsets are necessary. From-SVN: r35828 --- gcc/cp/ChangeLog | 11 +++ gcc/cp/class.c | 196 +++++++++++++++++++++++++++-------------------- 2 files changed, 126 insertions(+), 81 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 88d56b09238..18449d117d5 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2000-08-20 Mark Mitchell + + * class.c (build_vtbl_initializer): Clear the entire + vtbl_init_data. Start keeping track of the functions for which we + have created vcall offsets here. + (dfs_build_vcall_offset_vtbl_entries): Remove. + (build_vcall_offset_vtbl_entries): Reimplement. + (add_vcall_offset_vtbl_entries_r): New function. + (add_vcall_offset_vtbl_entries_1): Likewise. Tweak logic for + computing when vcall offsets are necessary. + 2000-08-18 Nathan Sidwell * decl.c (member_function_or_else): Use cp_error ... %T. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f749c74e6d8..2834154f3d8 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -160,7 +160,8 @@ static void propagate_binfo_offsets PARAMS ((tree, tree)); static void layout_virtual_bases PARAMS ((tree, varray_type *)); static tree dfs_set_offset_for_unshared_vbases PARAMS ((tree, void *)); static void build_vbase_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *)); -static tree dfs_build_vcall_offset_vtbl_entries PARAMS ((tree, void *)); +static void add_vcall_offset_vtbl_entries_r PARAMS ((tree, vtbl_init_data *)); +static void add_vcall_offset_vtbl_entries_1 PARAMS ((tree, vtbl_init_data *)); static void build_vcall_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *)); static void layout_vtable_decl PARAMS ((tree, int)); static tree dfs_find_final_overrider PARAMS ((tree, void *)); @@ -7097,9 +7098,9 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) vtbl_init_data vid; /* Initialize VID. */ + bzero (&vid, sizeof (vid)); vid.binfo = binfo; vid.derived = t; - vid.inits = NULL_TREE; vid.last_init = &vid.inits; vid.primary_vtbl_p = (binfo == TYPE_BINFO (t)); vid.ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t); @@ -7109,9 +7110,15 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) /* Add entries to the vtable for RTTI. */ build_rtti_vtbl_entries (binfo, rtti_binfo, &vid); + /* Create an array for keeping track of the functions we've + processed. When we see multiple functions with the same + signature, we share the vcall offsets. */ + VARRAY_TREE_INIT (vid.fns, 32, "fns"); /* Add the vcall and vbase offset entries. */ build_vcall_and_vbase_vtbl_entries (binfo, &vid); - /* Clear BINFO_VTABLE_PAATH_MARKED; it's set by + /* Clean up. */ + VARRAY_FREE (vid.fns); + /* Clear BINFO_VTABLE_PAATH_MARKED; it's set by build_vbase_offset_vtbl_entries. */ for (vbase = CLASSTYPE_VBASECLASSES (t); vbase; @@ -7283,25 +7290,98 @@ build_vbase_offset_vtbl_entries (binfo, vid) } } +/* Adds the initializers for the vcall offset entries in the vtable + for BINFO (which is part of the class hierarchy dominated by T) to + VID->INITS. */ + +static void +build_vcall_offset_vtbl_entries (binfo, vid) + tree binfo; + vtbl_init_data *vid; +{ + /* Under the old ABI, the adjustments to the `this' pointer were made + elsewhere. */ + if (!vcall_offsets_in_vtable_p ()) + return; + + /* We only need these entries if this base is a virtual base. */ + if (!TREE_VIA_VIRTUAL (binfo)) + return; + + /* We need a vcall offset for each of the virtual functions in this + vtable. For example: + + class A { virtual void f (); }; + class B : virtual public A { }; + class C: virtual public A, public B {}; + + Now imagine: + + B* b = new C; + b->f(); + + The location of `A' is not at a fixed offset relative to `B'; the + offset depends on the complete object derived from `B'. So, + `B' vtable contains an entry for `f' that indicates by what + amount the `this' pointer for `B' needs to be adjusted to arrive + at `A'. + + We need entries for all the functions in our primary vtable and + in our non-virtual bases vtables. */ + vid->vbase = binfo; + /* Now, walk through the non-virtual bases, adding vcall offsets. */ + add_vcall_offset_vtbl_entries_r (binfo, vid); +} + +/* Build vcall offsets, starting with those for BINFO. */ + +static void +add_vcall_offset_vtbl_entries_r (binfo, vid) + tree binfo; + vtbl_init_data *vid; +{ + int i; + tree primary_binfo; + + /* Don't walk into virtual bases -- except, of course, for the + virtual base for which we are building vcall offsets. */ + if (TREE_VIA_VIRTUAL (binfo) && vid->vbase != binfo) + return; + + /* If BINFO has a primary base, process it first. */ + primary_binfo = get_primary_binfo (binfo); + if (primary_binfo) + add_vcall_offset_vtbl_entries_r (primary_binfo, vid); + + /* Add BINFO itself to the list. */ + add_vcall_offset_vtbl_entries_1 (binfo, vid); + + /* Scan the non-primary bases of BINFO. */ + for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i) + { + tree base_binfo; + + base_binfo = BINFO_BASETYPE (binfo, i); + if (base_binfo != primary_binfo) + add_vcall_offset_vtbl_entries_r (base_binfo, vid); + } +} + /* Called from build_vcall_offset_vtbl_entries via dfs_walk. */ -static tree -dfs_build_vcall_offset_vtbl_entries (binfo, data) +static void +add_vcall_offset_vtbl_entries_1 (binfo, vid) tree binfo; - void *data; + vtbl_init_data* vid; { - vtbl_init_data* vid; tree derived_virtuals; tree base_virtuals; + tree orig_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; - /* The primary base of BINFO. */ - tree primary_binfo; - int i; - vid = (vtbl_init_data *) data; binfo_inits = NULL_TREE; /* We might be a primary base class. Go up the inheritance @@ -7329,29 +7409,35 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) 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); - primary_binfo = get_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); - } - /* Make entries for the rest of the virtuals. */ - for (; base_virtuals; - derived_virtuals = TREE_CHAIN (derived_virtuals), - base_virtuals = TREE_CHAIN (base_virtuals)) - { - /* Figure out what function we're looking at. */ - tree fn = BV_FN (derived_virtuals); + for (base_virtuals = BINFO_VIRTUALS (binfo), + derived_virtuals = BINFO_VIRTUALS (non_primary_binfo), + orig_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo))); + base_virtuals; + base_virtuals = TREE_CHAIN (base_virtuals), + derived_virtuals = TREE_CHAIN (derived_virtuals), + orig_virtuals = TREE_CHAIN (orig_virtuals)) + { + tree orig_fn; + tree fn; tree base; tree base_binfo; size_t i; + /* Find the declaration that originally caused this function to + be present. */ + orig_fn = BV_FN (orig_virtuals); + + /* We do not need an entry if this function is declared in a + virtual base (or one of its virtual bases), and not + overridden in the section of the hierarchy dominated by the + virtual base for which we are building vcall offsets. */ + if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo))) + continue; + + /* Find the overriding function. */ + fn = BV_FN (derived_virtuals); + /* If there is already an entry for a function with the same signature as FN, then we do not need a second vcall offset. Check the list of functions already present in the derived @@ -7398,58 +7484,6 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) /* Keep track of this function. */ VARRAY_PUSH_TREE (vid->fns, derived_virtuals); } - - return NULL_TREE; -} - -/* Adds the initializers for the vcall offset entries in the vtable - for BINFO (which is part of the class hierarchy dominated by T) to - VID->INITS. */ - -static void -build_vcall_offset_vtbl_entries (binfo, vid) - tree binfo; - vtbl_init_data *vid; -{ - /* Under the old ABI, the adjustments to the `this' pointer were made - elsewhere. */ - if (!vcall_offsets_in_vtable_p ()) - return; - - /* We only need these entries if this base is a virtual base. */ - if (!TREE_VIA_VIRTUAL (binfo)) - return; - - /* We need a vcall offset for each of the virtual functions in this - vtable. For example: - - class A { virtual void f (); }; - class B : virtual public A { }; - class C: virtual public A, public B {}; - - Now imagine: - - B* b = new C; - b->f(); - - The location of `A' is not at a fixed offset relative to `B'; the - offset depends on the complete object derived from `B'. So, - `B' vtable contains an entry for `f' that indicates by what - amount the `this' pointer for `B' needs to be adjusted to arrive - at `A'. - - We need entries for all the functions in our primary vtable and - in our non-virtual bases vtables. For each base, the entries - appear in the same order as in the base; but the bases themselves - appear in reverse depth-first, left-to-right order. */ - vid->vbase = binfo; - VARRAY_TREE_INIT (vid->fns, 32, "fns"); - dfs_walk_real (binfo, - dfs_build_vcall_offset_vtbl_entries, - NULL, - dfs_skip_vbases, - vid); - VARRAY_FREE (vid->fns); } /* Return vtbl initializers for the RTTI entries coresponding to the -- 2.30.2