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]
Other format: [Raw text]

[c++ patch] ABI vtable ordering


Mark,
this fixes 7470 and lays down the trailing part of the primary
vtable in the ABI defined order. Rather than keep two separate
lists of new vfuncs and overridden vfuncs, we now have a single
list -- this makes the code a bit simpler :-)

Hmm, I guess a test case could build a ptr to mfunc and then
peek inside for the vtable index -- I'll try doing that.

booted & tested on i686-pc-linux-gnu on HEAD & 3.2 branch.
ok for both?

nathan

-- 
Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery LLC
         'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org
2002-08-03  Nathan Sidwell  <nathan@codesourcery.com>

	PR 7470.
	C++ ABI change - vfunc ordering.
	* class.c (add_virtual_function): Remove.
	(dfs_modify_all_vtables): Take list of all declared
	virtuals. Assign all that are not in primary base.
	(check_for_override): Adjust comments.
	(create_vtable_ptr): Take single list of virtuals. Build chain
	of declared virtuals here.
	(layout_class_type): Take single list of virtuals. Adjust.
	(finish_struct_1): Keep virtuals on single list. Adjust.

Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.458
diff -c -3 -p -r1.458 class.c
*** cp/class.c	23 Jul 2002 06:22:03 -0000	1.458
--- cp/class.c	3 Aug 2002 00:28:29 -0000
*************** static int build_primary_vtable PARAMS (
*** 112,118 ****
  static int build_secondary_vtable PARAMS ((tree, tree));
  static void finish_vtbls PARAMS ((tree));
  static void modify_vtable_entry PARAMS ((tree, tree, tree, tree, tree *));
- static void add_virtual_function PARAMS ((tree *, tree *, int *, tree, tree));
  static tree delete_duplicate_fields_1 PARAMS ((tree, tree));
  static void delete_duplicate_fields PARAMS ((tree));
  static void finish_struct_bits PARAMS ((tree));
--- 112,117 ----
*************** static void check_methods PARAMS ((tree)
*** 148,155 ****
  static void remove_zero_width_bit_fields PARAMS ((tree));
  static void check_bases PARAMS ((tree, int *, int *, int *));
  static void check_bases_and_members PARAMS ((tree, int *));
! static tree create_vtable_ptr PARAMS ((tree, int *, int *, tree *, tree *));
! static void layout_class_type PARAMS ((tree, int *, int *, tree *, tree *));
  static void fixup_pending_inline PARAMS ((tree));
  static void fixup_inline_methods PARAMS ((tree));
  static void set_primary_base PARAMS ((tree, tree, int *));
--- 147,154 ----
  static void remove_zero_width_bit_fields PARAMS ((tree));
  static void check_bases PARAMS ((tree, int *, int *, int *));
  static void check_bases_and_members PARAMS ((tree, int *));
! static tree create_vtable_ptr PARAMS ((tree, int *, int *, tree *));
! static void layout_class_type PARAMS ((tree, int *, int *, tree *));
  static void fixup_pending_inline PARAMS ((tree));
  static void fixup_inline_methods PARAMS ((tree));
  static void set_primary_base PARAMS ((tree, tree, int *));
*************** set_vindex (decl, vfuns_p)
*** 754,814 ****
  	       ? TARGET_VTABLE_USES_DESCRIPTORS : 1);
    DECL_VINDEX (decl) = build_shared_int_cst (vindex);
  }
- 
- /* Add a virtual function to all the appropriate vtables for the class
-    T.  DECL_VINDEX(X) should be error_mark_node, if we want to
-    allocate a new slot in our table.  If it is error_mark_node, we
-    know that no other function from another vtable is overridden by X.
-    VFUNS_P keeps track of how many virtuals there are in our
-    main vtable for the type, and we build upon the NEW_VIRTUALS list
-    and return it.  */
- 
- static void
- add_virtual_function (new_virtuals_p, overridden_virtuals_p,
- 		      vfuns_p, fndecl, t)
-      tree *new_virtuals_p;
-      tree *overridden_virtuals_p;
-      int *vfuns_p;
-      tree fndecl;
-      tree t; /* Structure type.  */
- {
-   tree new_virtual;
- 
-   /* If this function doesn't override anything from a base class, we
-      can just assign it a new DECL_VINDEX now.  Otherwise, if it does
-      override something, we keep it around and assign its DECL_VINDEX
-      later, in modify_all_vtables.  */
-   if (TREE_CODE (DECL_VINDEX (fndecl)) == INTEGER_CST)
-     /* We've already dealt with this function.  */
-     return;
- 
-   new_virtual = make_node (TREE_LIST);
-   BV_FN (new_virtual) = fndecl;
-   BV_DELTA (new_virtual) = integer_zero_node;
- 
-   if (DECL_VINDEX (fndecl) == error_mark_node)
-     {
-       /* FNDECL is a new virtual function; it doesn't override any
- 	 virtual function in a base class.  */
- 
-       /* We remember that this was the base sub-object for rtti.  */
-       CLASSTYPE_RTTI (t) = t;
- 
-       /* Now assign virtual dispatch information.  */
-       set_vindex (fndecl, vfuns_p);
-       DECL_VIRTUAL_CONTEXT (fndecl) = t;
- 
-       /* Save the state we've computed on the NEW_VIRTUALS list.  */
-       TREE_CHAIN (new_virtual) = *new_virtuals_p;
-       *new_virtuals_p = new_virtual;
-     }
-   else
-     {
-       /* FNDECL overrides a function from a base class.  */
-       TREE_CHAIN (new_virtual) = *overridden_virtuals_p;
-       *overridden_virtuals_p = new_virtual;
-     }
- }
  
  /* Add method METHOD to class TYPE.  If ERROR_P is true, we are adding
     the method after the class has already been defined because a
--- 753,758 ----
*************** dfs_modify_vtables (binfo, data)
*** 2626,2643 ****
  
  /* Update all of the primary and secondary vtables for T.  Create new
     vtables as required, and initialize their RTTI information.  Each
!    of the functions in OVERRIDDEN_VIRTUALS overrides a virtual
!    function from a base class; find and modify the appropriate entries
!    to point to the overriding functions.  Returns a list, in
!    declaration order, of the functions that are overridden in this
!    class, but do not appear in the primary base class vtable, and
!    which should therefore be appended to the end of the vtable for T.  */
  
  static tree
! modify_all_vtables (t, vfuns_p, overridden_virtuals)
       tree t;
       int *vfuns_p;
!      tree overridden_virtuals;
  {
    tree binfo = TYPE_BINFO (t);
    tree *fnsp;
--- 2570,2587 ----
  
  /* Update all of the primary and secondary vtables for T.  Create new
     vtables as required, and initialize their RTTI information.  Each
!    of the functions in VIRTUALS is declared in T and may override a
!    virtual function from a base class; find and modify the appropriate
!    entries to point to the overriding functions.  Returns a list, in
!    declaration order, of the virtual functions that are declared in T,
!    but do not appear in the primary base class vtable, and which
!    should therefore be appended to the end of the vtable for T.  */
  
  static tree
! modify_all_vtables (t, vfuns_p, virtuals)
       tree t;
       int *vfuns_p;
!      tree virtuals;
  {
    tree binfo = TYPE_BINFO (t);
    tree *fnsp;
*************** modify_all_vtables (t, vfuns_p, overridd
*** 2649,2662 ****
  	    t);
    dfs_walk (binfo, dfs_unmark, dfs_marked_real_bases_queue_p, t);
  
!   /* Include overriding functions for secondary vtables in our primary
!      vtable.  */
!   for (fnsp = &overridden_virtuals; *fnsp; )
      {
        tree fn = TREE_VALUE (*fnsp);
  
!       if (!BINFO_VIRTUALS (binfo)
! 	  || !value_member (fn, BINFO_VIRTUALS (binfo)))
  	{
  	  /* Set the vtable index.  */
  	  set_vindex (fn, vfuns_p);
--- 2593,2608 ----
  	    t);
    dfs_walk (binfo, dfs_unmark, dfs_marked_real_bases_queue_p, t);
  
!   /* Add virtual functions not already in our primary vtable. These
!      will be both those introduced by this class, and those overridden
!      from secondary bases.  It does not include virtuals merely
!      inherited from secondary bases.  */
!   for (fnsp = &virtuals; *fnsp; )
      {
        tree fn = TREE_VALUE (*fnsp);
  
!       if (!value_member (fn, BINFO_VIRTUALS (binfo))
! 	  || DECL_VINDEX (fn) == error_mark_node)
  	{
  	  /* Set the vtable index.  */
  	  set_vindex (fn, vfuns_p);
*************** modify_all_vtables (t, vfuns_p, overridd
*** 2669,2676 ****
  	  BV_DELTA (*fnsp) = integer_zero_node;
  	  BV_VCALL_INDEX (*fnsp) = NULL_TREE;
  
! 	  /* This is an overridden function not already in our
! 	     vtable.  Keep it.  */
  	  fnsp = &TREE_CHAIN (*fnsp);
  	}
        else
--- 2615,2621 ----
  	  BV_DELTA (*fnsp) = integer_zero_node;
  	  BV_VCALL_INDEX (*fnsp) = NULL_TREE;
  
! 	  /* This is a function not already in our vtable.  Keep it.  */
  	  fnsp = &TREE_CHAIN (*fnsp);
  	}
        else
*************** modify_all_vtables (t, vfuns_p, overridd
*** 2678,2684 ****
  	*fnsp = TREE_CHAIN (*fnsp);
      }
    
!   return overridden_virtuals;
  }
  
  /* Here, we already know that they match in every respect.
--- 2623,2629 ----
  	*fnsp = TREE_CHAIN (*fnsp);
      }
    
!   return virtuals;
  }
  
  /* Here, we already know that they match in every respect.
*************** check_for_override (decl, ctype)
*** 2748,2763 ****
         || IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)))
        && look_for_overrides (ctype, decl)
        && !DECL_STATIC_FUNCTION_P (decl))
!     {
!       /* Set DECL_VINDEX to a value that is neither an
! 	 INTEGER_CST nor the error_mark_node so that
! 	 add_virtual_function will realize this is an
! 	 overriding function.  */
!       DECL_VINDEX (decl) = decl;
!     }
    if (DECL_VIRTUAL_P (decl))
      {
!       if (DECL_VINDEX (decl) == NULL_TREE)
  	DECL_VINDEX (decl) = error_mark_node;
        IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
      }
--- 2693,2706 ----
         || IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)))
        && look_for_overrides (ctype, decl)
        && !DECL_STATIC_FUNCTION_P (decl))
!     /* Set DECL_VINDEX to a value that is neither an INTEGER_CST nor
!        the error_mark_node so that we know it is an overriding
!        function.  */
!     DECL_VINDEX (decl) = decl;
! 
    if (DECL_VIRTUAL_P (decl))
      {
!       if (!DECL_VINDEX (decl))
  	DECL_VINDEX (decl) = error_mark_node;
        IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
      }
*************** check_bases_and_members (t, empty_p)
*** 4379,4409 ****
     accordingly.  If a new vfield was created (because T doesn't have a
     primary base class), then the newly created field is returned.  It
     is not added to the TYPE_FIELDS list; it is the caller's
!    responsibility to do that.  */
  
  static tree
! create_vtable_ptr (t, empty_p, vfuns_p,
! 		   new_virtuals_p, overridden_virtuals_p)
       tree t;
       int *empty_p;
       int *vfuns_p;
