C++ PATCH: More vcall offset preparation

Mark Mitchell mark@codesourcery.com
Fri Jan 28 19:59:00 GMT 2000


Here are some more changes to pave the way for the vcall-offset stuff
required by the new ABI.

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

2000-01-27  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.def (THUNK_DECL): Discuss vcall indices.
	* cp-tree.h (BINFO_VIRTUALS): Update documentation.
	(BF_DELTA): New macro.
	(BF_VCALL_INDEX): Likewise.
	(BF_FN): Likewise.
	(THUNK_VCALL_OFFSET): Likewise.
	(make_thunk): Change prototype.
	* class.c (build_vtable_entry): Integrate
	build_vtable_entry_for_fn.  Handle vcall indices.
	(build_vtable_entry_for_fn): Remove.
	(set_rtti_entry): Handle vcall indices.  Use BF_DELTA,
	BF_VCALL_INDEX, BF_FN.
	(modify_vtable_entry): Integrate common code from
	modify_one_vtable and dfs_fixup_vtable_deltas.
	(add_virtual_function): Set BF_VCALL_INDEX.
	(build_vtbl_initializer): Simplify.  Use BF_DELTA, BF_VCALL_INDEX,
	and BF_FN.
	(modify_one_vtable): Simplify.
	(dfs_fixup_vtable_deltas): Likewise.
	(override_one_vtable): Use BF_DELTA, BF_VCALL_INDEX, BF_FN. 
	* method.c (make_thunk): Handle vcall indices.

Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.246
diff -c -p -r1.246 class.c
*** class.c	2000/01/26 20:51:33	1.246
--- class.c	2000/01/29 03:56:13
*************** static class_stack_node_t current_class_
*** 75,81 ****
  static tree get_vfield_name PARAMS ((tree));
  static void finish_struct_anon PARAMS ((tree));
  static tree build_vbase_pointer PARAMS ((tree, tree));
! static tree build_vtable_entry PARAMS ((tree, tree));
  static tree get_vtable_name PARAMS ((tree));
  static tree get_derived_offset PARAMS ((tree, tree));
  static tree get_basefndecls PARAMS ((tree, tree));
--- 75,81 ----
  static tree get_vfield_name PARAMS ((tree));
  static void finish_struct_anon PARAMS ((tree));
  static tree build_vbase_pointer PARAMS ((tree, tree));
! static tree build_vtable_entry PARAMS ((tree, tree, tree));
  static tree get_vtable_name PARAMS ((tree));
  static tree get_derived_offset PARAMS ((tree, tree));
  static tree get_basefndecls PARAMS ((tree, tree));
*************** static void prepare_fresh_vtable PARAMS 
*** 85,92 ****
  static tree dfs_fixup_vtable_deltas PARAMS ((tree, void *));
  static tree dfs_finish_vtbls PARAMS ((tree, void *));
  static void finish_vtbls PARAMS ((tree));
! static void modify_vtable_entry PARAMS ((tree, tree, tree));
! static tree get_vtable_entry_n PARAMS ((tree, unsigned HOST_WIDE_INT));
  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));
--- 85,91 ----
  static tree dfs_fixup_vtable_deltas PARAMS ((tree, void *));
  static tree dfs_finish_vtbls PARAMS ((tree, void *));
  static void finish_vtbls PARAMS ((tree));
! static void modify_vtable_entry PARAMS ((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 tree fixed_type_or_null PARAMS ((
*** 114,120 ****
  static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int,
  							  int, tree));
  static void build_vtable_entry_ref PARAMS ((tree, tree, tree));
- static tree build_vtable_entry_for_fn PARAMS ((tree, tree));
  static tree build_vtbl_initializer PARAMS ((tree, tree));
  static int count_fields PARAMS ((tree));
  static int add_fields_to_vec PARAMS ((tree, tree, int));
--- 113,118 ----
*************** build_vbase_path (code, type, expr, path
*** 683,705 ****
  
  /* Virtual function things.  */
  
! /* Build an entry in the virtual function table.
!    DELTA is the offset for the `this' pointer.
!    PFN is an ADDR_EXPR containing a pointer to the virtual function.
!    Note that the index (DELTA2) in the virtual function table
!    is always 0.  */
  
  static tree
! build_vtable_entry (delta, pfn)
!      tree delta, pfn;
  {
    if (flag_vtable_thunks)
      {
!       HOST_WIDE_INT idelta = TREE_INT_CST_LOW (delta);
!       if (idelta && ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (pfn, 0)))
  	{
! 	  pfn = build1 (ADDR_EXPR, vtable_entry_type,
! 			make_thunk (pfn, idelta));
  	  TREE_READONLY (pfn) = 1;
  	  TREE_CONSTANT (pfn) = 1;
  	}
--- 681,717 ----
  
  /* Virtual function things.  */
  
! /* Build an entry in the virtual function table.  DELTA is the offset
!    for the `this' pointer.  VCALL_INDEX is the vtable index containing
!    the vcall offset; zero if none.  FNDECL is the virtual function
!    itself.  */
  
  static tree
! build_vtable_entry (delta, vcall_index, fndecl)
!      tree delta;
!      tree vcall_index;
!      tree fndecl;
  {
+   tree pfn;
+ 
+   /* Take the address of the function, considering it to be of an
+      appropriate generic type.  */
+   pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl);
+   /* The address of a function can't change.  */
+   TREE_CONSTANT (pfn) = 1;
+ 
    if (flag_vtable_thunks)
      {
!       HOST_WIDE_INT idelta;
!       HOST_WIDE_INT ivindex;
! 
!       idelta = TREE_INT_CST_LOW (delta);
!       ivindex = TREE_INT_CST_LOW (vcall_index);
!       if ((idelta || ivindex) 
! 	  && ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (pfn, 0)))
  	{
! 	  pfn = make_thunk (pfn, idelta, ivindex);
! 	  pfn = build1 (ADDR_EXPR, vtable_entry_type, pfn);
  	  TREE_READONLY (pfn) = 1;
  	  TREE_CONSTANT (pfn) = 1;
  	}
*************** build_vtable_entry (delta, pfn)
*** 716,721 ****
--- 728,736 ----
  					 build_tree_list (NULL_TREE, pfn)));
        tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
  
+       /* We don't use vcall offsets when not using vtable thunks.  */
+       my_friendly_assert (integer_zerop (vcall_index), 20000125);
+ 
        /* DELTA used to be constructed by `size_int' and/or size_binop,
  	 which caused overflow problems when it was negative.  That should
  	 be fixed now.  */
*************** build_vtable_entry (delta, pfn)
*** 740,764 ****
      }
  }
  
- /* Build a vtable entry for FNDECL.  DELTA is the amount by which we
-    must adjust the this pointer when calling F.  */
- 
- static tree
- build_vtable_entry_for_fn (delta, fndecl)
-      tree delta;
-      tree fndecl;
- {
-   tree pfn;
- 
-   /* Take the address of the function, considering it to be of an
-      appropriate generic type.  */
-   pfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl);
-   /* The address of a function can't change.  */
-   TREE_CONSTANT (pfn) = 1;
-   /* Now build the vtable entry itself.  */
-   return build_vtable_entry (delta, pfn);
- }
- 
  /* We want to give the assembler the vtable identifier as well as
     the offset to the function pointer.  So we generate
  
--- 755,760 ----
*************** set_rtti_entry (virtuals, offset, type)
*** 981,987 ****
    if (flag_vtable_thunks)
      {
        /* The first slot holds the offset.  */
!       TREE_PURPOSE (virtuals) = offset;
  
        /* The next node holds the function.  */
        virtuals = TREE_CHAIN (virtuals);
--- 977,984 ----
    if (flag_vtable_thunks)
      {
        /* The first slot holds the offset.  */
!       BF_DELTA (virtuals) = offset;
!       BF_VCALL_INDEX (virtuals) = integer_zero_node;
  
        /* The next node holds the function.  */
        virtuals = TREE_CHAIN (virtuals);
*************** set_rtti_entry (virtuals, offset, type)
*** 989,996 ****
      }
  
    /* This slot holds the function to call.  */
