C++ PATCH: implement vcall offset thunks

Mark Mitchell mark@codesourcery.com
Sun Apr 16 12:48:00 GMT 2000


This patch implements vcall offset thunks in the new ABI.  (They don't
yet get emitted only in the object files where the thunked-to function
is placed, though.)

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

2000-04-15  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.def (THUNK_DECL): Add to documentation.
	* cp-tree.h (flag_huge_objects): Declare.
	* class.c (modify_vtable_entry): Tidy.
	(update_vtable_entry_for_fn): Split out from dfs_modify_vtables.
	Calculate delta appropriately for the new ABI.
	(dfs_modify_vtables): Use it.
	(modify_all_vtables): Fix thinko in code to add overriding copies
	of functions to primary vtables.
	(build_clone): Fix typo in comment.
	(clone_function_decl): Correct order of destructors in vtable.
	(build_vbase_offset_vtbl_entries): Adjust comment.
	(dfs_vcall_offset_queue_p): Remove.
	(dfs_build_vcall_offset_vtbl_entries): Update BV_VCALL_INDEX.
	(build_vcall_offset_vtbl_entries): Juse use dfs_skip_vbases.
	(build_vtable_entry): Correct check for pure virtual functions.
	Don't declare flag_huge_objects.
	* decl.c (flag_huge_objects): Remove declaration.
	* method.c (make_thunk): Tweak mangling for vcall offset thunks.
	Use int_size_in_bytes.
	(emit_thunk): Handle vcall offset thunks.
	
Index: testsuite/g++.old-deja/g++.abi/vtable2.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C,v
retrieving revision 1.1
diff -c -p -r1.1 vtable2.C
*** vtable2.C	2000/04/04 18:13:21	1.1
--- vtable2.C	2000/04/16 18:53:17
*************** void S4::s1 ()
*** 108,117 ****
  
     S2-in-S4 secondary vtable
  
-      S4::s1 vcall offset
       S1 vbase offset
!      S2:s0 vcall offset
       S0 vbase offset
       S2 offset to top
       S4 RTTI
       S2::s0
--- 108,117 ----
  
     S2-in-S4 secondary vtable
  
       S1 vbase offset
!      S4::s1 vcall offset
       S0 vbase offset
+      S2:s0 vcall offset
       S2 offset to top
       S4 RTTI
       S2::s0
*************** int main ()
*** 151,160 ****
      return 5;
    if (*vtbl++ != (ptrdiff_t) &s1__2S4)
      return 6;
!   // All the vcall and vbase offsets should be zero.
    if (*vtbl++ != 0)
      return 7;
!   if (*vtbl++ != 0)
      return 8;
    if (*vtbl++ != 0)
      return 9;
--- 151,162 ----
      return 5;
    if (*vtbl++ != (ptrdiff_t) &s1__2S4)
      return 6;
!   // The S1 vbase offset.
    if (*vtbl++ != 0)
      return 7;
!   // The S4::s1 vcall offset is negative; once you convert to S2, you
!   // have to convert to S4 to find the final overrider.
!   if (*vtbl++ != ((char*) &s4 - (char*) (S2*) &s4))
      return 8;
    if (*vtbl++ != 0)
      return 9;
Index: cp/cp-tree.def
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.def,v
retrieving revision 1.46
diff -c -p -r1.46 cp-tree.def
*** cp-tree.def	2000/02/26 20:15:45	1.46
--- cp-tree.def	2000/04/16 18:53:23
*************** DEFTREECODE (TYPEOF_TYPE, "typeof_type",
*** 161,168 ****
  /* 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:
  
--- 161,170 ----
  /* A thunk is a stub function.
  
     A THUNK_DECL is an alternate entry point for an ordinary
!    FUNCTION_DECL.  The address of the ordinary FUNCTION_DECL is given
!    by the DECL_INITIAL, which is always an ADDR_EXPR whose operand is
!    a FUNCTION_DECL.  The job of the thunk is to adjust the `this'
!    pointer before transferring control to the FUNCTION_DECL.
  
     A thunk may perform either, or both, of the following operations:
  
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.442
diff -c -p -r1.442 cp-tree.h
*** cp-tree.h	2000/04/12 07:48:12	1.442
--- cp-tree.h	2000/04/16 18:53:26
*************** extern int flag_honor_std;
*** 219,224 ****
--- 219,229 ----
  
  extern int flag_rtti;
  
+ /* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes)
+    objects.  */
+ 
+ extern int flag_huge_objects;
+ 
  /* Nonzero if virtual base class offsets are stored in the virtual
     function table.  Zero if, instead, a pointer to the virtual base is
     stored in the object itself.  */
*************** struct lang_type
*** 1767,1773 ****
  
        struct A {};
        struct B : public A { };
!       struct C : virtual public B { void f(); };
  
     `A' is the primary base class for `B'.  But, `B' is not a primary
     base class for `C'.  So, in the copy of `A' that appears in the
--- 1772,1778 ----
  
        struct A {};
        struct B : public A { };
!       struct C : virtual public B { void f(); int i; };
  
     `A' is the primary base class for `B'.  But, `B' is not a primary
     base class for `C'.  So, in the copy of `A' that appears in the
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.292
diff -c -p -r1.292 class.c
*** class.c	2000/04/13 11:14:28	1.292
--- class.c	2000/04/16 18:53:23
*************** static void layout_virtual_bases PARAMS 
*** 146,152 ****
  static tree dfs_set_offset_for_shared_vbases PARAMS ((tree, void *));
  static tree dfs_set_offset_for_unshared_vbases PARAMS ((tree, void *));
  static void build_vbase_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *));
- static tree dfs_vcall_offset_queue_p PARAMS ((tree, void *));
  static tree dfs_build_vcall_offset_vtbl_entries PARAMS ((tree, void *));
  static void build_vcall_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *));
  static void layout_vtable_decl PARAMS ((tree, int));
--- 146,151 ----
*************** make_new_vtable (t, binfo)
*** 977,985 ****
  
  /* Make *VIRTUALS, an entry on the BINFO_VIRTUALS list for BINFO
     (which is in the hierarchy dominated by T) list FNDECL as its
!    BV_FN.  DELTA is the required adjustment from the `this' pointer
!    where the vtable entry appears to the `this' required when the
!    function is actually called.  */
  
  static void
  modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
--- 976,984 ----
  
  /* Make *VIRTUALS, an entry on the BINFO_VIRTUALS list for BINFO
     (which is in the hierarchy dominated by T) list FNDECL as its
!    BV_FN.  DELTA is the required constant adjustment from the `this'
!    pointer where the vtable entry appears to the `this' required when
!    the function is actually called.  */
  
  static void
  modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
