C++ PATCH: Fix more vcall offset stuff

Mark Mitchell mark@codesourcery.com
Sun Aug 20 21:40:00 GMT 2000


This patch tweaks the new-ABI vcall-offset generation code a little
more -- hopefully for the last time.  The spec keeps moving around a
little, and we keep chasing it...

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2000-08-20  Mark Mitchell  <mark@codesourcery.com>

	* 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.

Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.330
diff -c -p -r1.330 class.c
*** class.c	2000/08/17 13:26:14	1.330
--- class.c	2000/08/21 04:21:17
*************** static void propagate_binfo_offsets PARA
*** 160,166 ****
  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 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 *));
--- 160,167 ----
  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 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 *));
*************** build_vtbl_initializer (binfo, orig_binf
*** 7107,7115 ****
    vtbl_init_data vid;
  
    /* Initialize 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);
--- 7108,7116 ----
    vtbl_init_data vid;
  
    /* Initialize VID.  */
+   bzero (&vid, sizeof (vid));
    vid.binfo = binfo;
    vid.derived = t;
    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);
*************** build_vtbl_initializer (binfo, orig_binf
*** 7119,7127 ****
    /* Add entries to the vtable for RTTI.  */
    build_rtti_vtbl_entries (binfo, rtti_binfo, &vid);
  
    /* Add the vcall and vbase offset entries.  */
    build_vcall_and_vbase_vtbl_entries (binfo, &vid);
!    /* Clear BINFO_VTABLE_PAATH_MARKED; it's set by
       build_vbase_offset_vtbl_entries.  */
    for (vbase = CLASSTYPE_VBASECLASSES (t); 
         vbase; 
--- 7120,7134 ----
    /* 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);
!   /* 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; 
*************** build_vbase_offset_vtbl_entries (binfo, 
*** 7293,7317 ****
      }
  }
  
  /* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
  
! static tree
! dfs_build_vcall_offset_vtbl_entries (binfo, data)
       tree binfo;
!      void *data;
  {
-   vtbl_init_data* vid;
    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;
-   /* 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
--- 7300,7397 ----
      }
  }
  
+ /* 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 void
! add_vcall_offset_vtbl_entries_1 (binfo, vid)
       tree binfo;
!      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;
  
    binfo_inits = NULL_TREE;
  
    /* We might be a primary base class.  Go up the inheritance
*************** dfs_build_vcall_offset_vtbl_entries (bin
*** 7339,7367 ****
        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);
        tree base;
        tree base_binfo;
        size_t i;
  
        /* 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
--- 7419,7453 ----
        non_primary_binfo = b;
      }
  
    /* Make entries for the rest of the 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
*************** dfs_build_vcall_offset_vtbl_entries (bin
*** 7408,7465 ****
        /* 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
--- 7494,7499 ----


More information about the Gcc-patches mailing list