!   TREE_PURPOSE (virtuals) = offset;
!   TREE_VALUE (virtuals) = fn;
  }
  
  /* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic,
--- 986,994 ----
      }
  
    /* This slot holds the function to call.  */
!   BF_DELTA (virtuals) = offset;
!   BF_VCALL_INDEX (virtuals) = integer_zero_node;
!   BF_FN (virtuals) = fn;
  }
  
  /* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic,
*************** prepare_fresh_vtable (binfo, for_type)
*** 1260,1301 ****
    SET_BINFO_NEW_VTABLE_MARKED (binfo);
  }
  
! /* Change the offset for the FNDECL entry to NEW_OFFSET.  Also update
!    DECL_VINDEX (FNDECL).  */
  
  static void
! modify_vtable_entry (old_entry_in_list, new_offset, fndecl)
!      tree old_entry_in_list, new_offset, fndecl;
  {
!   tree base_fndecl = TREE_VALUE (old_entry_in_list);
! 
!   /* Update the entry.  */
!   TREE_PURPOSE (old_entry_in_list) = new_offset;
!   TREE_VALUE (old_entry_in_list) = fndecl;
! 
!   /* Now assign virtual dispatch information, if unset.  We can
!      dispatch this, through any overridden base function.  */
!   if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
      {
!       DECL_VINDEX (fndecl) = DECL_VINDEX (base_fndecl);
!       DECL_VIRTUAL_CONTEXT (fndecl) = DECL_VIRTUAL_CONTEXT (base_fndecl);
!     }
! }
  
! /* Access the virtual function table entry N.  VIRTUALS is the virtual
!    function table's initializer.  */
  
! static tree
! get_vtable_entry_n (virtuals, n)
!      tree virtuals;
!      unsigned HOST_WIDE_INT n;
! {
!   while (n > 0)
!     {
!       --n;
!       virtuals = TREE_CHAIN (virtuals);
      }
-   return virtuals;
  }
  
  /* Call this function whenever its known that a vtable for T is going
--- 1258,1328 ----
    SET_BINFO_NEW_VTABLE_MARKED (binfo);
  }
  
! /* Make V, an entry on the BINFO_VIRTUALS list for BINFO (which is in
!    the hierarchy dominated by T) list FNDECL as its BF_FN.  */
  
  static void
! modify_vtable_entry (t, binfo, fndecl, v)
!      tree t;
!      tree binfo;
!      tree fndecl;
!      tree v;
  {
!   tree base_offset, offset;
!   tree context = DECL_CLASS_CONTEXT (fndecl);
!   tree vfield = TYPE_VFIELD (t);
!   tree this_offset;
!   tree vcall_index;
! 
!   offset = get_class_offset (context, t, binfo, fndecl);
! 
!   /* Find the right offset for ythe this pointer based on the
!      base class we just found.  We have to take into
!      consideration the virtual base class pointers that we
!      stick in before the virtual function table pointer.
! 
!      Also, we want just the delta between the most base class
!      that we derived this vfield from and us.  */
!   base_offset 
!     = size_binop (PLUS_EXPR,
! 		  get_derived_offset (binfo, 
! 				      DECL_VIRTUAL_CONTEXT (BF_FN (v))),
! 		  BINFO_OFFSET (binfo));
!   this_offset = ssize_binop (MINUS_EXPR, offset, base_offset);
!   vcall_index = integer_zero_node;
! 
!   if (fndecl != BF_FN (v)
!       || !tree_int_cst_equal (this_offset, BF_DELTA (v))
!       || !tree_int_cst_equal (vcall_index, BF_VCALL_INDEX (v)))
      {
!       tree base_fndecl;
  
!       /* Make sure we can modify the derived association with immunity.  */
!       if (binfo == TYPE_BINFO (t))
! 	/* In this case, it is *type*'s vtable we are modifying.  We
! 	   start with the approximation that it's vtable is that of
! 	   the immediate base class.  */
! 	build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t);
!       else
! 	/* This is our very own copy of `basetype' to play with.
! 	   Later, we will fill in all the virtual functions that
! 	   override the virtual functions in these base classes which
! 	   are not defined by the current type.  */
! 	prepare_fresh_vtable (binfo, t);
  
!       base_fndecl = BF_FN (v);
!       BF_DELTA (v) = this_offset;
!       BF_VCALL_INDEX (v) = vcall_index;
!       BF_FN (v) = fndecl;
! 
!       /* Now assign virtual dispatch information, if unset.  We can
! 	 dispatch this, through any overridden base function.  */
!       if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
! 	{
! 	  DECL_VINDEX (fndecl) = DECL_VINDEX (base_fndecl);
! 	  DECL_VIRTUAL_CONTEXT (fndecl) = DECL_VIRTUAL_CONTEXT (base_fndecl);
! 	}
      }
  }
  
  /* Call this function whenever its known that a vtable for T is going
*************** add_virtual_function (new_virtuals_p, ov
*** 1337,1350 ****
       tree fndecl;
       tree t; /* Structure type.  */
  {
    /* 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.  */
!     ;
!   else if (DECL_VINDEX (fndecl) == error_mark_node)
      {
        /* FNDECL is a new virtual function; it doesn't override any
  	 virtual function in a base class.  */
--- 1364,1383 ----
       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 = build_tree_list (integer_zero_node, fndecl);
!   BF_VCALL_INDEX (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.  */
*************** add_virtual_function (new_virtuals_p, ov
*** 1359,1373 ****
        DECL_VIRTUAL_CONTEXT (fndecl) = t;
  
        /* Save the state we've computed on the NEW_VIRTUALS list.  */
!       *new_virtuals_p = tree_cons (integer_zero_node,
! 				   fndecl,
! 				   *new_virtuals_p);
!     }
!   else if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
!     /* FNDECL overrides a function from a base class.  */
!     *overridden_virtuals_p = tree_cons (NULL_TREE, 
! 					fndecl, 
! 					*overridden_virtuals_p);
  }
  
  extern struct obstack *current_obstack;
--- 1392,1406 ----
        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;
!     }
  }
  
  extern struct obstack *current_obstack;
*************** build_vtbl_initializer (binfo, t)
*** 2612,2618 ****
  	 we can put it in the vtable.  */
        init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
        TREE_CONSTANT (init) = 1;
-       init = build_vtable_entry (integer_zero_node, init);
        inits = tree_cons (NULL_TREE, init, inits);
  
        /* Even in this case, the second entry (the tdesc pointer) is
--- 2645,2650 ----
*************** build_vtbl_initializer (binfo, t)
*** 2625,2637 ****
    while (v)
      {
        tree delta;
        tree fn;
        tree init;
  
        /* Pull the offset for `this', and the function to call, out of
  	 the list.  */
!       delta = TREE_PURPOSE (v);
!       fn = TREE_VALUE (v);
        my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
        my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
  
