* cp-tree.h (vcall_offset_in_vtable_p): New macro.
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 25 Jan 2000 23:26:21 +0000 (23:26 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 25 Jan 2000 23:26:21 +0000 (23:26 +0000)
* class.c (build_vbase_offset_vtbl_entries): Fix typo in commment.
(struct vcall_offset_data_s): New type.
(dfs_vcall_offset_queue_p): New function.
(dfs_build_vcall_offset_vtbl_entries): Likewise.
(build_vcall_offset_vtbl_entries): Likewise.
(layout_vtable_decl): Likewise.
(num_vfun_entries): Likewise.
(num_extra_vtbl_entries): Add the entries for vcall offsets.
(build_vtbl_initializer): Likewise.
(dfs_finish_vtabls): Use layout_vtable_decl.
(modify_one_vtables): Always duplicate vtables under the new ABI.
(finish_struct_1): Use layout_vtable_decl.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@31619 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h

index 0b5c2ff..97231fb 100644 (file)
@@ -1,3 +1,19 @@
+2000-01-25  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (vcall_offset_in_vtable_p): New macro.
+       * class.c (build_vbase_offset_vtbl_entries): Fix typo in commment.
+       (struct vcall_offset_data_s): New type.
+       (dfs_vcall_offset_queue_p): New function.
+       (dfs_build_vcall_offset_vtbl_entries): Likewise.
+       (build_vcall_offset_vtbl_entries): Likewise.
+       (layout_vtable_decl): Likewise.
+       (num_vfun_entries): Likewise.
+       (num_extra_vtbl_entries): Add the entries for vcall offsets.
+       (build_vtbl_initializer): Likewise.
+       (dfs_finish_vtabls): Use layout_vtable_decl.
+       (modify_one_vtables): Always duplicate vtables under the new ABI.
+       (finish_struct_1): Use layout_vtable_decl.
+       
 2000-01-25  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * decl.c (member_function_or_else): Change third arg from a format
index aaa90cc..0085052 100644 (file)
@@ -146,7 +146,13 @@ static tree dfs_set_offset_for_shared_vbases PROTO((tree, void *));
 static tree dfs_set_offset_for_unshared_vbases PROTO((tree, void *));
 static tree dfs_build_vbase_offset_vtbl_entries PROTO((tree, void *));
 static tree build_vbase_offset_vtbl_entries PROTO((tree, tree));
+static tree dfs_vcall_offset_queue_p PROTO((tree, void *));
+static tree dfs_build_vcall_offset_vtbl_entries PROTO((tree, void *));
+static tree build_vcall_offset_vtbl_entries PROTO((tree, tree));
+static tree dfs_count_virtuals PROTO((tree, void *));
 static void start_vtable PROTO((tree, int *));
+static void layout_vtable_decl PROTO((tree, int));
+static int num_vfun_entries PROTO((tree));
 
 /* Variables shared between class.c and call.c.  */
 
@@ -324,7 +330,7 @@ build_vbase_offset_vtbl_entries (binfo, t)
            list);
   inits = nreverse (TREE_VALUE (list));
 
-  /* We've now got offsets in the right oder.  However, the offsets
+  /* We've now got offsets in the right order.  However, the offsets
      we've stored are offsets from the beginning of the complete
      object, and we need offsets from this BINFO.  */
   for (init = inits; init; init = TREE_CHAIN (init))
@@ -345,6 +351,140 @@ build_vbase_offset_vtbl_entries (binfo, t)
   return inits;
 }
 
