FreeBSD/contrib/gcc/cp/class.c
/* Construct the initializer for BINFO's virtual function table.  BINFO
   is part of the hierarchy dominated by T.  If we're building a
   construction vtable, the ORIG_BINFO is the binfo we should use to
   find the actual function pointers to put in the vtable - but they
   can be overridden on the path to most-derived in the graph that
   ORIG_BINFO belongs.  Otherwise,
   ORIG_BINFO should be the same as BINFO.  The RTTI_BINFO is the
   BINFO that should be indicated by the RTTI information in the
   vtable; it will be a base class of T, rather than T itself, if we
   are building a construction vtable.

   The value returned is a TREE_LIST suitable for wrapping in a
   CONSTRUCTOR to use as the DECL_INITIAL for a vtable.  If
   NON_FN_ENTRIES_P is not NULL, *NON_FN_ENTRIES_P is set to the
   number of non-function entries in the vtable.

   It might seem that this function should never be called with a
   BINFO for which BINFO_PRIMARY_P holds, the vtable for such a
   base is always subsumed by a derived class vtable.  However, when
   we are building construction vtables, we do build vtables for
   primary bases; we need these while the primary base is being
   constructed.  */
Construct the initializer for BINFO's virtual function table.  BINFO
is part of the hierarchy dominated by T.  If we're building a
construction vtable, the ORIG_BINFO is the binfo we should use to
find the actual function pointers to put in the vtable - but they
can be overridden on the path to most-derived in the graph that
ORIG_BINFO belongs.  Otherwise,
ORIG_BINFO should be the same as BINFO.  The RTTI_BINFO is the
BINFO that should be indicated by the RTTI information in the
vtable; it will be a base class of T, rather than T itself, if we
are building a construction vtable.

The value returned is a TREE_LIST suitable for wrapping in a
CONSTRUCTOR to use as the DECL_INITIAL for a vtable.  If
NON_FN_ENTRIES_P is not NULL, *NON_FN_ENTRIES_P is set to the
number of non-function entries in the vtable.