--- 2657,2671 ----
    while (v)
      {
        tree delta;
+       tree vcall_index;
        tree fn;
        tree init;
  
        /* Pull the offset for `this', and the function to call, out of
  	 the list.  */
!       delta = BF_DELTA (v);
!       vcall_index = BF_VCALL_INDEX (v);
!       fn = BF_FN (v);
        my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
        my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
  
*************** build_vtbl_initializer (binfo, t)
*** 2641,2647 ****
  	fn = abort_fndecl;
  
        /* Package up that information for the vtable.  */
!       init = build_vtable_entry_for_fn (delta, fn);
        /* And add it to the chain of initializers.  */
        inits = tree_cons (NULL_TREE, init, inits);
  
--- 2675,2681 ----
  	fn = abort_fndecl;
  
        /* Package up that information for the vtable.  */
!       init = build_vtable_entry (delta, vcall_index, fn);
        /* And add it to the chain of initializers.  */
        inits = tree_cons (NULL_TREE, init, inits);
  
*************** modify_one_vtable (binfo, t, fndecl)
*** 2908,2918 ****
    if (fndecl == NULL_TREE)
      return;
  
!   virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
! 
!   while (virtuals)
      {
!       tree current_fndecl = TREE_VALUE (virtuals);
  
        /* We should never have an instance of __pure_virtual on the
  	 BINFO_VIRTUALS list.  If we do, then we will never notice
--- 2942,2952 ----
    if (fndecl == NULL_TREE)
      return;
  
!   for (virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
!        virtuals;
!        virtuals = TREE_CHAIN (virtuals), ++n)
      {
!       tree current_fndecl = BF_FN (virtuals);
  
        /* We should never have an instance of __pure_virtual on the
  	 BINFO_VIRTUALS list.  If we do, then we will never notice
*************** modify_one_vtable (binfo, t, fndecl)
*** 2922,2968 ****
  			  19990727);
  
        if (current_fndecl && overrides (fndecl, current_fndecl))
! 	{
! 	  tree base_offset, offset;
! 	  tree context = DECL_CLASS_CONTEXT (fndecl);
! 	  tree vfield = TYPE_VFIELD (t);
! 	  tree this_offset;
! 
! 	  offset = get_class_offset (context, t, binfo, fndecl);
! 
! 	  /* Find the right offset for the this pointer based on the
! 	     base class we just found.  We have to take into
! 	     consideration the virtual base class pointers that we
! 	     stick in before the virtual function table pointer.
! 
! 	     Also, we want just the delta between the most base class
! 	     that we derived this vfield from and us.  */
! 	  base_offset = size_binop (PLUS_EXPR,
! 				    get_derived_offset (binfo, DECL_CONTEXT (current_fndecl)),
! 				    BINFO_OFFSET (binfo));
! 	  this_offset = ssize_binop (MINUS_EXPR, offset, base_offset);
! 
! 	  if (binfo == TYPE_BINFO (t))
! 	    /* In this case, it is *type*'s vtable we are modifying.
! 	       We start with the approximation that it's vtable is
! 	       that of the immediate base class.  */
! 	      build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t);
! 	  else
! 	    /* This is our very own copy of `basetype' to play with.
! 	       Later, we will fill in all the virtual functions that
! 	       override the virtual functions in these base classes
! 	       which are not defined by the current type.  */
! 	    prepare_fresh_vtable (binfo, t);
! 
! #ifdef NOTQUITE
! 	  cp_warning ("in %D", DECL_NAME (BINFO_VTABLE (binfo)));
! #endif
! 	  modify_vtable_entry (get_vtable_entry_n (BINFO_VIRTUALS (binfo), n),
! 			       this_offset,
! 			       fndecl);
! 	}
!       ++n;
!       virtuals = TREE_CHAIN (virtuals);
      }
  }
  
--- 2956,2962 ----
  			  19990727);
  
        if (current_fndecl && overrides (fndecl, current_fndecl))
! 	modify_vtable_entry (t, binfo, fndecl, virtuals);
      }
  }
  
*************** dfs_fixup_vtable_deltas (binfo, data)
*** 3083,3141 ****
        if (TREE_VIA_VIRTUAL (binfo))
  	return NULL_TREE;
      }
- 
-   virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
  
!   while (virtuals)
      {
!       tree fndecl = TREE_VALUE (virtuals);
!       tree delta = TREE_PURPOSE (virtuals);
  
        if (fndecl)
! 	{
! 	  tree base_offset, offset;
! 	  tree context = DECL_CLASS_CONTEXT (fndecl);
! 	  tree vfield = TYPE_VFIELD (t);
! 	  tree this_offset;
! 
! 	  offset = get_class_offset (context, t, binfo, fndecl);
! 
! 	  /* Find the right offset for the this pointer based on the
! 	     base class we just found.  We have to take into
! 	     consideration the virtual base class pointers that we
! 	     stick in before the virtual function table pointer.
! 
! 	     Also, we want just the delta between the most base class
! 	     that we derived this vfield from and us.  */
! 	  base_offset = size_binop (PLUS_EXPR,
! 				    get_derived_offset (binfo,
! 							DECL_CONTEXT (fndecl)),
! 				    BINFO_OFFSET (binfo));
! 	  this_offset = ssize_binop (MINUS_EXPR, offset, base_offset);
! 
! 	  if (! tree_int_cst_equal (this_offset, delta))
! 	    {
! 	      /* Make sure we can modify the derived association with immunity.  */
! 	      if (binfo == TYPE_BINFO (t))
! 		/* In this case, it is *type*'s vtable we are modifying.
! 		   We start with the approximation that it's vtable is that
! 		   of the immediate base class.  */
! 		build_vtable (TYPE_BINFO (DECL_CONTEXT (vfield)), t);
! 	      else
! 		/* This is our very own copy of `basetype' to play
! 		   with.  Later, we will fill in all the virtual
! 		   functions that override the virtual functions in
! 		   these base classes which are not defined by the
! 		   current type.  */
! 		prepare_fresh_vtable (binfo, t);
! 
! 	      modify_vtable_entry (get_vtable_entry_n (BINFO_VIRTUALS (binfo), n),
! 				   this_offset,
! 				   fndecl);
! 	    }
! 	}
!       ++n;
!       virtuals = TREE_CHAIN (virtuals);
      }
  
    return NULL_TREE;