+typedef struct vcall_offset_data_s
+{
+  /* The binfo for the most-derived type.  */
+  tree derived;
+  /* The binfo for the virtual base for which we're building
+     initializers.  */
+  tree vbase;
+  /* The vcall offset initializers built up so far.  */
+  tree inits;
+  /* The number of vcall offsets accumulated.  */
+  int offsets;
+} vcall_offset_data;
+
+/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
+
+static tree
+dfs_vcall_offset_queue_p (binfo, data)
+     tree binfo;
+     void *data;
+{
+  vcall_offset_data* vod = (vcall_offset_data *) data;
+
+  return (binfo == vod->vbase) ? binfo : dfs_skip_vbases (binfo, NULL);
+}
+
+/* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
+
+static tree
+dfs_build_vcall_offset_vtbl_entries (binfo, data)
+     tree binfo;
+     void *data;
+{
+  vcall_offset_data* vod;
+  tree virtuals;
+  tree binfo_inits;
+
+  /* Primary bases are not interesting; all of the virtual
+     function table entries have been overridden.  */
+  if (BINFO_PRIMARY_MARKED_P (binfo))
+     return NULL_TREE;
+
+  vod = (vcall_offset_data *) data;
+  binfo_inits = NULL_TREE;
+
+  /* We chain the offsets on in reverse order.  That's correct --
+     build_vtbl_initializer will straighten them out.  */
+  for (virtuals = skip_rtti_stuff (binfo,
+                                  BINFO_TYPE (binfo),
+                                  NULL);
+       virtuals;
+       virtuals = TREE_CHAIN (virtuals))
+    {
+      tree fn;
+      tree base;
+      tree base_binfo;
+      tree offset;
+
+      /* Figure out what function we're looking at.  */
+      fn = TREE_VALUE (virtuals);
+      base = DECL_CLASS_CONTEXT (fn);
+
+      /* The FN is comes from BASE.  So, we must caculate the
+        adjustment from the virtual base that derived from BINFO to
+        BASE.  */
+      base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
+      offset = ssize_binop (MINUS_EXPR,
+                           BINFO_OFFSET (base_binfo),
+                           BINFO_OFFSET (vod->vbase));
+      offset = build1 (NOP_EXPR, vtable_entry_type, offset);
+      offset = fold (offset);
+      TREE_CONSTANT (offset) = 1;
+      binfo_inits = tree_cons (NULL_TREE, offset, binfo_inits);
+    }
+
+  /* Now add the initializers we've just created to the list that will
+     be returned to our caller.  */
+  vod->inits = chainon (vod->inits, binfo_inits);
+
+  return NULL_TREE;
+}
+
+/* Returns the initializers for the vcall offset entries in the vtable
+   for BINFO (which is part of the class hierarchy dominated by T), in
+   reverse order.  */
+
+static tree
+build_vcall_offset_vtbl_entries (binfo, t)
+     tree binfo;
+     tree t;
+{
+  vcall_offset_data vod;
+
+  /* Under the old ABI, the adjustments to the `this' pointer were made
+     elsewhere.  */
+  if (!vcall_offsets_in_vtable_p ())
+    return NULL_TREE;
+
+  /* We only need these entries if this base is a virtual base.  */
+  if (!TREE_VIA_VIRTUAL (binfo))
+    return NULL_TREE;
+
+  /* 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.  */
+  vod.derived = t;
+  vod.vbase = binfo;
+  vod.inits = NULL_TREE;
+  dfs_walk (binfo,
+           dfs_build_vcall_offset_vtbl_entries,
+           dfs_vcall_offset_queue_p,
+           &vod);
+
+  return vod.inits;
+}
+
 /* Returns a pointer to the virtual base class of EXP that has the
    indicated TYPE.  EXP is of class type, not a pointer type.  */
 
@@ -2321,6 +2461,68 @@ duplicate_tag_error (t)
   TYPE_NONCOPIED_PARTS (t) = NULL_TREE;
 }
 
+/* Make the BINFO's vtablehave N entries, including RTTI entries, but
+   not including vbase and vcall offsets.  Set its type and call the
+   backend to lay it out.  */
+
+static void
+layout_vtable_decl (binfo, n)
+     tree binfo;
+     int n;
+{
+  tree itype;
+  tree atype;
+
+  itype = size_int (n);
+  itype = size_binop (PLUS_EXPR, 
+                     itype,
+                     num_extra_vtbl_entries (binfo));
+  atype = build_cplus_array_type (vtable_entry_type, 
+                                 build_index_type (itype));
+  layout_type (atype);
+
+  /* We may have to grow the vtable.  */
+  if (!same_type_p (TREE_TYPE (BINFO_VTABLE (binfo)), atype))
+    {
+      TREE_TYPE (BINFO_VTABLE (binfo)) = atype;
+      DECL_SIZE (BINFO_VTABLE (binfo)) = 0;
+      layout_decl (BINFO_VTABLE (binfo), 0);
+      /* At one time the vtable info was grabbed 2 words at a time.  This
+        fails on sparc unless you have 8-byte alignment.  (tiemann) */
+      DECL_ALIGN (BINFO_VTABLE (binfo))
+       = MAX (TYPE_ALIGN (double_type_node),
+              DECL_ALIGN (BINFO_VTABLE (binfo)));
+    }
+}
+
+/* Returns the number of virtual function table entries (excluding
+   RTTI information, vbase and vcall offests, etc.) in the vtable for
+   BINFO.  */
+
+static int
+num_vfun_entries (binfo)
+     tree binfo;
+{
+  return list_length (skip_rtti_stuff (binfo,
+                                      BINFO_TYPE (binfo),
+                                      NULL));
+}
+
+/* Called from num_extra_vtbl_entries via dfs_walk.  */
+
+static tree
+dfs_count_virtuals (binfo, data)
+     tree binfo;
+     void *data;
+{
+  /* Non-primary bases are not interesting; all of the virtual
+     function table entries have been overridden.  */
+  if (!BINFO_PRIMARY_MARKED_P (binfo))
+    ((vcall_offset_data *) data)->offsets += num_vfun_entries (binfo);
+  
+  return NULL_TREE;
+}
+
 /* Returns the number of extra entries (at negative indices) required
    for BINFO's vtable.  */
 
@@ -2331,17 +2533,29 @@ num_extra_vtbl_entries (binfo)
   tree type;
   int entries;
 