!      tree *new_virtuals_p;
!      tree *overridden_virtuals_p;
  {
    tree fn;
  
!   /* Loop over the virtual functions, adding them to our various
!      vtables.  */
    for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
!     if (DECL_VINDEX (fn) && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
!       add_virtual_function (new_virtuals_p, overridden_virtuals_p,
! 			    vfuns_p, fn, t);
  
    /* If we couldn't find an appropriate base class, create a new field
       here.  Even if there weren't any new virtual functions, we might need a
       new virtual function table if we're supposed to include vptrs in
       all classes that need them.  */
!   if (!TYPE_VFIELD (t) && (*vfuns_p || TYPE_CONTAINS_VPTR_P (t)))
      {
        /* We build this decl with vtbl_ptr_type_node, which is a
  	 `vtable_entry_type*'.  It might seem more precise to use
--- 4322,4358 ----
     accordingly.  If a new vfield was created (because T doesn't have a
     primary base class), then the newly created field is returned.  It
     is not added to the TYPE_FIELDS list; it is the caller's
!    responsibility to do that.  Accumulate declared virtual functions
!    on VIRTUALS_P.  */
  
  static tree
! create_vtable_ptr (t, empty_p, vfuns_p, virtuals_p)
       tree t;
       int *empty_p;
       int *vfuns_p;
!      tree *virtuals_p;
  {
    tree fn;
  
!   /* Collect the virtual functions declared in T.  */
    for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
!     if (DECL_VINDEX (fn) && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)
! 	&& TREE_CODE (DECL_VINDEX (fn)) != INTEGER_CST)
!       {
! 	tree new_virtual = make_node (TREE_LIST);
! 	
! 	BV_FN (new_virtual) = fn;
! 	BV_DELTA (new_virtual) = integer_zero_node;
  
+ 	TREE_CHAIN (new_virtual) = *virtuals_p;
+ 	*virtuals_p = new_virtual;
+       }
+   
    /* If we couldn't find an appropriate base class, create a new field
       here.  Even if there weren't any new virtual functions, we might need a
       new virtual function table if we're supposed to include vptrs in
       all classes that need them.  */
!   if (!TYPE_VFIELD (t) && (*virtuals_p || TYPE_CONTAINS_VPTR_P (t)))
      {
        /* We build this decl with vtbl_ptr_type_node, which is a
  	 `vtable_entry_type*'.  It might seem more precise to use
*************** splay_tree_compare_integer_csts (k1, k2)
*** 4795,4810 ****
  
  /* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T.  Calculate
     BINFO_OFFSETs for all of the base-classes.  Position the vtable
!    pointer.  */
  
  static void
! layout_class_type (t, empty_p, vfuns_p, 
! 		   new_virtuals_p, overridden_virtuals_p)
       tree t;
       int *empty_p;
       int *vfuns_p;
!      tree *new_virtuals_p;
!      tree *overridden_virtuals_p;
  {
    tree non_static_data_members;
    tree field;
--- 4744,4757 ----
  
  /* Calculate the TYPE_SIZE, TYPE_ALIGN, etc for T.  Calculate
     BINFO_OFFSETs for all of the base-classes.  Position the vtable
!    pointer.  Accumulate declared virtual functions on VIRTUALS_P. */
  
  static void
! layout_class_type (t, empty_p, vfuns_p, virtuals_p)
       tree t;
       int *empty_p;
       int *vfuns_p;
!      tree *virtuals_p;
  {
    tree non_static_data_members;
    tree field;
*************** layout_class_type (t, empty_p, vfuns_p, 
*** 4826,4833 ****
    determine_primary_base (t, vfuns_p);
  
    /* Create a pointer to our virtual function table.  */
!   vptr = create_vtable_ptr (t, empty_p, vfuns_p,
! 			    new_virtuals_p, overridden_virtuals_p);
  
    /* The vptr is always the first thing in the class.  */
    if (vptr)
--- 4773,4779 ----
    determine_primary_base (t, vfuns_p);
  
    /* Create a pointer to our virtual function table.  */
!   vptr = create_vtable_ptr (t, empty_p, vfuns_p, virtuals_p);
  
    /* The vptr is always the first thing in the class.  */
    if (vptr)
*************** finish_struct_1 (t)
*** 5034,5048 ****
  {
    tree x;
    int vfuns;
!   /* The NEW_VIRTUALS is a TREE_LIST.  The TREE_VALUE of each node is
!      a FUNCTION_DECL.  Each of these functions is a virtual function
!      declared in T that does not override any virtual function from a
!      base class.  */
!   tree new_virtuals = NULL_TREE;
!   /* The OVERRIDDEN_VIRTUALS list is like the NEW_VIRTUALS list,
!      except that each declaration here overrides the declaration from
!      a base class.  */
!   tree overridden_virtuals = NULL_TREE;
    int n_fields = 0;
    tree vfield;
    int empty = 1;
--- 4980,4987 ----
  {
    tree x;
    int vfuns;
!   /* A TREE_LIST.  The TREE_VALUE of each node is a FUNCTION_DECL. */
!   tree virtuals = NULL_TREE;
    int n_fields = 0;
    tree vfield;
    int empty = 1;
*************** finish_struct_1 (t)
*** 5072,5079 ****
    check_bases_and_members (t, &empty);
  
    /* Layout the class itself.  */
!   layout_class_type (t, &empty, &vfuns,
! 		     &new_virtuals, &overridden_virtuals);
  
    /* Make sure that we get our own copy of the vfield FIELD_DECL.  */
    vfield = TYPE_VFIELD (t);
--- 5011,5017 ----
    check_bases_and_members (t, &empty);
  
    /* Layout the class itself.  */
!   layout_class_type (t, &empty, &vfuns, &virtuals);
  
    /* Make sure that we get our own copy of the vfield FIELD_DECL.  */
    vfield = TYPE_VFIELD (t);
*************** finish_struct_1 (t)
*** 5097,5104 ****
    else
      my_friendly_assert (!vfield || DECL_FIELD_CONTEXT (vfield) == t, 20010726);
  
!   overridden_virtuals 
!     = modify_all_vtables (t, &vfuns, nreverse (overridden_virtuals));
  
    /* If we created a new vtbl pointer for this class, add it to the
       list.  */
--- 5035,5041 ----
    else
      my_friendly_assert (!vfield || DECL_FIELD_CONTEXT (vfield) == t, 20010726);
  
!   virtuals = modify_all_vtables (t, &vfuns, nreverse (virtuals));
  
    /* If we created a new vtbl pointer for this class, add it to the
       list.  */
*************** finish_struct_1 (t)
*** 5107,5115 ****
        = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));
  
    /* If necessary, create the primary vtable for this class.  */
!   if (new_virtuals || overridden_virtuals || TYPE_CONTAINS_VPTR_P (t))
      {
-       new_virtuals = nreverse (new_virtuals);
        /* We must enter these virtuals into the table.  */
        if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
  	build_primary_vtable (NULL_TREE, t);
--- 5044,5051 ----
        = chainon (CLASSTYPE_VFIELDS (t), build_tree_list (NULL_TREE, t));
  
    /* If necessary, create the primary vtable for this class.  */
!   if (virtuals || TYPE_CONTAINS_VPTR_P (t))
      {
        /* We must enter these virtuals into the table.  */
        if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
  	build_primary_vtable (NULL_TREE, t);
*************** finish_struct_1 (t)
*** 5122,5128 ****
  	 constructors might clobber the virtual function table.  But
  	 they don't if the derived class shares the exact vtable of the base
  	 class.  */
- 
        CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
      }
    /* If we didn't need a new vtable, see if we should copy one from
--- 5058,5063 ----
*************** finish_struct_1 (t)
*** 5148,5161 ****
  			    20000116);
  
        CLASSTYPE_VSIZE (t) = vfuns;
!       /* Entries for virtual functions defined in the primary base are
! 	 followed by entries for new functions unique to this class.  */
!       TYPE_BINFO_VIRTUALS (t) 
! 	= chainon (TYPE_BINFO_VIRTUALS (t), new_virtuals);
!       /* Finally, add entries for functions that override virtuals
! 	 from non-primary bases.  */
!       TYPE_BINFO_VIRTUALS (t) 
! 	= chainon (TYPE_BINFO_VIRTUALS (t), overridden_virtuals);
      }
  
    finish_struct_bits (t);
--- 5083,5090 ----
  			    20000116);
  
        CLASSTYPE_VSIZE (t) = vfuns;
!       /* Add entries for virtual functions introduced by this class.  */
!       TYPE_BINFO_VIRTUALS (t) = chainon (TYPE_BINFO_VIRTUALS (t), virtuals);
      }
  
    finish_struct_bits (t);

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