It might seem that this function should never be called with a
BINFO for which BINFO_PRIMARY_P holds, the vtable for such a
base is always subsumed by a derived class vtable.  However, when
we are building construction vtables, we do build vtables for
primary bases; we need these while the primary base is being
constructed.
Construct the initializer for BINFO ' s virtual function table . BINFO is part of the hierarchy dominated by T . If we ' re building a construction vtable the ORIG_BINFO is the binfo we should use to find the actual function pointers to put in the vtable - but they can be overridden on the path to most - derived in the graph that ORIG_BINFO belongs . Otherwise ORIG_BINFO should be the same as BINFO . The RTTI_BINFO is the BINFO that should be indicated by the RTTI information in the vtable ; it will be a base class of T rather than T itself if we are building a construction vtable . The value returned is a TREE_LIST suitable for wrapping in a CONSTRUCTOR to use as the DECL_INITIAL for a vtable . If NON_FN_ENTRIES_P is not NULL * NON_FN_ENTRIES_P is set to the number of non - function entries in the vtable . It might seem that this function should never be called with a BINFO for which BINFO_PRIMARY_P holds the vtable for such a base is always subsumed by a derived class vtable . However when we are building construction vtables we do build vtables for primary bases ; we need these while the primary base is being constructed .
static tree
build_vtbl_initializer (tree binfo,
			tree orig_binfo,
			tree t,
			tree rtti_binfo,
			int* non_fn_entries_p)
{
  tree v, b;
  tree vfun_inits;
  vtbl_init_data vid;
  unsigned ix;
  tree vbinfo;
  VEC(tree,gc) *vbases;
  memset (&vid, 0, sizeof (vid));
  vid.binfo = binfo;
  vid.derived = t;
  vid.rtti_binfo = rtti_binfo;
  vid.last_init = &vid.inits;
  vid.primary_vtbl_p = SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), t);
  vid.ctor_vtbl_p = !SAME_BINFO_TYPE_P (BINFO_TYPE (rtti_binfo), t);
  vid.generate_vcall_entries = true;
  vid.index = ssize_int(-3 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
  build_rtti_vtbl_entries (binfo, &vid);
  vid.fns = VEC_alloc (tree, gc, 32);
  build_vcall_and_vbase_vtbl_entries (binfo, &vid);
  for (vbases = CLASSTYPE_VBASECLASSES (t), ix = 0;
       VEC_iterate (tree, vbases, ix, vbinfo); ix++)
    BINFO_VTABLE_PATH_MARKED (vbinfo) = 0;
  if (TARGET_VTABLE_DATA_ENTRY_DISTANCE > 1)
    {
      tree cur, *prev;
      for (prev = &vid.inits; (cur = *prev); prev = &TREE_CHAIN (cur))
	{
	  tree add = cur;
	  int i;
	  for (i = 1; i < TARGET_VTABLE_DATA_ENTRY_DISTANCE; ++i)
	    add = tree_cons (NULL_TREE,
			     build1 (NOP_EXPR, vtable_entry_type,
				     null_pointer_node),
			     add);
	  *prev = add;
	}
    }
  if (non_fn_entries_p)
    *non_fn_entries_p = list_length (vid.inits);
  vfun_inits = NULL_TREE;
  for (v = BINFO_VIRTUALS (orig_binfo); v; v = TREE_CHAIN (v))
    {
      tree delta;
      tree vcall_index;
      tree fn, fn_original;
      tree init = NULL_TREE;
      fn = BV_FN (v);
      fn_original = fn;
      if (DECL_THUNK_P (fn))
	{
	  if (!DECL_NAME (fn))
	    finish_thunk (fn);
	  if (THUNK_ALIAS (fn))
	    {
	      fn = THUNK_ALIAS (fn);
	      BV_FN (v) = fn;
	    }
	  fn_original = THUNK_TARGET (fn);
	}
      for (b = binfo; ; b = get_primary_binfo (b))
	{
	  if (look_for_overrides_here (BINFO_TYPE (b), fn_original))
	    break;
	  if (BINFO_LOST_PRIMARY_P (b))
	    {
	      init = size_zero_node;
	      break;
	    }
	}
      if (! init)
	{
	  delta = BV_DELTA (v);
	  vcall_index = BV_VCALL_INDEX (v);
	  gcc_assert (TREE_CODE (delta) == INTEGER_CST);
	  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
	  if (DECL_PURE_VIRTUAL_P (fn_original))
	    {
	      fn = abort_fndecl;
	      if (abort_fndecl_addr == NULL)
		abort_fndecl_addr = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
	      init = abort_fndecl_addr;
	    }
	  else
	    {
	      if (!integer_zerop (delta) || vcall_index)
		{
		  fn = make_thunk (fn, 1, delta, vcall_index);
		  if (!DECL_NAME (fn))
		    finish_thunk (fn);
		}
	      init = build1 (ADDR_EXPR, vfunc_ptr_type_node, fn);
	    }
	}
      if (TARGET_VTABLE_USES_DESCRIPTORS)
	{
	  int i;
	  if (init == size_zero_node)
	    for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
	      vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
	  else
	    for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
	      {
		tree fdesc = build2 (FDESC_EXPR, vfunc_ptr_type_node,
				     TREE_OPERAND (init, 0),
				     build_int_cst (NULL_TREE, i));
		TREE_CONSTANT (fdesc) = 1;
		TREE_INVARIANT (fdesc) = 1;
		vfun_inits = tree_cons (NULL_TREE, fdesc, vfun_inits);
	      }
	}
      else
	vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
    }
  vfun_inits = nreverse (vfun_inits);
  vid.inits = nreverse (vid.inits);
  return chainon (vid.inits, vfun_inits);
}
static tree build_vtbl_initializer ( tree binfo , tree orig_binfo , tree t , tree rtti_binfo , int * non_fn_entries_p ) { tree v , b ; tree vfun_inits ; vtbl_init_data vid ; unsigned ix ; tree vbinfo ; VEC ( tree , gc ) * vbases ; memset ( & vid , 0 , sizeof ( vid ) ) ; vid . binfo = binfo ; vid . derived = t ; vid . rtti_binfo = rtti_binfo ; vid . last_init = & vid . inits ; vid . primary_vtbl_p = SAME_BINFO_TYPE_P ( BINFO_TYPE ( binfo ) , t ) ; vid . ctor_vtbl_p = ! SAME_BINFO_TYPE_P ( BINFO_TYPE ( rtti_binfo ) , t ) ; vid . generate_vcall_entries = true ; vid . index = ssize_int ( -3 * TARGET_VTABLE_DATA_ENTRY_DISTANCE ) ; build_rtti_vtbl_entries ( binfo , & vid ) ; vid . fns = VEC_alloc ( tree , gc , 32 ) ; build_vcall_and_vbase_vtbl_entries ( binfo , & vid ) ; for ( vbases = CLASSTYPE_VBASECLASSES ( t ) , ix = 0 ; VEC_iterate ( tree , vbases , ix , vbinfo ) ; ix ++ ) BINFO_VTABLE_PATH_MARKED ( vbinfo ) = 0 ; if ( TARGET_VTABLE_DATA_ENTRY_DISTANCE > 1 ) { tree cur , * prev ; for ( prev = & vid . inits ; ( cur = * prev ) ; prev = & TREE_CHAIN ( cur ) ) { tree add = cur ; int i ; for ( i = 1 ; i < TARGET_VTABLE_DATA_ENTRY_DISTANCE ; ++ i ) add = tree_cons ( NULL_TREE , build1 ( NOP_EXPR , vtable_entry_type , null_pointer_node ) , add ) ; * prev = add ; } } if ( non_fn_entries_p ) * non_fn_entries_p = list_length ( vid . inits ) ; vfun_inits = NULL_TREE ; for ( v = BINFO_VIRTUALS ( orig_binfo ) ; v ; v = TREE_CHAIN ( v ) ) { tree delta ; tree vcall_index ; tree fn , fn_original ; tree init = NULL_TREE ; fn = BV_FN ( v ) ; fn_original = fn ; if ( DECL_THUNK_P ( fn ) ) { if ( ! DECL_NAME ( fn ) ) finish_thunk ( fn ) ; if ( THUNK_ALIAS ( fn ) ) { fn = THUNK_ALIAS ( fn ) ; BV_FN ( v ) = fn ; } fn_original = THUNK_TARGET ( fn ) ; } for ( b = binfo ; ; b = get_primary_binfo ( b ) ) { if ( look_for_overrides_here ( BINFO_TYPE ( b ) , fn_original ) ) break ; if ( BINFO_LOST_PRIMARY_P ( b ) ) { init = size_zero_node ; break ; } } if ( ! init ) { delta = BV_DELTA ( v ) ; vcall_index = BV_VCALL_INDEX ( v ) ; gcc_assert ( TREE_CODE ( delta ) == INTEGER_CST ) ; gcc_assert ( TREE_CODE ( fn ) == FUNCTION_DECL ) ; if ( DECL_PURE_VIRTUAL_P ( fn_original ) ) { fn = abort_fndecl ; if ( abort_fndecl_addr == NULL ) abort_fndecl_addr = build1 ( ADDR_EXPR , vfunc_ptr_type_node , fn ) ; init = abort_fndecl_addr ; } else { if ( ! integer_zerop ( delta ) || vcall_index ) { fn = make_thunk ( fn , 1 , delta , vcall_index ) ; if ( ! DECL_NAME ( fn ) ) finish_thunk ( fn ) ; } init = build1 ( ADDR_EXPR , vfunc_ptr_type_node , fn ) ; } } if ( TARGET_VTABLE_USES_DESCRIPTORS ) { int i ; if ( init == size_zero_node ) for ( i = 0 ; i < TARGET_VTABLE_USES_DESCRIPTORS ; ++ i ) vfun_inits = tree_cons ( NULL_TREE , init , vfun_inits ) ; else for ( i = 0 ; i < TARGET_VTABLE_USES_DESCRIPTORS ; ++ i ) { tree fdesc = build2 ( FDESC_EXPR , vfunc_ptr_type_node , TREE_OPERAND ( init , 0 ) , build_int_cst ( NULL_TREE , i ) ) ; TREE_CONSTANT ( fdesc ) = 1 ; TREE_INVARIANT ( fdesc ) = 1 ; vfun_inits = tree_cons ( NULL_TREE , fdesc , vfun_inits ) ; } } else vfun_inits = tree_cons ( NULL_TREE , init , vfun_inits ) ; } vfun_inits = nreverse ( vfun_inits ) ; vid . inits = nreverse ( vid . inits ) ; return chainon ( vid . inits , vfun_inits ) ; }
Construct the initializer for BINFO's virtual function table.
Construct the initializer for BINFO ' s virtual function table .
/* Initialize VID.  */ /* The first vbase or vcall offset is at index -3 in the vtable.  */ /* Add entries to the vtable for RTTI.  */ /* Create an array for keeping track of the functions we've
     processed.  When we see multiple functions with the same
     signature, we share the vcall offsets.  */ /* Add the vcall and vbase offset entries.  */ /* Clear BINFO_VTABLE_PATH_MARKED; it's set by
     build_vbase_offset_vtbl_entries.  */ /* If the target requires padding between data entries, add that now.  */ /* Go through all the ordinary virtual functions, building up
     initializers.  */ /* If the only definition of this function signature along our
	 primary base chain is from a lost primary, this vtable slot will
	 never be used, so just zero it out.  This is important to avoid
	 requiring extra thunks which cannot be generated with the function.

	 We first check this in update_vtable_entry_for_fn, so we handle
	 restored primary bases properly; we also need to do it here so we
	 zero out unused slots in ctor vtables, rather than filling themff
	 with erroneous values (though harmless, apart from relocation
	 costs).  */ /* We found a defn before a lost primary; go ahead as normal.  */ /* The nearest definition is from a lost primary; clear the
	     slot.  */ /* Pull the offset for `this', and the function to call, out of
	     the list.  */ /* You can't call an abstract virtual function; it's abstract.
	     So, we replace these functions with __pure_virtual.  */ /*this_adjusting=*/ /* Take the address of the function, considering it to be of an
		 appropriate generic type.  */ /* And add it to the chain of initializers.  */ /* The initializers for virtual functions were built up in reverse
     order; straighten them out now.  */ /* The negative offset initializers are also in reverse order.  */ /* Chain the two together.  */