*************** modify_vtable_entry (t, binfo, fndecl, d
*** 989,1003 ****
       tree delta;
       tree *virtuals;
  {
-   tree vcall_index;
    tree v;
  
    v = *virtuals;
-   vcall_index = integer_zero_node;
  
    if (fndecl != BV_FN (v)
!       || !tree_int_cst_equal (delta, BV_DELTA (v))
!       || !tree_int_cst_equal (vcall_index, BV_VCALL_INDEX (v)))
      {
        tree base_fndecl;
  
--- 988,999 ----
       tree delta;
       tree *virtuals;
  {
    tree v;
  
    v = *virtuals;
  
    if (fndecl != BV_FN (v)
!       || !tree_int_cst_equal (delta, BV_DELTA (v)))
      {
        tree base_fndecl;
  
*************** modify_vtable_entry (t, binfo, fndecl, d
*** 1015,1021 ****
  
        base_fndecl = BV_FN (v);
        BV_DELTA (v) = delta;
!       BV_VCALL_INDEX (v) = vcall_index;
        BV_FN (v) = fndecl;
  
        /* Now assign virtual dispatch information, if unset.  We can
--- 1011,1017 ----
  
        base_fndecl = BV_FN (v);
        BV_DELTA (v) = delta;
!       BV_VCALL_INDEX (v) = integer_zero_node;
        BV_FN (v) = fndecl;
  
        /* Now assign virtual dispatch information, if unset.  We can
*************** add_virtual_function (new_virtuals_p, ov
*** 1087,1093 ****
      /* We've already dealt with this function.  */
      return;
  
!   new_virtual = build_tree_list (integer_zero_node, fndecl);
    BV_VCALL_INDEX (new_virtual) = integer_zero_node;
  
    if (DECL_VINDEX (fndecl) == error_mark_node)
--- 1083,1090 ----
      /* We've already dealt with this function.  */
      return;
  
!   new_virtual = build_tree_list (NULL_TREE, fndecl);
!   BV_DELTA (new_virtual) = integer_zero_node;
    BV_VCALL_INDEX (new_virtual) = integer_zero_node;
  
    if (DECL_VINDEX (fndecl) == error_mark_node)
*************** dfs_find_base (binfo, data)
*** 2470,2475 ****
--- 2467,2546 ----
  	  ? binfo : NULL_TREE);
  }
  
+ static void
+ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
+      tree t;
+      tree binfo;
+      tree fn;
+      tree *virtuals;
+ {
+   tree b;
+   tree overrider;
+   tree vindex;
+   tree delta;
+   HOST_WIDE_INT vindex_val;
+   HOST_WIDE_INT i;
+ 
+   /* Find the function which originally caused this vtable
+      entry to be present.  */
+   vindex = DECL_VINDEX (fn);
+   b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn));
+   fn = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (b)));
+   i = first_vfun_index (BINFO_TYPE (b));
+   vindex_val = tree_low_cst (vindex, 0);
+   while (i < vindex_val)
+     {
+       fn = TREE_CHAIN (fn);
+       ++i;
+     }
+   fn = BV_FN (fn);
+ 
+   /* Handle the case of a virtual function defined in BINFO itself.  */
+   overrider = find_final_overrider (t, b, fn);
+   if (overrider == error_mark_node)
+     return;
+ 
+   /* Compute the constant adjustment to the `this' pointer.  The
+      `this' pointer, when this function is called, will point at the
+      class whose vtable this is.  */
+   delta = size_binop (PLUS_EXPR,
+ 		      get_derived_offset (binfo,
+ 					  DECL_VIRTUAL_CONTEXT (fn)),
+ 		      BINFO_OFFSET (binfo));
+   if (flag_new_abi)
+     {
+       /* Under the new ABI, we only need to adjust as far as the
+ 	 nearest virtual base.  Then we use the vcall offset in the
+ 	 virtual bases vtable.  */
+       for (b = binfo; b; b = BINFO_INHERITANCE_CHAIN (b))
+ 	{
+ 	  if (TREE_VIA_VIRTUAL (b))
+ 	    break;
+ 	  if (same_type_p (BINFO_TYPE (b), 
+ 			   BINFO_TYPE (TREE_VALUE (overrider))))
+ 	    break;
+ 	}
+     }
+   else
+     b = NULL_TREE;
+ 
+   if (b && TREE_VIA_VIRTUAL (b))
+     /* The `this' pointer needs to be adjusted to the nearest virtual
+        base.  */
+     delta = size_diffop (BINFO_OFFSET (b), delta);
+   else
+     /* The `this' pointer needs to be adjusted from pointing to
+        BINFO to pointing at the base where the final overrider
+        appears.  */
+     delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), delta);
+ 
+   modify_vtable_entry (t, 
+ 		       binfo, 
+ 		       TREE_PURPOSE (overrider),
+ 		       delta,
+ 		       virtuals);
+ }
+ 
  /* Called from modify_all_vtables via dfs_walk.  */
  
  static tree
*************** dfs_modify_vtables (binfo, data)
*** 2503,2553 ****
  	   virtuals;
  	   virtuals = TREE_CHAIN (virtuals),
  	     old_virtuals = TREE_CHAIN (old_virtuals))
! 	{
! 	  tree b;
! 	  tree fn;
! 	  tree overrider;
! 	  tree vindex;
! 	  tree delta;
! 	  HOST_WIDE_INT vindex_val;
! 	  HOST_WIDE_INT i;
! 
! 	  /* Find the function which originally caused this vtable
! 	     entry to be present.  */
! 	  fn = BV_FN (old_virtuals);
! 	  vindex = DECL_VINDEX (fn);
! 	  b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn));
! 	  fn = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (b)));
! 	  i = first_vfun_index (BINFO_TYPE (b));
! 	  vindex_val = tree_low_cst (vindex, 0);
! 	  while (i < vindex_val)
! 	    {
! 	      fn = TREE_CHAIN (fn);
! 	      ++i;
! 	    }
! 	  fn = BV_FN (fn);
! 
! 	  /* Handle the case of a virtual function defined in BINFO
! 	     itself.  */
! 	  overrider = find_final_overrider (t, b, fn);
! 	  if (overrider == error_mark_node)
! 	    continue;
! 
! 	  /* The `this' pointer needs to be adjusted from pointing to
! 	     BINFO to pointing at the base where the final overrider
! 	     appears.  */
! 	  delta = size_binop (PLUS_EXPR,
! 			      get_derived_offset (binfo,
! 						  DECL_VIRTUAL_CONTEXT (fn)),
! 			      BINFO_OFFSET (binfo));
! 	  delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), delta);
! 
! 	  modify_vtable_entry (t, 
! 			       binfo, 
! 			       TREE_PURPOSE (overrider),
! 			       delta,
! 			       &virtuals);
! 	}
      }
  
    SET_BINFO_MARKED (binfo);
--- 2574,2583 ----
  	   virtuals;
  	   virtuals = TREE_CHAIN (virtuals),
  	     old_virtuals = TREE_CHAIN (old_virtuals))
! 	update_vtable_entry_for_fn (t, 
! 				    binfo, 
! 				    BV_FN (old_virtuals),
! 				    &virtuals);
      }
  
    SET_BINFO_MARKED (binfo);
*************** modify_all_vtables (t, vfuns_p, overridd
*** 2591,2598 ****
  	{
  	  tree fn = TREE_VALUE (*fnsp);
  
! 	  if (BINFO_VIRTUALS (binfo)
! 	      && !value_member (fn, BINFO_VIRTUALS (binfo)))
  	    {
  	      /* Set the vtable index.  */
  	      set_vindex (t, fn, vfuns_p);
--- 2621,2628 ----
  	{
  	  tree fn = TREE_VALUE (*fnsp);
  
! 	  if (!BINFO_VIRTUALS (binfo)
! 	      || !value_member (fn, BINFO_VIRTUALS (binfo)))
  	    {
  	      /* Set the vtable index.  */
  	      set_vindex (t, fn, vfuns_p);
*************** build_clone (fn, name)
*** 3891,3897 ****
  	DECL_VINDEX (clone) = NULL_TREE;
      }
  
!   /* If there was an in-charge paramter, drop it from the function
       type.  */
    if (DECL_HAS_IN_CHARGE_PARM_P (clone))
      {
--- 3921,3927 ----
  	DECL_VINDEX (clone) = NULL_TREE;
      }
  
!   /* If there was an in-charge parameter, drop it from the function
       type.  */
    if (DECL_HAS_IN_CHARGE_PARM_P (clone))
      {
*************** clone_function_decl (fn, update_method_v
*** 3990,4000 ****
  
        /* For each destructor, we need two variants: an in-charge
  	 version, a not-in-charge version, and an in-charge deleting
! 	 version.  */
!       clone = build_clone (fn, complete_dtor_identifier);
        if (update_method_vec_p)
  	add_method (DECL_CONTEXT (clone), NULL, clone);
!       clone = build_clone (fn, deleting_dtor_identifier);
        if (update_method_vec_p)
  	add_method (DECL_CONTEXT (clone), NULL, clone);
        clone = build_clone (fn, base_dtor_identifier);
--- 4020,4033 ----
  
        /* For each destructor, we need two variants: an in-charge
  	 version, a not-in-charge version, and an in-charge deleting
! 	 version.  We clone the deleting version first because that
! 	 means it will go second on the TYPE_METHODS list -- and that
! 	 corresponds to the correct layout order in the virtual
! 	 function table.  */
!       clone = build_clone (fn, deleting_dtor_identifier);
        if (update_method_vec_p)
  	add_method (DECL_CONTEXT (clone), NULL, clone);
!       clone = build_clone (fn, complete_dtor_identifier);
        if (update_method_vec_p)
  	add_method (DECL_CONTEXT (clone), NULL, clone);
        clone = build_clone (fn, base_dtor_identifier);
*************** build_vbase_offset_vtbl_entries (binfo, 
*** 6637,6645 ****
  				vod->index, integer_one_node));
  
        /* The initializer is the delta from BINFO to this virtual base.
! 	   The vbase offsets go in reverse inheritance-graph order, and
! 	   we are walking in inheritance graph order so these end up in
! 	   the right order.  */
        delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (binfo));
        vod->inits = tree_cons (NULL_TREE, 
  			      fold (build1 (NOP_EXPR, 
--- 6670,6678 ----
  				vod->index, integer_one_node));
  
        /* The initializer is the delta from BINFO to this virtual base.
! 	 The vbase offsets go in reverse inheritance-graph order, and
! 	 we are walking in inheritance graph order so these end up in
! 	 the right order.  */
        delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (binfo));
        vod->inits = tree_cons (NULL_TREE, 
  			      fold (build1 (NOP_EXPR, 
*************** build_vbase_offset_vtbl_entries (binfo, 
*** 6648,6665 ****
  			      vod->inits);
      }
  }
- 
- /* 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.  */
  
--- 6681,6689 ----
  			      vod->inits);
      }
  }
  
! /* FIXME: We need to decide about overridden functions: where does the 
!           vcall offset go?  */
  
  /* Called from build_vcall_offset_vtbl_entries via dfs_walk.  */
  
*************** dfs_build_vcall_offset_vtbl_entries (bin
*** 6669,6709 ****
       void *data;
  {
    vcall_offset_data* vod;
!   tree virtuals;
    tree binfo_inits;
    tree b;
    int i;
  
    vod = (vcall_offset_data *) data;
    binfo_inits = NULL_TREE;
!   
    /* Skip virtuals that we have already handled in a primary base
       class.  */
!   virtuals = BINFO_VIRTUALS (binfo);
    b = BINFO_PRIMARY_BINFO (binfo);
    if (b)
      for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i)
!       virtuals = TREE_CHAIN (virtuals);
  
    /* Make entries for the rest of the virtuals.  */
!   while (virtuals)
      {
        /* Figure out what function we're looking at.  */
!       tree fn = TREE_VALUE (virtuals);
        tree base = DECL_CONTEXT (fn);
        /* The FN comes from BASE.  So, we must caculate the adjustment
  	 from the virtual base that derived from BINFO to BASE.  */
        tree base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
  
        binfo_inits
  	= tree_cons (NULL_TREE,
  		     fold (build1 (NOP_EXPR, vtable_entry_type,
  				   size_diffop (BINFO_OFFSET (base_binfo),
  						BINFO_OFFSET (vod->vbase)))),
  		     binfo_inits);
        vod->index = fold (build (MINUS_EXPR, integer_type_node,
  				vod->index, integer_one_node));
!       virtuals = TREE_CHAIN (virtuals);
      }
  
    /* The offests are built up in reverse order, so we straighten them
--- 6693,6756 ----
       void *data;
  {
    vcall_offset_data* vod;
!   tree derived_virtuals;
!   tree base_virtuals;
    tree binfo_inits;
+   tree non_primary_binfo;
    tree b;
    int i;
  
    vod = (vcall_offset_data *) data;
    binfo_inits = NULL_TREE;
! 
!   /* We might be a primary base class.  Go up the inheritance
!      hierarchy until we find the class of which we are a primary base:
!      it is the BINFO_VIRTUALS there that we need to consider.  */
!   non_primary_binfo = binfo;
!   while (BINFO_PRIMARY_MARKED_P (non_primary_binfo))
!     non_primary_binfo = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
! 
    /* Skip virtuals that we have already handled in a primary base
       class.  */
!   base_virtuals = BINFO_VIRTUALS (binfo);
!   derived_virtuals = BINFO_VIRTUALS (non_primary_binfo);
    b = BINFO_PRIMARY_BINFO (binfo);
    if (b)
      for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i)
!       {
! 	base_virtuals = TREE_CHAIN (base_virtuals);
! 	derived_virtuals = TREE_CHAIN (derived_virtuals);
!       }
  
    /* Make entries for the rest of the virtuals.  */
!   while (base_virtuals)
      {
        /* Figure out what function we're looking at.  */
!       tree fn = TREE_VALUE (derived_virtuals);
        tree base = DECL_CONTEXT (fn);
        /* The FN comes from BASE.  So, we must caculate the adjustment
  	 from the virtual base that derived from BINFO to BASE.  */
        tree base_binfo = get_binfo (base, vod->derived, /*protect=*/0);
  
+       /* Compute the vcall offset.  */
        binfo_inits
  	= tree_cons (NULL_TREE,
  		     fold (build1 (NOP_EXPR, vtable_entry_type,
  				   size_diffop (BINFO_OFFSET (base_binfo),
  						BINFO_OFFSET (vod->vbase)))),
  		     binfo_inits);
+ 
+       /* Keep track of the vtable index where this vcall offset can be
+ 	 found.  */
+       BV_VCALL_INDEX (derived_virtuals) = vod->index;
+       /* The next vcall offset will be found at a more negative
+ 	 offset.  */
        vod->index = fold (build (MINUS_EXPR, integer_type_node,
  				vod->index, integer_one_node));
! 
!       /* Go to the next entries in the list.  */
!       derived_virtuals = TREE_CHAIN (derived_virtuals);
!       base_virtuals = TREE_CHAIN (base_virtuals);
      }
  
    /* The offests are built up in reverse order, so we straighten them
*************** build_vcall_offset_vtbl_entries (binfo, 
*** 6772,6778 ****
    dfs_walk_real (binfo,
  		 dfs_build_vcall_offset_vtbl_entries,
  		 NULL,
! 		 dfs_vcall_offset_queue_p,
  		 vod);
    vod->inits = chainon (vod->inits, inits);
  }
--- 6819,6825 ----
    dfs_walk_real (binfo,
  		 dfs_build_vcall_offset_vtbl_entries,
  		 NULL,
! 		 dfs_skip_vbases,
  		 vod);
    vod->inits = chainon (vod->inits, inits);
  }
*************** build_vtable_entry (delta, vcall_index, 
*** 6880,6886 ****
        idelta = tree_low_cst (delta, 0);
        ivindex = tree_low_cst (vcall_index, 0);
        if ((idelta || ivindex) 
! 	  && ! DECL_PURE_VIRTUAL_P (TREE_OPERAND (entry, 0)))
  	{
  	  entry = make_thunk (entry, idelta, ivindex);
  	  entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
--- 6927,6933 ----
        idelta = tree_low_cst (delta, 0);
        ivindex = tree_low_cst (vcall_index, 0);
        if ((idelta || ivindex) 
! 	  && TREE_OPERAND (entry, 0) != abort_fndecl)
  	{
  	  entry = make_thunk (entry, idelta, ivindex);
  	  entry = build1 (ADDR_EXPR, vtable_entry_type, entry);
*************** build_vtable_entry (delta, vcall_index, 
*** 6894,6900 ****
      }
    else
      {
-       extern int flag_huge_objects;
        tree elems = tree_cons (NULL_TREE, delta,
  			      tree_cons (NULL_TREE, integer_zero_node,
  					 build_tree_list (NULL_TREE, entry)));
--- 6941,6946 ----
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.590
diff -c -p -r1.590 decl.c
*** decl.c	2000/04/12 07:48:12	1.590
--- decl.c	2000/04/16 18:53:35
*************** extern int flag_no_builtin;
*** 336,345 ****
  
  extern int flag_no_nonansi_builtin;
  
- /* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes)
-    objects.  */
- extern int flag_huge_objects;
- 
  /* Nonzero if we want to conserve space in the .o files.  We do this
     by putting uninitialized data and runtime initialized data into
     .common instead of .data at the expense of not flagging multiple
--- 336,341 ----
Index: cp/method.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/method.c,v
retrieving revision 1.148
diff -c -p -r1.148 method.c
*** method.c	2000/04/11 20:16:35	1.148
--- method.c	2000/04/16 18:53:37
*************** make_thunk (function, delta, vcall_index
*** 2036,2047 ****
    else
      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));
  
--- 2036,2047 ----
    else
      icat (-delta);
    OB_PUTC ('_');
    if (vcall_index)
      {
        icat (vcall_index);
+       OB_PUTC ('_');
      }
+   OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
    OB_FINISH ();
    thunk_id = get_identifier (obstack_base (&scratch_obstack));
  
*************** make_thunk (function, delta, vcall_index
*** 2062,2068 ****
        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: */
--- 2062,2068 ----
        DECL_INITIAL (thunk) = function;
        THUNK_DELTA (thunk) = delta;
        THUNK_VCALL_OFFSET (thunk) 
! 	= vcall_index * int_size_in_bytes (vtable_entry_type);
        DECL_EXTERNAL (thunk) = 1;
        DECL_ARTIFICIAL (thunk) = 1;
        /* So that finish_file can write out any thunks that need to be: */
*************** void
*** 2077,2084 ****
  emit_thunk (thunk_fndecl)
       tree thunk_fndecl;
  {
!   tree function = TREE_OPERAND (DECL_INITIAL (thunk_fndecl), 0);
    int delta = THUNK_DELTA (thunk_fndecl);
  
    if (TREE_ASM_WRITTEN (thunk_fndecl))
      return;
--- 2077,2086 ----
  emit_thunk (thunk_fndecl)
       tree thunk_fndecl;
  {
!   tree fnaddr = DECL_INITIAL (thunk_fndecl);
!   tree function = TREE_OPERAND (fnaddr, 0);
    int delta = THUNK_DELTA (thunk_fndecl);
+   int vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
  
    if (TREE_ASM_WRITTEN (thunk_fndecl))
      return;
*************** emit_thunk (thunk_fndecl)
*** 2094,2100 ****
    TREE_SET_CODE (thunk_fndecl, FUNCTION_DECL);
  
  #ifdef ASM_OUTPUT_MI_THUNK
!   if (!flag_syntax_only)
      {
        const char *fnname;
        current_function_decl = thunk_fndecl;
--- 2096,2102 ----
    TREE_SET_CODE (thunk_fndecl, FUNCTION_DECL);
  
  #ifdef ASM_OUTPUT_MI_THUNK
!   if (!flag_syntax_only && vcall_offset == 0)
      {
        const char *fnname;
        current_function_decl = thunk_fndecl;
*************** emit_thunk (thunk_fndecl)
*** 2112,2118 ****
        current_function_decl = 0;
        cfun = 0;
      }
! #else /* ASM_OUTPUT_MI_THUNK */
    {
    /* If we don't have the necessary macro for efficient thunks, generate a
       thunk function that just makes a call to the real function.
--- 2114,2121 ----
        current_function_decl = 0;
        cfun = 0;
      }
! #endif /* ASM_OUTPUT_MI_THUNK */
!   else
    {
    /* If we don't have the necessary macro for efficient thunks, generate a
       thunk function that just makes a call to the real function.
*************** emit_thunk (thunk_fndecl)
*** 2140,2155 ****
      copy_lang_decl (thunk_fndecl);
      DECL_INTERFACE_KNOWN (thunk_fndecl) = 1;
      DECL_NOT_REALLY_EXTERN (thunk_fndecl) = 1;
  
!     start_function (NULL_TREE, thunk_fndecl, NULL_TREE, 
! 		    SF_DEFAULT | SF_PRE_PARSED);
      store_parm_decls ();
      current_function_is_thunk = 1;
  
!     /* Build up the call to the real function.  */
!     t = build_int_2 (delta, -1 * (delta < 0));
      TREE_TYPE (t) = signed_type (sizetype);
      t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
      t = tree_cons (NULL_TREE, t, NULL_TREE);
      for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
        t = tree_cons (NULL_TREE, a, t);
--- 2143,2186 ----
      copy_lang_decl (thunk_fndecl);
      DECL_INTERFACE_KNOWN (thunk_fndecl) = 1;
      DECL_NOT_REALLY_EXTERN (thunk_fndecl) = 1;
+     DECL_SAVED_FUNCTION_DATA (thunk_fndecl) = NULL;
  
!     push_to_top_level ();
!     start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
      store_parm_decls ();
      current_function_is_thunk = 1;
  
!     /* Adjust the this pointer by the constant.  */
!     t = ssize_int (delta);
      TREE_TYPE (t) = signed_type (sizetype);
      t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
+     /* If there's a vcall offset, look up that value in the vtable and
+        adjust the `this' pointer again.  */
+     if (vcall_offset != 0)
+       {
+ 	tree orig_this;
+ 
+ 	t = save_expr (t);
+ 	orig_this = t;
+ 	/* The vptr is always at offset zero in the object.  */
+ 	t = build1 (NOP_EXPR,
+ 		    build_pointer_type (build_pointer_type 
+ 					(vtable_entry_type)),
+ 		    t);
+ 	/* Form the vtable address.  */
+ 	t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
+ 	/* Find the entry with the vcall offset.  */
+ 	t = build (PLUS_EXPR, TREE_TYPE (t), t, ssize_int (vcall_offset));
+ 	/* Calculate the offset itself.  */
+ 	t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
+ 	/* Adjust the `this' pointer.  */
+ 	t = fold (build (PLUS_EXPR,
+ 			 TREE_TYPE (orig_this),
+ 			 orig_this,
+ 			 t));
+       }
+ 
+     /* Build up the call to the real function.  */
      t = tree_cons (NULL_TREE, t, NULL_TREE);
      for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
        t = tree_cons (NULL_TREE, a, t);
*************** emit_thunk (thunk_fndecl)
*** 2157,2169 ****
      t = build_call (function, t);
      finish_return_stmt (t);
  
      expand_body (finish_function (0));
  
      /* Don't let the backend defer this function.  */
      if (DECL_DEFER_OUTPUT (thunk_fndecl))
        output_inline_function (thunk_fndecl);
    }
- #endif /* ASM_OUTPUT_MI_THUNK */
  
    TREE_SET_CODE (thunk_fndecl, THUNK_DECL);
  }
--- 2188,2208 ----
      t = build_call (function, t);
      finish_return_stmt (t);
  
+     /* The back-end expects DECL_INITIAL to contain a BLOCK, so we
+        clear this here.  */
+     DECL_INITIAL (thunk_fndecl) = NULL_TREE;
+     DECL_INITIAL (thunk_fndecl) = make_node (BLOCK);
+     BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) 
+       = DECL_ARGUMENTS (thunk_fndecl);
      expand_body (finish_function (0));
+     /* Restore the DECL_INITIAL for the THUNK_DECL.  */
+     DECL_INITIAL (thunk_fndecl) = fnaddr;
+     pop_from_top_level ();
  
      /* Don't let the backend defer this function.  */
      if (DECL_DEFER_OUTPUT (thunk_fndecl))
        output_inline_function (thunk_fndecl);
    }
  
    TREE_SET_CODE (thunk_fndecl, THUNK_DECL);
  }


More information about the Gcc-patches mailing list