--- 3077,3091 ----
        if (TREE_VIA_VIRTUAL (binfo))
  	return NULL_TREE;
      }
  
!   for (virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
!        virtuals;
!        virtuals = TREE_CHAIN (virtuals), ++n)
      {
!       tree fndecl = BF_FN (virtuals);
  
        if (fndecl)
! 	modify_vtable_entry (t, binfo, fndecl, virtuals);
      }
  
    return NULL_TREE;
*************** override_one_vtable (binfo, old, t)
*** 3206,3213 ****
  
    while (orig_virtuals)
      {
!       tree fndecl = TREE_VALUE (virtuals);
!       tree old_fndecl = TREE_VALUE (old_virtuals);
  
        /* First check to see if they are the same.  */
        if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (old_fndecl))
--- 3156,3163 ----
  
    while (orig_virtuals)
      {
!       tree fndecl = BF_FN (virtuals);
!       tree old_fndecl = BF_FN (old_virtuals);
  
        /* First check to see if they are the same.  */
        if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (old_fndecl))
*************** override_one_vtable (binfo, old, t)
*** 3260,3266 ****
  	    }
  	  {
  	    /* This MUST be overridden, or the class is ill-formed.  */
! 	    tree fndecl = TREE_VALUE (virtuals);
  
  	    fndecl = copy_node (fndecl);
  	    copy_lang_decl (fndecl);
--- 3210,3216 ----
  	    }
  	  {
  	    /* This MUST be overridden, or the class is ill-formed.  */
! 	    tree fndecl = BF_FN (virtuals);
  
  	    fndecl = copy_node (fndecl);
  	    copy_lang_decl (fndecl);
*************** override_one_vtable (binfo, old, t)
*** 3271,3278 ****
  
  	    /* We can use integer_zero_node, as we will core dump
  	       if this is used anyway.  */
! 	    TREE_PURPOSE (virtuals) = integer_zero_node;
! 	    TREE_VALUE (virtuals) = fndecl;
  	  }
  	}
        virtuals = TREE_CHAIN (virtuals);
--- 3221,3228 ----
  
  	    /* We can use integer_zero_node, as we will core dump
  	       if this is used anyway.  */
! 	    BF_DELTA (virtuals) = integer_zero_node;
! 	    BF_FN (virtuals) = fndecl;
  	  }
  	}
        virtuals = TREE_CHAIN (virtuals);