-  /* Under the old ABI, there are no entries at negative offsets.  */
-  if (!vbase_offsets_in_vtable_p ())
-    return size_zero_node;
-
   type = BINFO_TYPE (binfo);
   entries = 0;
 
   /* There is an entry for the offset to each virtual base.  */
-  entries += list_length (CLASSTYPE_VBASECLASSES (type));
+  if (vbase_offsets_in_vtable_p ())
+    entries += list_length (CLASSTYPE_VBASECLASSES (type));
+
+  /* If this is a virtual base, there are entries for each virtual
+     function defined in this class or its bases.  */
+  if (vcall_offsets_in_vtable_p () && TREE_VIA_VIRTUAL (binfo))
+    {
+      vcall_offset_data vod;
 
-  return size_int (entries);
+      vod.vbase = binfo;
+      vod.offsets = 0;
+      dfs_walk (binfo,
+               dfs_count_virtuals,
+               dfs_vcall_offset_queue_p,
+               &vod);
+      entries += vod.offsets;
+    }
+      
+  return entries ? size_int (entries) : size_zero_node;
 }
 
 /* Returns the offset (in bytes) from the beginning of BINFO's vtable
@@ -2372,8 +2586,13 @@ build_vtbl_initializer (binfo, t)
   tree inits = NULL_TREE;
   tree type = BINFO_TYPE (binfo);
 
+  /* Add entries to the vtable that indicate how to adjust the this
+     pointer when calling a virtual function in this class.  */
+  inits = build_vcall_offset_vtbl_entries (binfo, t);
+
   /* Add entries to the vtable for offsets to our virtual bases.  */
-  inits = build_vbase_offset_vtbl_entries (binfo, t);
+  inits = chainon (build_vbase_offset_vtbl_entries (binfo, t),
+                  inits);
 
   /* Process the RTTI stuff at the head of the list.  If we're not
      using vtable thunks, then the RTTI entry is just an ordinary
@@ -2451,6 +2670,7 @@ dfs_finish_vtbls (binfo, data)
       tree decl;
       tree context;
       
+      layout_vtable_decl (binfo, list_length (BINFO_VIRTUALS (binfo)));
       decl = BINFO_VTABLE (binfo);
       context = DECL_CONTEXT (decl);
       DECL_CONTEXT (decl) = 0;
@@ -2675,8 +2895,10 @@ modify_one_vtable (binfo, t, fndecl)
   tree virtuals;
   unsigned HOST_WIDE_INT n;
   
-  /* update rtti entry */
-  if (flag_rtti)
+  /* If we're support RTTI then we always need a new vtable to point
+     to the RTTI information.  Under the new ABI we may need a new
+     vtable to contain vcall and vbase offsets.  */
+  if (flag_rtti || flag_new_abi)
     {
       if (binfo == TYPE_BINFO (t))
        build_vtable (TYPE_BINFO (DECL_CONTEXT (TYPE_VFIELD (t))), t);
@@ -5010,32 +5232,7 @@ finish_struct_1 (t)
 
   /* Now lay out the virtual function table.  */
   if (has_virtual)
-    {
-      /* Use size_int so values are memoized in common cases.  */
-      tree itype;
-      tree atype;
-
-      itype = size_int (has_virtual);
-      itype = size_binop (PLUS_EXPR, 
-                         itype,
-                         num_extra_vtbl_entries (TYPE_BINFO (t)));
-      atype = build_cplus_array_type (vtable_entry_type, 
-                                     build_index_type (itype));
-      layout_type (atype);
-
-      /* We may have to grow the vtable.  */
-      if (TREE_TYPE (TYPE_BINFO_VTABLE (t)) != atype)
-       {
-         TREE_TYPE (TYPE_BINFO_VTABLE (t)) = atype;
-         DECL_SIZE (TYPE_BINFO_VTABLE (t)) = 0;
-         layout_decl (TYPE_BINFO_VTABLE (t), 0);
-         /* At one time the vtable info was grabbed 2 words at a time.  This
-            fails on sparc unless you have 8-byte alignment.  (tiemann) */
-         DECL_ALIGN (TYPE_BINFO_VTABLE (t))
-           = MAX (TYPE_ALIGN (double_type_node),
-                  DECL_ALIGN (TYPE_BINFO_VTABLE (t)));
-       }
-    }
+    layout_vtable_decl (TYPE_BINFO (t), has_virtual);
 
   /* If we created a new vtbl pointer for this class, add it to the
      list.  */
index 564cbe3..0d83576 100644 (file)
@@ -213,6 +213,11 @@ extern int flag_rtti;
    stored in the object itself.  */
 #define vbase_offsets_in_vtable_p() (flag_new_abi)
 
+/* Nonzero if displacements to the `this' pointer to use when calling
+   virtual functions in a virtual base class are present in the
+   vtable.  */
+#define vcall_offsets_in_vtable_p() (flag_new_abi)
+
 /* Nonzero if a derived class that needs a vptr should always get one,
    even if a non-primary base class already has one.  For example,
    given: