This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

C++ PATCH: allocate primary bases first under the new ABI



Under the old ABI, with something like:

   class A { int i; };
   class B { virtual void f(); }
   class C : public A, public B {};

`B' occurred after `A' in `C'.  Under the new ABI, `B' occurs first;
the new ABI has an invariant that the vtable pointer goes first in the
object.  Thus, under the new ABI objects of type C are smaller, and
get initialized faster.

This is the change that makes that happen.

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

2000-01-10  Mark Mitchell  <mitchell@dumbledore.codesourcery.com>

	* class.c (build_base_field): New function, split out from ...
	(build_base_fields): ... here.  Use it.  Allocate primary bases
	first, under the new ABI.
	(get_vtable_entry): Remove.
	(remove_base_field): New function, split out from ...
	(remove_base_fields): ... here.  Adjust since primary bases come
	first under the new ABI.

Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.225
diff -c -p -r1.225 class.c
*** class.c	2000/01/11 02:28:01	1.225
--- class.c	2000/01/11 03:13:28
*************** static void check_field_decl PROTO((tree
*** 125,130 ****
--- 125,131 ----
  static void check_field_decls PROTO((tree, tree *, int *, int *, int *, 
  				     int *));
  static int avoid_overlap PROTO((tree, tree, int *));
+ static tree build_base_field PROTO((tree, tree, int *, int *, unsigned int *));
  static tree build_base_fields PROTO((tree, int *));
  static tree build_vbase_pointer_fields PROTO((tree, int *));
  static tree build_vtbl_or_vbase_field PROTO((tree, tree, tree, tree, int *));
*************** static void propagate_binfo_offsets PROT
*** 141,146 ****
--- 142,148 ----
  static void layout_basetypes PROTO((tree));
  static tree dfs_set_offset_for_vbases PROTO((tree, void *));
  static void layout_virtual_bases PROTO((tree));
+ static void remove_base_field PROTO((tree, tree, tree *));
  static void remove_base_fields PROTO((tree));
  
  /* Variables shared between class.c and call.c.  */
*************** prepare_fresh_vtable (binfo, for_type)
*** 930,963 ****
    SET_BINFO_NEW_VTABLE_MARKED (binfo);
  }
  
- #if 0
- /* Access the virtual function table entry that logically
-    contains BASE_FNDECL.  VIRTUALS is the virtual function table's
-    initializer.  We can run off the end, when dealing with virtual
-    destructors in MI situations, return NULL_TREE in that case.  */
- 
- static tree
- get_vtable_entry (virtuals, base_fndecl)
-      tree virtuals, base_fndecl;
- {
-   unsigned HOST_WIDE_INT n = (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
- 	   ? (TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl))
- 	      & (((unsigned HOST_WIDE_INT)1<<(BITS_PER_WORD-1))-1))
- 	   : TREE_INT_CST_LOW (DECL_VINDEX (base_fndecl)));
- 
- #ifdef GATHER_STATISTICS
-   n_vtable_searches += n;
- #endif
- 
-   while (n > 0 && virtuals)
-     {
-       --n;
-       virtuals = TREE_CHAIN (virtuals);
-     }
-   return virtuals;
- }
- #endif
- 
  /* Change the offset for the FNDECL entry to NEW_OFFSET.  Also update
     DECL_VINDEX (FNDECL).  */
  
--- 932,937 ----
*************** avoid_overlap (decl, newdecl, empty_p)
*** 3745,3750 ****
--- 3719,3777 ----
    return 1;
  }
  
+ /* Build a FIELD_DECL for the base given by BINFO in T.  If the new
+    object is non-empty, clear *EMPTY_P.  Otherwise, set *SAW_EMPTY_P.
+    *BASE_ALIGN is a running maximum of the alignments of any base
+    class.  */
+ 
+ static tree
+ build_base_field (t, binfo, empty_p, saw_empty_p, base_align)
+      tree t;
+      tree binfo;
+      int *empty_p;
+      int *saw_empty_p;
+      unsigned int *base_align;
+ {
+   tree basetype = BINFO_TYPE (binfo);
+   tree decl;
+ 
+   if (TYPE_SIZE (basetype) == 0)
+     /* This error is now reported in xref_tag, thus giving better
+        location information.  */
+     return NULL_TREE;
+   
+   decl = build_lang_decl (FIELD_DECL, NULL_TREE, basetype);
+   DECL_ARTIFICIAL (decl) = 1;
+   DECL_FIELD_CONTEXT (decl) = DECL_CLASS_CONTEXT (decl) = t;
+   DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
+   DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
+   
+   if (flag_new_abi && DECL_SIZE (decl) == integer_zero_node)
+     {
+       *saw_empty_p = 1;
+       return decl;
+     }
+ 
+   /* The containing class is non-empty because it has a non-empty base
+      class.  */
+   *empty_p = 0;
+       
+   if (! flag_new_abi)
+     {
+       /* Brain damage for backwards compatibility.  For no good
+ 	 reason, the old layout_basetypes made every base at least
+ 	 as large as the alignment for the bases up to that point,
+ 	 gratuitously wasting space.  So we do the same thing
+ 	 here.  */
+       *base_align = MAX (*base_align, DECL_ALIGN (decl));
+       DECL_SIZE (decl)
+ 	= size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
+ 			 (int) (*base_align)));
+     }
+ 
+   return decl;
+ }
+ 
  /* Returns a list of fields to stand in for the base class subobjects
     of REC.  These fields are later removed by layout_basetypes.  */
  
*************** build_base_fields (rec, empty_p)
*** 3756,3813 ****
    /* Chain to hold all the new FIELD_DECLs which stand in for base class
       subobjects.  */
    tree base_decls = NULL_TREE;
-   tree binfos = TYPE_BINFO_BASETYPES (rec);
    int n_baseclasses = CLASSTYPE_N_BASECLASSES (rec);
    tree decl, nextdecl;
    int i, saw_empty = 0;
    unsigned int base_align = 0;
  
    for (i = 0; i < n_baseclasses; ++i)
      {
!       register tree base_binfo = TREE_VEC_ELT (binfos, i);
!       register tree basetype = BINFO_TYPE (base_binfo);
  
!       if (TYPE_SIZE (basetype) == 0)
! 	/* This error is now reported in xref_tag, thus giving better
! 	   location information.  */
  	continue;
  
        /* A primary virtual base class is allocated just like any other
  	 base class, but a non-primary virtual base is allocated
  	 later, in layout_basetypes.  */
        if (TREE_VIA_VIRTUAL (base_binfo) 
! 	  && i != CLASSTYPE_VFIELD_PARENT (rec))
  	continue;
  
!       decl = build_lang_decl (FIELD_DECL, NULL_TREE, basetype);
!       DECL_ARTIFICIAL (decl) = 1;
!       DECL_FIELD_CONTEXT (decl) = DECL_CLASS_CONTEXT (decl) = rec;
!       DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
!       DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
!       TREE_CHAIN (decl) = base_decls;
!       base_decls = decl;
! 
!       if (flag_new_abi && DECL_SIZE (decl) == integer_zero_node)
! 	saw_empty = 1;
!       else
! 	{
! 	  /* The containing class is non-empty because it has a
! 	     non-empty base class.  */
! 	  *empty_p = 0;
! 
! 	  if (! flag_new_abi)
! 	    {
! 	      /* Brain damage for backwards compatibility.  For no
! 		 good reason, the old layout_basetypes made every base
! 		 at least as large as the alignment for the bases up
! 		 to that point, gratuitously wasting space.  So we do
! 		 the same thing here.  */
! 	      base_align = MAX (base_align, DECL_ALIGN (decl));
! 	      DECL_SIZE (decl)
! 		= size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
! 				 (int) base_align));
! 	    }
! 	}
      }
  
    /* Reverse the list of fields so we allocate the bases in the proper
--- 3783,3832 ----
    /* Chain to hold all the new FIELD_DECLs which stand in for base class
       subobjects.  */
    tree base_decls = NULL_TREE;
    int n_baseclasses = CLASSTYPE_N_BASECLASSES (rec);
    tree decl, nextdecl;
    int i, saw_empty = 0;
    unsigned int base_align = 0;
  
+   /* Under the new ABI, the primary base class is always allocated
+      first.  */
+   if (flag_new_abi && CLASSTYPE_HAS_PRIMARY_BASE_P (rec))
+     {
+       tree primary_base;
+ 
+       primary_base = CLASSTYPE_PRIMARY_BINFO (rec);
+       base_decls = chainon (build_base_field (rec, 
+ 					      primary_base,
+ 					      empty_p,
+ 					      &saw_empty,
+ 					      &base_align),
+ 			    base_decls);
+     }
+ 
+   /* Now allocate the rest of the bases.  */
    for (i = 0; i < n_baseclasses; ++i)
      {
!       tree base_binfo;
  
!       /* Under the new ABI, the primary base was already allocated
! 	 above, so we don't need to allocate it again here.  */
!       if (flag_new_abi && i == CLASSTYPE_VFIELD_PARENT (rec))
  	continue;
  
+       base_binfo = BINFO_BASETYPE (TYPE_BINFO (rec), i);
+ 
        /* A primary virtual base class is allocated just like any other
  	 base class, but a non-primary virtual base is allocated
  	 later, in layout_basetypes.  */
        if (TREE_VIA_VIRTUAL (base_binfo) 
! 	  && !BINFO_PRIMARY_MARKED_P (base_binfo))
  	continue;
  
!       base_decls = chainon (build_base_field (rec, base_binfo,
! 					      empty_p,
! 					      &saw_empty,
! 					      &base_align),
! 			    base_decls);
      }
  
    /* Reverse the list of fields so we allocate the bases in the proper
*************** propagate_binfo_offsets (binfo, offset)
*** 4218,4223 ****
--- 4237,4270 ----
      }
  }
  
+ /* Remove *FIELD (which corresponds to the base given by BINFO) from
+    the field list for T.  */
+ 
+ static void
+ remove_base_field (t, binfo, field)
+      tree t;
+      tree binfo;
+      tree *field;
+ {
+   tree basetype = BINFO_TYPE (binfo);
+   tree offset;
+ 
+   my_friendly_assert (TREE_TYPE (*field) == basetype, 23897);
+ 
+   if (get_base_distance (basetype, t, 0, (tree*)0) == -2)
+     cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
+ 		basetype, t);
+ 
+   offset
+     = size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (*field)),
+ 		      BITS_PER_UNIT));
+   BINFO_OFFSET (binfo) = offset;
+   propagate_binfo_offsets (binfo, offset);
+ 
+   /* Remove this field.  */
+   *field = TREE_CHAIN (*field);
+ }
+ 
  /* Remove the FIELD_DECLs created for T's base classes in
     build_base_fields.  Simultaneously, update BINFO_OFFSET for all the
     bases, except for non-primary virtual baseclasses.  */
*************** remove_base_fields (t)
*** 4244,4274 ****
  			  19991218);
        field = &TREE_CHAIN (*field);
      }
!     
    for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); i++)
      {
!       register tree base_binfo = BINFO_BASETYPE (TYPE_BINFO (t), i);
!       register tree basetype = BINFO_TYPE (base_binfo);
  
!       /* We treat a primary virtual base class just like an ordinary
! 	 base class.  But, non-primary virtual bases are laid out
! 	 later.  */
!       if (TREE_VIA_VIRTUAL (base_binfo) && i != CLASSTYPE_VFIELD_PARENT (t))
  	continue;
  
!       my_friendly_assert (TREE_TYPE (*field) == basetype, 23897);
  
!       if (get_base_distance (basetype, t, 0, (tree*)0) == -2)
! 	cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
! 		    basetype, t);
! 
!       BINFO_OFFSET (base_binfo)
! 	= size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (*field)),
! 			  BITS_PER_UNIT));
!       propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo));
  
!       /* Remove this field.  */
!       *field = TREE_CHAIN (*field);
      }
  }
  
--- 4291,4319 ----
  			  19991218);
        field = &TREE_CHAIN (*field);
      }
! 
!   /* Under the new ABI, the primary base is always allocated first.  */
!   if (flag_new_abi && CLASSTYPE_HAS_PRIMARY_BASE_P (t))
!     remove_base_field (t, CLASSTYPE_PRIMARY_BINFO (t), field);
! 
!   /* Now remove the rest of the bases.  */
    for (i = 0; i < CLASSTYPE_N_BASECLASSES (t); i++)
      {
!       tree binfo;
  
!       /* Under the new ABI, we've already removed the primary base
! 	 above.  */
!       if (flag_new_abi && i == CLASSTYPE_VFIELD_PARENT (t))
  	continue;
  
!       binfo = BINFO_BASETYPE (TYPE_BINFO (t), i);
  
!       /* We treat a primary virtual base class just like an ordinary base
! 	 class.  But, non-primary virtual bases are laid out later.  */
!       if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
! 	continue;
  
!       remove_base_field (t, binfo, field);
      }
  }
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]