Index: cp-tree.def
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.def,v
retrieving revision 1.44
diff -c -p -r1.44 cp-tree.def
*** cp-tree.def	1999/12/15 09:18:21	1.44
--- cp-tree.def	2000/01/29 03:56:14
***************
*** 1,7 ****
  /* This file contains the definitions and documentation for the
     additional tree codes used in the GNU C++ compiler (see tree.def
     for the standard codes).
!    Copyright (C) 1987,88,90,93,97-8,1999 Free Software Foundation, Inc.
     Hacked by Michael Tiemann (tiemann@cygnus.com)
  
  This file is part of GNU CC.
--- 1,7 ----
  /* This file contains the definitions and documentation for the
     additional tree codes used in the GNU C++ compiler (see tree.def
     for the standard codes).
!    Copyright (C) 1987,88,90,93,97-8,1999, 2000 Free Software Foundation, Inc.
     Hacked by Michael Tiemann (tiemann@cygnus.com)
  
  This file is part of GNU CC.
*************** DEFTREECODE (TYPEOF_TYPE, "typeof_type",
*** 159,170 ****
  
  /* A thunk is a stub function.
  
!    Thunks are used to implement multiple inheritance:
!    At run-time, such a thunk subtracts THUNK_DELTA (an int, not a tree)
!    from the this pointer, and then jumps to DECL_INITIAL
!    (which is an ADDR_EXPR whose operand is a FUNCTION_DECL).
! 
!    Other kinds of thunks may be defined later. */
  DEFTREECODE (THUNK_DECL, "thunk_decl", 'd', 0)
  
  /* A using declaration.  DECL_INITIAL contains the specified scope.  
--- 159,180 ----
  
  /* A thunk is a stub function.
  
!    A THUNK_DECL is an alternate entry point for an ordinary
!    FUNCTION_DECL.  It's job is to adjust the `this' poitner before
!    transferring control to the FUNCTION_DECL.
! 
!    A thunk may perform either, or both, of the following operations:
! 
!    o Adjust the `this' pointer by a constant offset.
!    o Adjust the `this' pointer by looking up a vcall-offset
!      in the vtable.
! 
!    If both operations are performed, then the constant adjument to
!    `this' is performed first.
! 
!    The constant adjustment is given by THUNK_DELTA.  If the
!    vcall-offset is required, the index into the vtable is given by
!    THUNK_VCALL_OFFSET.  */
  DEFTREECODE (THUNK_DECL, "thunk_decl", 'd', 0)
  
  /* A using declaration.  DECL_INITIAL contains the specified scope.  
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.395
diff -c -p -r1.395 cp-tree.h
*** cp-tree.h	2000/01/26 20:51:33	1.395
--- cp-tree.h	2000/01/29 03:56:17
*************** Boston, MA 02111-1307, USA.  */
*** 115,130 ****
       For a static VAR_DECL, this is DECL_INIT_PRIORITY.
  
     BINFO_VIRTUALS
!      For a binfo, this is a TREE_LIST.  The TREE_PURPOSE of each node
       gives the amount by which to adjust the `this' pointer when
       calling the function.  If the method is an overriden version of a
       base class method, then it is assumed that, prior to adjustment,
       the this pointer points to an object of the base class.
  
!      The TREE_VALUE is the declaration for the virtual function
!      itself.  When CLASSTYPE_COM_INTERFACE_P does not hold, the first
!      entry does not have a TREE_VALUE; it is just an offset.
  
     DECL_ARGUMENTS
       For a VAR_DECL this is DECL_ANON_UNION_ELEMS.  
  
--- 115,133 ----
       For a static VAR_DECL, this is DECL_INIT_PRIORITY.
  
     BINFO_VIRTUALS
!      For a binfo, this is a TREE_LIST.  The BF_DELTA of each node
       gives the amount by which to adjust the `this' pointer when
       calling the function.  If the method is an overriden version of a
       base class method, then it is assumed that, prior to adjustment,
       the this pointer points to an object of the base class.
  
!      The BF_VCALL_INDEX of each node, if non-NULL, gives the vtable
!      index of the vcall offset for this entry.
  
+      The BF_FN is the declaration for the virtual function itself.
+      When CLASSTYPE_COM_INTERFACE_P does not hold, the first entry
+      does not have a BF_FN; it is just an offset.
+ 
     DECL_ARGUMENTS
       For a VAR_DECL this is DECL_ANON_UNION_ELEMS.  
  
*************** struct lang_type
*** 1715,1720 ****
--- 1718,1735 ----
  
  /* Get the value of the top-most type dominating the non-`normal' vfields.  */
  #define VF_DERIVED_VALUE(NODE) (VF_BINFO_VALUE (NODE) ? BINFO_TYPE (VF_BINFO_VALUE (NODE)) : NULL_TREE)
+ 
+ /* The number of bytes by which to adjust the `this' pointer when
+    calling this virtual function.  */
+ #define BF_DELTA(NODE) (TREE_PURPOSE (NODE))
+ 
+ /* If non-NULL, the vtable index at which to find the vcall offset
+    when calling this virtual function.  */
+ #define BF_VCALL_INDEX(NODE) (TREE_TYPE (NODE))
+ 
+ /* The function to call.  */
+ #define BF_FN(NODE) (TREE_VALUE (NODE))
+ 
  
  /* Nonzero for TREE_LIST node means that this list of things
     is a list of parameters, as opposed to a list of expressions.  */
*************** extern int flag_new_for_scope;
*** 2784,2791 ****
--- 2799,2814 ----
  #define DECL_REALLY_EXTERN(NODE) \
    (DECL_EXTERNAL (NODE) && ! DECL_NOT_REALLY_EXTERN (NODE))
  
+ /* An integer indicating how many bytes should be subtracted from the
+    `this' pointer when this function is called.  */
  #define THUNK_DELTA(DECL) ((DECL)->decl.frame_size.i)
  
+ /* An integer indicating how many bytes should be subtracted from the
+    vtable for the `this' pointer to find the vcall offset.  (The vptr
+    is always located at offset zero from the `this' pointer.)  If
+    zero, then there is no vcall offset.  */
+ #define THUNK_VCALL_OFFSET(DECL) (DECL_FIELD_SIZE (DECL))
+ 
  /* DECL_NEEDED_P holds of a declaration when we need to emit its
     definition.  This is true when the back-end tells us that
     the symbol has been referenced in the generated code.  If, however,
*************** extern tree build_overload_with_type		PA
*** 3913,3919 ****
  extern tree build_destructor_name		PARAMS ((tree));
  extern tree build_opfncall			PARAMS ((enum tree_code, int, tree, tree, tree));
  extern tree hack_identifier			PARAMS ((tree, tree));
! extern tree make_thunk				PARAMS ((tree, int));
  extern void emit_thunk				PARAMS ((tree));
  extern void synthesize_method			PARAMS ((tree));
  extern tree get_id_2				PARAMS ((const char *, tree));
--- 3936,3942 ----
  extern tree build_destructor_name		PARAMS ((tree));
  extern tree build_opfncall			PARAMS ((enum tree_code, int, tree, tree, tree));
  extern tree hack_identifier			PARAMS ((tree, tree));
! extern tree make_thunk				PROTO((tree, int, int));
  extern void emit_thunk				PARAMS ((tree));
  extern void synthesize_method			PARAMS ((tree));
  extern tree get_id_2				PARAMS ((const char *, tree));
Index: method.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/method.c,v
retrieving revision 1.133
diff -c -p -r1.133 method.c
*** method.c	2000/01/26 20:51:34	1.133
--- method.c	2000/01/29 03:56:18
*************** hack_identifier (value, name)
*** 2008,2016 ****
  
  
  tree
! make_thunk (function, delta)
       tree function;
       int delta;
  {
    tree thunk_id;
    tree thunk;
--- 2008,2017 ----
  
  
  tree
! make_thunk (function, delta, vcall_index)
       tree function;
       int delta;
+      int vcall_index;
  {
    tree thunk_id;
    tree thunk;
*************** make_thunk (function, delta)
*** 2033,2038 ****
--- 2034,2044 ----
      icat (-delta);
    OB_PUTC ('_');
    OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
+   if (vcall_index)
+     {
+       OB_PUTC ('_');
+       icat (vcall_index);
+     }
    OB_FINISH ();
    thunk_id = get_identifier (obstack_base (&scratch_obstack));
  
*************** make_thunk (function, delta)
*** 2052,2057 ****
--- 2058,2065 ----
        TREE_SET_CODE (thunk, THUNK_DECL);
        DECL_INITIAL (thunk) = function;
        THUNK_DELTA (thunk) = delta;
+       THUNK_VCALL_OFFSET (thunk) 
+ 	= vcall_index * TREE_INT_CST_LOW (TYPE_SIZE (vtable_entry_type));
        DECL_EXTERNAL (thunk) = 1;
        DECL_ARTIFICIAL (thunk) = 1;
        /* So that finish_file can write out any thunks that need to be: */


More information about the Gcc-patches mailing list