diff mbox

vtables patch 3/3

Message ID 5177BE4E.2020002@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt April 24, 2013, 11:13 a.m. UTC
This is the final piece which contains the modifications to the C++
frontend.

Bootstrapped and tested on x86_64-linux, including compat tests against
the installed compiler. I've also built an ia64-hpux (the only target
defining TARGET_VTABLE_DATA_ENTRY_DISTANCE) cc1plus and verified that at
least it doesn't crash on some vtable testcases, but realistically I
have no way of properly testing that target. Ok?


Bernd
diff mbox

Patch

commit d6957d8e1ad8179c01d373f741099b021a05730f
Author: Bernd Schmidt <bernds@codesourcery.com>
Date:   Mon Apr 15 11:24:04 2013 +0200

    Change handling of vtables to use fields and COMPONENT_REFs
    
    The C++ frontend accesses the various parts of the vtable using positive
    and negative indices from the vtable pointer.  This assumes that all fields
    in the vtable have the same size.  Change this to build structure decls
    instead and access data with COMPONENT_REFs of the fields.
    
    	gcc/cp/
    	* class.c (struct vtbl_init_data_s): Add new member FIELD.  Change
    	INDEX to an int.
    	(build_vtbl_initializer, layout_vtable_decl, accumulate_vtbl_inits,
    	dfs_accumulate_vtbl_inits): Adjust declarations.
    	(dump_array, initialize_vtable): Remove unnecessary declarations.
    	(vfunc_array_vtbl_offset): New static function.
    	(build_vtbl_ref_1): Remove idx argument, add new argument outer.
    	Return only a pointer to the vtbl or a pointer to its array member,
    	depending on outer.  All callers changed.
    	(build_vtbl_rtti_offset_ref, build_vtbl_rtti_object_ref): New
    	functions.
    	(build_vtbl_ref): Build the array reference here.
    	(build_vfn_ref): Use build_vtbl_ref, not build_vtbl_ref_1.
    	(layout_vtable_decl): Remove argument n, add new argument fields.  All
    	callers changed.  Make a record type instead of an array.
    	(vbase_offset_from_index): New function.
    	(get_vtbl_decl_for_binfo): Adjust to expect an ADDR_EXPR of a
    	COMPONENT_REF.
    	(dump_array): New arguments inits and off.  All callers changed.  Use
    	the inits instead of DECL_INITIAL.  Print offsets starting from off.
    	Print different header depending on the type of the decl.
    	(dump_record): New static function.
    	(dump_vtable): Use it instead of dump_array.
    	(initialize_vtable): Move before users.  Add new arg fields.  All
    	callers changed.
    	(finish_vtbls): Create an empty fields vector and pass it to
    	accumulate_vtbl_inits.
    	(build_ctor_vtbl_group): Likewise.  Use layout_vtable_decl.
    	(accumulate_vtbl_inits): Add new arg fields.  All callers changed.
    	(dfs_accumulate_vtbl_inits): Likewise. Build an ADDR_EXPR of a
    	COMPONENT_REF to get the right vtbl pointer.  Truncate fields along
    	with inits if necessary.
    	(build_vtbl_initializer): Add new arg fields.  All callers changed.
    	Use integer arithmetic for the vid.index field.  Add extra fields for
    	alignment padding if necessary.  Create and append a FIELD_DECL for
    	the array.
    	(build_vbase_offset_vtbl_entries): Use integer arithmetic for
    	vid->index.  Use vbase_offset_from_index.  Create a FIELD_DECL
    	corresponding to the initializer.  Remove cast to vtable_entry_type.
    	(add_vcall_offset): Use integer arithmetic for vid->index.  Remove
    	cast to vtable_entry_type.  Create a FIELD_DECL corresponding to the
    	initializer.
    	(build_rtti_vtbl_entries): Use null_pointer_node instead of
    	integer_zero_node.  Don't cast to vfunc_ptr_type_node.  Create a
    	FIELD_DECL corresponding to the initializer.
    	* decl.c (initialize_predefined_identifiers): Add voffset, vti and
    	array identifiers.
    	(create_vtable_type): New static function.
    	(cxx_init_decl_processing): Use it to create vtbl_type_node.  Set
    	vtbl_array_type_node to the array type.
    	* decl2.c (mark_vtable_elt): New static function.
    	(mark_vtable_entries): Use it.  Look inside CONSTRUCTORs for elements
    	that need marking.
    	* rtti.c (build_headof): Use build_vtbl_rtti_offset_ref and
    	build_vtbl_rtti_object_ref.
    	(tinfo_base_init): Use the address of a COMPONENT_REF to find the
    	right offset.
    	* method.c (make_thunk): Use vbase_offset_from_index.
    	* cp-tree.h (enum cp_tree_index): Add CPTI_VTBL_ARRAY_TYPE,
    	CPTI_VOFFSET_IDENTIFIER, CPTI_VTI_IDENTIFIER, CPTI_ARRAY_IDENTIFIER.
    	(vtbl_array_type_node, voffset_identifier, vti_identifier,
    	array_identifier): Define.
    	(vbase_offset_from_index, build_vtbl_rtti_offset_ref,
    	build_vtbl_rti_object_ref): Declare.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 58248bf..fbc712b 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -77,6 +77,8 @@  typedef struct vtbl_init_data_s
   /* The negative-index vtable initializers built up so far.  These
      are in order from least negative index to most negative index.  */
   vec<constructor_elt, va_gc> *inits;
+  /* FIELD_DECLs corresponding to the previous set of initializers.  */
+  vec<tree, va_gc> *fields;
   /* The binfo for the virtual base for which we're building
      vcall offset initializers.  */
   tree vbase;
@@ -84,7 +86,7 @@  typedef struct vtbl_init_data_s
      offsets.  */
   vec<tree, va_gc> *fns;
   /* The vtable index of the next vcall or vbase offset.  */
-  tree index;
+  int index;
   /* Nonzero if we are building the initializer for the primary
      vtable.  */
   int primary_vtbl_p;
@@ -132,9 +134,9 @@  static int resort_method_name_cmp (const void *, const void *);
 static void add_implicitly_declared_members (tree, tree*, int, int);
 static tree fixed_type_or_null (tree, int *, int *);
 static tree build_simple_base_path (tree expr, tree binfo);
-static tree build_vtbl_ref_1 (tree, tree);
 static void build_vtbl_initializer (tree, tree, tree, tree, int *,
-				    vec<constructor_elt, va_gc> **);
+				    vec<constructor_elt, va_gc> **,
+				    vec<tree, va_gc> **);
 static int count_fields (tree);
 static int add_fields_to_record_type (tree, struct sorted_fields_type*, int);
 static void insert_into_classtype_sorted_fields (tree, tree, int);
@@ -157,7 +159,7 @@  static void add_vcall_offset_vtbl_entries_r (tree, vtbl_init_data *);
 static void add_vcall_offset_vtbl_entries_1 (tree, vtbl_init_data *);
 static void build_vcall_offset_vtbl_entries (tree, vtbl_init_data *);
 static void add_vcall_offset (tree, tree, vtbl_init_data *);
-static void layout_vtable_decl (tree, int);
+static void layout_vtable_decl (tree, vec<tree, va_gc> *fields_vec);
 static tree dfs_find_final_overrider_pre (tree, void *);
 static tree dfs_find_final_overrider_post (tree, void *);
 static tree find_final_overrider (tree, tree, tree);
@@ -167,20 +169,20 @@  static int maybe_indent_hierarchy (FILE *, int, int);
 static tree dump_class_hierarchy_r (FILE *, int, tree, tree, int);
 static void dump_class_hierarchy (tree);
 static void dump_class_hierarchy_1 (FILE *, int, tree);
-static void dump_array (FILE *, tree);
 static void dump_vtable (tree, tree, tree);
 static void dump_vtt (tree, tree);
 static void dump_thunk (FILE *, int, tree);
 static tree build_vtable (tree, tree, tree);
-static void initialize_vtable (tree, vec<constructor_elt, va_gc> *);
 static void layout_nonempty_base_or_field (record_layout_info,
 					   tree, tree, splay_tree);
 static tree end_of_class (tree, int);
 static bool layout_empty_base (record_layout_info, tree, tree, splay_tree);
 static void accumulate_vtbl_inits (tree, tree, tree, tree, tree,
-				   vec<constructor_elt, va_gc> **);
+				   vec<constructor_elt, va_gc> **,
+				   vec<tree, va_gc> **);
 static void dfs_accumulate_vtbl_inits (tree, tree, tree, tree, tree,
-				       vec<constructor_elt, va_gc> **);
+				       vec<constructor_elt, va_gc> **,
+				       vec<tree, va_gc> **);
 static void build_rtti_vtbl_entries (tree, vtbl_init_data *);
 static void build_vcall_and_vbase_vtbl_entries (tree, vtbl_init_data *);
 static void clone_constructors_and_destructors (tree);
@@ -624,15 +626,24 @@  build_vfield_ref (tree datum, tree type)
   return build3 (COMPONENT_REF, TREE_TYPE (vfield), datum, vfield, NULL_TREE);
 }
 
-/* Given an object INSTANCE, return an expression which yields the
-   vtable element corresponding to INDEX.  There are many special
-   cases for INSTANCE which we take care of here, mainly to avoid
-   creating extra tree nodes when we don't have to.  */
+static tree
+vfunc_array_vtbl_offset (void)
+{
+  tree field = TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (vtbl_type_node)));
+  return size_binop (PLUS_EXPR, DECL_FIELD_OFFSET (field),
+		     fold_convert (size_type_node,
+				   size_binop (EXACT_DIV_EXPR,
+					       DECL_FIELD_BIT_OFFSET (field),
+					       bitsize_int (BITS_PER_UNIT))));
+}
+
+/* Given an object INSTANCE, return the vtable for it for use in building a
+   vtable reference.  If OUTER, return a pointer to the vtable object rather
+   than just the virtual function array.  */
 
 static tree
-build_vtbl_ref_1 (tree instance, tree idx)
+build_vtbl_ref_1 (tree instance, bool outer)
 {
-  tree aref;
   tree vtbl = NULL_TREE;
 
   /* Try to figure out what a reference refers to, and
@@ -653,17 +664,57 @@  build_vtbl_ref_1 (tree instance, tree idx)
 
   if (!vtbl)
     vtbl = build_vfield_ref (instance, basetype);
+  if (outer)
+    {
+      tree off = vfunc_array_vtbl_offset ();
+      off = fold_build1 (NEGATE_EXPR, sizetype, off);
+      vtbl = fold_convert (build_pointer_type (vtbl_type_node),
+			   fold_build2 (POINTER_PLUS_EXPR, const_ptr_type_node,
+					vtbl, off));
+    }
+  return vtbl;
+}
 
-  aref = build_array_ref (input_location, vtbl, idx);
-  TREE_CONSTANT (aref) |= TREE_CONSTANT (vtbl) && TREE_CONSTANT (idx);
+/* Given an object INSTANCE, return the RTTI offset field that is contained
+   within the vtable.  */
+
+tree
+build_vtbl_rtti_offset_ref (tree instance)
+{
+  tree vtbl = build_vtbl_ref_1 (instance, true);
+  tree vtbl1 = build1 (INDIRECT_REF, vtbl_type_node, vtbl);
+  tree field = TYPE_FIELDS (vtbl_type_node);
+  tree aref = build3 (COMPONENT_REF, TREE_TYPE (field), vtbl1, field, NULL_TREE);
+  TREE_CONSTANT (aref) |= TREE_CONSTANT (vtbl);
 
   return aref;
 }
 
+/* Given an object INSTANCE, return the RTTI object field that is contained
+   within the vtable.  */
+
+tree
+build_vtbl_rtti_object_ref (tree instance)
+{
+  tree vtbl = build_vtbl_ref_1 (instance, true);
+  tree vtbl1 = build1 (INDIRECT_REF, vtbl_type_node, vtbl);
+  tree field = TREE_CHAIN (TYPE_FIELDS (vtbl_type_node));
+  tree aref;
+  aref = build3 (COMPONENT_REF, TREE_TYPE (field), vtbl1, field, NULL_TREE);
+  TREE_CONSTANT (aref) |= TREE_CONSTANT (vtbl);
+
+  return aref;
+}
+
+/* Given an object INSTANCE, return the virtual function at index IDX in the
+   vtable.  */
+
 tree
 build_vtbl_ref (tree instance, tree idx)
 {
-  tree aref = build_vtbl_ref_1 (instance, idx);
+  tree vtbl = build_vtbl_ref_1 (instance, false);
+  tree aref = build_array_ref (input_location, vtbl, idx);
+  TREE_CONSTANT (aref) |= TREE_CONSTANT (vtbl) && TREE_CONSTANT (idx);
 
   return aref;
 }
@@ -676,9 +727,9 @@  build_vfn_ref (tree instance_ptr, tree idx)
 {
   tree aref;
 
-  aref = build_vtbl_ref_1 (cp_build_indirect_ref (instance_ptr, RO_NULL,
-                                                  tf_warning_or_error), 
-                           idx);
+  aref = build_vtbl_ref (cp_build_indirect_ref (instance_ptr, RO_NULL,
+						tf_warning_or_error), 
+			 idx);
 
   /* When using function descriptors, the address of the
      vtable entry is treated as a function pointer.  */
@@ -2019,27 +2070,29 @@  finish_struct_methods (tree t)
 	   len-slot, sizeof (tree), method_name_cmp);
 }
 
-/* Make BINFO's vtable have N entries, including RTTI entries,
-   vbase and vcall offsets, etc.  Set its type and call the back end
-   to lay it out.  */
+/* Build a type for VTABLE out of FIELDs.  Set its type and call the
+   back end to lay it out.  */
 
 static void
-layout_vtable_decl (tree binfo, int n)
+layout_vtable_decl (tree vtable, vec<tree, va_gc> *fields_vec)
 {
-  tree atype;
-  tree vtable;
-
-  atype = build_array_of_n_type (vtable_entry_type, n);
-  layout_type (atype);
+  size_t i;
+  tree fields = NULL_TREE;
+  tree field;
 
-  /* We may have to grow the vtable.  */
-  vtable = get_vtbl_decl_for_binfo (binfo);
-  if (!same_type_p (TREE_TYPE (vtable), atype))
+  FOR_EACH_VEC_SAFE_ELT (fields_vec, i, field)
     {
-      TREE_TYPE (vtable) = atype;
-      DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = NULL_TREE;
-      layout_decl (vtable, 0);
+      TREE_CHAIN (field) = fields;
+      fields = field;
     }
+
+  tree type = make_class_type (RECORD_TYPE);
+  finish_builtin_struct (type, "vtbl type", fields, NULL_TREE);
+  TREE_PUBLIC (TYPE_MAIN_DECL (type)) = 1;
+
+  TREE_TYPE (vtable) = type;
+  DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = NULL_TREE;
+  layout_decl (vtable, 0);
 }
 
 /* True iff FNDECL and BASE_FNDECL (both non-static member functions)
@@ -2229,6 +2282,21 @@  find_final_overrider (tree derived, tree binfo, tree fn)
   return ffod.candidates;
 }
 
+/* Convert a negative index from the vtable to an offset in terms of
+   bytes.  The indices are sizetype fields, possibly aligned to
+   pointer alignment if that is greater.  */
+
+tree
+vbase_offset_from_index (tree index)
+{
+  tree off1 = size_binop (MULT_EXPR, index,
+			  convert (ssizetype,
+				   TYPE_SIZE_UNIT (size_type_node)));
+  tree off2 = vfunc_array_vtbl_offset ();
+  off2 = convert (ssizetype, off2);
+  return size_binop (MINUS_EXPR, off1, off2);
+}
+
 /* Return the index of the vcall offset for FN when TYPE is used as a
    virtual base.  */
 
@@ -7768,9 +7836,9 @@  get_vtbl_decl_for_binfo (tree binfo)
   tree decl;
 
   decl = BINFO_VTABLE (binfo);
-  if (decl && TREE_CODE (decl) == POINTER_PLUS_EXPR)
+  if (decl && TREE_CODE (decl) == ADDR_EXPR)
     {
-      gcc_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR);
+      gcc_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == COMPONENT_REF);
       decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
     }
   if (decl)
@@ -7944,25 +8012,62 @@  dump_class_hierarchy (tree t)
 }
 
 static void
-dump_array (FILE * stream, tree decl)
+dump_array (FILE * stream, tree decl, tree inits, long off)
 {
   tree value;
   unsigned HOST_WIDE_INT ix;
   HOST_WIDE_INT elt;
-  tree size = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (decl)));
+  int nelts = CONSTRUCTOR_NELTS (inits);
+
+  gcc_assert (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE);
 
   elt = (tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_TYPE (decl))), 0)
 	 / BITS_PER_UNIT);
+
+  if (TREE_CODE (decl) == FIELD_DECL)
+    {
+      if (nelts == 0)
+	return;
+      fprintf (stream, " subarray with %d entries\n", nelts);
+    }
+  else
+    {
+      fprintf (stream, "%s:", decl_as_string (decl, TFF_PLAIN_IDENTIFIER));
+      fprintf (stream, " %d toplevel entries\n\n",
+	       (int)CONSTRUCTOR_NELTS (inits));
+    }
+
+  
+  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (inits), ix, value)
+    fprintf (stream, "%-8ld  %s\n", (long)(off + ix * elt),
+	     expr_as_string (value, TFF_PLAIN_IDENTIFIER));
+}
+
+static void
+dump_record (FILE * stream, tree decl)
+{
+  tree field;
+  tree value;
+  unsigned HOST_WIDE_INT ix;
+
   fprintf (stream, "%s:", decl_as_string (decl, TFF_PLAIN_IDENTIFIER));
-  fprintf (stream, " %s entries",
-	   expr_as_string (size_binop (PLUS_EXPR, size, size_one_node),
-			   TFF_PLAIN_IDENTIFIER));
+  fprintf (stream, " %d toplevel entries\n",
+	   (int)CONSTRUCTOR_NELTS (DECL_INITIAL (decl)));
   fprintf (stream, "\n");
 
+  field = TYPE_FIELDS (TREE_TYPE (decl));
   FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (DECL_INITIAL (decl)),
 			      ix, value)
-    fprintf (stream, "%-4ld  %s\n", (long)(ix * elt),
-	     expr_as_string (value, TFF_PLAIN_IDENTIFIER));
+    {
+      long off = TREE_INT_CST_LOW (byte_position (field));
+      if (TREE_CODE (value) == CONSTRUCTOR)
+	dump_array (stream, field, value, off);
+      else
+	fprintf (stream, "%-4ld  %s\n", off,
+		 expr_as_string (value, TFF_PLAIN_IDENTIFIER));
+
+      field = TREE_CHAIN (field);
+    }
 }
 
 static void
@@ -7989,7 +8094,7 @@  dump_vtable (tree t, tree binfo, tree vtable)
 	  fprintf (stream, " in %s", type_as_string (t, TFF_PLAIN_IDENTIFIER));
 	}
       fprintf (stream, "\n");
-      dump_array (stream, vtable);
+      dump_record (stream, vtable);
       fprintf (stream, "\n");
     }
 
@@ -8009,7 +8114,7 @@  dump_vtt (tree t, tree vtt)
     {
       fprintf (stream, "VTT for %s\n",
 	       type_as_string (t, TFF_PLAIN_IDENTIFIER));
-      dump_array (stream, vtt);
+      dump_array (stream, vtt, DECL_INITIAL (vtt), 0);
       fprintf (stream, "\n");
     }
 
@@ -8063,6 +8168,20 @@  debug_thunks (tree fn)
 
 /* Virtual function table initialization.  */
 
+/* Initialize the vtable for BINFO with the INITS.  */
+
+static void
+initialize_vtable (tree binfo, vec<constructor_elt, va_gc> *inits,
+		   vec<tree, va_gc> *fields)
+
+{
+  tree vtable = get_vtbl_decl_for_binfo (binfo);
+
+  layout_vtable_decl (vtable, fields);
+  initialize_artificial_var (vtable, inits);
+  dump_vtable (BINFO_TYPE (binfo), binfo, vtable);
+}
+
 /* Create all the necessary vtables for T and its base classes.  */
 
 static void
@@ -8070,37 +8189,25 @@  finish_vtbls (tree t)
 {
   tree vbase;
   vec<constructor_elt, va_gc> *v = NULL;
+  vec<tree, va_gc> *f = NULL;
   tree vtable = BINFO_VTABLE (TYPE_BINFO (t));
 
   /* We lay out the primary and secondary vtables in one contiguous
      vtable.  The primary vtable is first, followed by the non-virtual
      secondary vtables in inheritance graph order.  */
   accumulate_vtbl_inits (TYPE_BINFO (t), TYPE_BINFO (t), TYPE_BINFO (t),
-			 vtable, t, &v);
+			 vtable, t, &v, &f);
 
   /* Then come the virtual bases, also in inheritance graph order.  */
   for (vbase = TYPE_BINFO (t); vbase; vbase = TREE_CHAIN (vbase))
     {
       if (!BINFO_VIRTUAL_P (vbase))
 	continue;
-      accumulate_vtbl_inits (vbase, vbase, TYPE_BINFO (t), vtable, t, &v);
+      accumulate_vtbl_inits (vbase, vbase, TYPE_BINFO (t), vtable, t, &v, &f);
     }
 
   if (BINFO_VTABLE (TYPE_BINFO (t)))
-    initialize_vtable (TYPE_BINFO (t), v);
-}
-
-/* Initialize the vtable for BINFO with the INITS.  */
-
-static void
-initialize_vtable (tree binfo, vec<constructor_elt, va_gc> *inits)
-{
-  tree decl;
-
-  layout_vtable_decl (binfo, vec_safe_length (inits));
-  decl = get_vtbl_decl_for_binfo (binfo);
-  initialize_artificial_var (decl, inits);
-  dump_vtable (BINFO_TYPE (binfo), binfo, decl);
+    initialize_vtable (TYPE_BINFO (t), v, f);
 }
 
 /* Build the VTT (virtual table table) for T.
@@ -8358,6 +8465,7 @@  build_ctor_vtbl_group (tree binfo, tree t)
   tree id;
   tree vbase;
   vec<constructor_elt, va_gc> *v;
+  vec<tree, va_gc> *f;
 
   /* See if we've already created this construction vtable group.  */
   id = mangle_ctor_vtbl_for_type (t, binfo);
@@ -8378,8 +8486,9 @@  build_ctor_vtbl_group (tree binfo, tree t)
   DECL_VISIBILITY_SPECIFIED (vtbl) = true;
 
   v = NULL;
+  f = NULL;
   accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)),
-			 binfo, vtbl, t, &v);
+			 binfo, vtbl, t, &v, &f);
 
   /* Add the vtables for each of our virtual bases using the vbase in T
      binfo.  */
@@ -8393,7 +8502,7 @@  build_ctor_vtbl_group (tree binfo, tree t)
 	continue;
       b = copied_binfo (vbase, binfo);
 
-      accumulate_vtbl_inits (b, vbase, binfo, vtbl, t, &v);
+      accumulate_vtbl_inits (b, vbase, binfo, vtbl, t, &v, &f);
     }
 
   /* Figure out the type of the construction vtable.  */
@@ -8401,7 +8510,7 @@  build_ctor_vtbl_group (tree binfo, tree t)
   layout_type (type);
   TREE_TYPE (vtbl) = type;
   DECL_SIZE (vtbl) = DECL_SIZE_UNIT (vtbl) = NULL_TREE;
-  layout_decl (vtbl, 0);
+  layout_vtable_decl (vtbl, f);
 
   /* Initialize the construction vtable.  */
   CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);
@@ -8420,12 +8529,10 @@  build_ctor_vtbl_group (tree binfo, tree t)
    but are not necessarily the same in terms of layout.  */
 
 static void
-accumulate_vtbl_inits (tree binfo,
-		       tree orig_binfo,
-		       tree rtti_binfo,
-		       tree vtbl,
-		       tree t,
-		       vec<constructor_elt, va_gc> **inits)
+accumulate_vtbl_inits (tree binfo, tree orig_binfo, tree rtti_binfo,
+		       tree vtbl, tree t,
+		       vec<constructor_elt, va_gc> **inits,
+		       vec<tree, va_gc> **fields)
 {
   int i;
   tree base_binfo;
@@ -8445,7 +8552,8 @@  accumulate_vtbl_inits (tree binfo,
     return;
 
   /* Build the initializers for the BINFO-in-T vtable.  */
-  dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, vtbl, t, inits);
+  dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, vtbl, t,
+			     inits, fields);
 
   /* Walk the BINFO and its bases.  We walk in preorder so that as we
      initialize each vtable we can figure out at what offset the
@@ -8460,7 +8568,7 @@  accumulate_vtbl_inits (tree binfo,
       accumulate_vtbl_inits (base_binfo,
 			     BINFO_BASE_BINFO (orig_binfo, i),
 			     rtti_binfo, vtbl, t,
-			     inits);
+			     inits, fields);
     }
 }
 
@@ -8468,12 +8576,10 @@  accumulate_vtbl_inits (tree binfo,
    BINFO vtable to L.  */
 
 static void
-dfs_accumulate_vtbl_inits (tree binfo,
-			   tree orig_binfo,
-			   tree rtti_binfo,
-			   tree orig_vtbl,
-			   tree t,
-			   vec<constructor_elt, va_gc> **l)
+dfs_accumulate_vtbl_inits (tree binfo, tree orig_binfo, tree rtti_binfo,
+			   tree orig_vtbl, tree t,
+			   vec<constructor_elt, va_gc> **l,
+			   vec<tree, va_gc> **f)
 {
   tree vtbl = NULL_TREE;
   int ctor_vtbl_p = !SAME_BINFO_TYPE_P (BINFO_TYPE (rtti_binfo), t);
@@ -8533,23 +8639,22 @@  dfs_accumulate_vtbl_inits (tree binfo,
   else if (!BINFO_NEW_VTABLE_MARKED (orig_binfo))
     return;
 
+  gcc_assert (vec_safe_length (*f) == vec_safe_length (*l));
   n_inits = vec_safe_length (*l);
 
   if (!vtbl)
     {
-      tree index;
       int non_fn_entries;
 
       /* Add the initializer for this vtable.  */
       build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo,
-                              &non_fn_entries, l);
+                              &non_fn_entries, l, f);
 
+      tree field = (*f)->last ();
       /* Figure out the position to which the VPTR should point.  */
-      vtbl = build1 (ADDR_EXPR, vtbl_ptr_type_node, orig_vtbl);
-      index = size_binop (MULT_EXPR,
-			  TYPE_SIZE_UNIT (vtable_entry_type),
-			  size_int (non_fn_entries + n_inits));
-      vtbl = fold_build_pointer_plus (vtbl, index);
+      vtbl = build3 (COMPONENT_REF, TREE_TYPE (field), orig_vtbl, field,
+		     NULL_TREE);
+      vtbl = build1 (ADDR_EXPR, vtbl_ptr_type_node, vtbl);
     }
 
   if (ctor_vtbl_p)
@@ -8559,7 +8664,10 @@  dfs_accumulate_vtbl_inits (tree binfo,
     BINFO_VTABLE (binfo) = tree_cons (rtti_binfo, vtbl, BINFO_VTABLE (binfo));
   else if (BINFO_PRIMARY_P (binfo) && BINFO_VIRTUAL_P (binfo))
     /* Throw away any unneeded intializers.  */
-    (*l)->truncate (n_inits);
+    {
+      (*l)->truncate (n_inits);
+      (*f)->truncate (n_inits);
+    }
   else
      /* For an ordinary vtable, set BINFO_VTABLE.  */
     BINFO_VTABLE (binfo) = vtbl;
@@ -8596,7 +8704,8 @@  build_vtbl_initializer (tree binfo,
 			tree t,
 			tree rtti_binfo,
 			int* non_fn_entries_p,
-			vec<constructor_elt, va_gc> **inits)
+			vec<constructor_elt, va_gc> **inits,
+			vec<tree, va_gc> **fields)
 {
   tree v;
   vtbl_init_data vid;
@@ -8613,8 +8722,9 @@  build_vtbl_initializer (tree binfo,
   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;
-  /* The first vbase or vcall offset is at index -3 in the vtable.  */
-  vid.index = ssize_int(-3 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
+  /* The first vbase or vcall offset is at index -1 from the base of
+     the vtable.  */
+  vid.index = -TARGET_VTABLE_DATA_ENTRY_DISTANCE;
 
   /* Add entries to the vtable for RTTI.  */
   build_rtti_vtbl_entries (binfo, &vid);
@@ -8632,12 +8742,16 @@  build_vtbl_initializer (tree binfo,
        vec_safe_iterate (vbases, ix, &vbinfo); ix++)
     BINFO_VTABLE_PATH_MARKED (vbinfo) = 0;
 
-  /* If the target requires padding between data entries, add that now.  */
+  /* If the target requires padding between data entries, add that now.
+     We assume that in this case, size_type_node and const_ptr_type_node
+     have equal size.  */
   if (TARGET_VTABLE_DATA_ENTRY_DISTANCE > 1)
     {
       int n_entries = vec_safe_length (vid.inits);
+      int new_size = TARGET_VTABLE_DATA_ENTRY_DISTANCE * n_entries;
 
-      vec_safe_grow (vid.inits, TARGET_VTABLE_DATA_ENTRY_DISTANCE * n_entries);
+      vec_safe_grow (vid.inits, new_size);
+      vec_safe_grow (vid.fields, new_size);
 
       /* Move data entries into their new positions and add padding
 	 after the new positions.  Iterate backwards so we don't
@@ -8651,13 +8765,17 @@  build_vtbl_initializer (tree binfo,
 			      + (TARGET_VTABLE_DATA_ENTRY_DISTANCE - 1));
 
 	  (*vid.inits)[new_position] = *e;
+	  (*vid.fields)[new_position] = (*vid.fields)[ix];
 
 	  for (j = 1; j < TARGET_VTABLE_DATA_ENTRY_DISTANCE; ++j)
 	    {
-	      constructor_elt *f = &(*vid.inits)[new_position - j];
-	      f->index = NULL_TREE;
-	      f->value = build1 (NOP_EXPR, vtable_entry_type,
-				 null_pointer_node);
+	      tree *f = &(*vid.fields)[new_position - j];
+	      constructor_elt *e2 = &(*vid.inits)[new_position - j];
+	      *f = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+			       NULL, const_ptr_type_node);
+	      e2->index = *f;
+	      e2->value = build1 (NOP_EXPR, vtable_entry_type,
+				  null_pointer_node);
 	    }
 	}
     }
@@ -8665,19 +8783,36 @@  build_vtbl_initializer (tree binfo,
   if (non_fn_entries_p)
     *non_fn_entries_p = vec_safe_length (vid.inits);
 
+  /* Prepend alignment padding if necessary.  */
+  int inits_length = vid.inits->length ();
+  if (TARGET_VTABLE_DATA_ENTRY_DISTANCE == 1
+      && TYPE_ALIGN (const_ptr_type_node) > TYPE_ALIGN (size_type_node)
+      && (inits_length & 1) != 0)
+    {
+      tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+			       NULL, sizetype);
+      CONSTRUCTOR_APPEND_ELT (vid.inits, field, integer_minus_one_node);
+      vec_safe_push (vid.fields, field);
+    }
+
   /* The initializers for virtual functions were built up in reverse
      order.  Straighten them out and add them to the running list in one
      step.  */
   jx = vec_safe_length (*inits);
-  vec_safe_grow (*inits, jx + vid.inits->length ());
+  vec_safe_grow (*inits, jx + inits_length);
+  vec_safe_grow (*fields, jx + inits_length);
 
   for (ix = vid.inits->length () - 1;
        vid.inits->iterate (ix, &e);
        ix--, jx++)
-    (**inits)[jx] = *e;
+    {
+      (**inits)[jx] = *e;
+      (**fields)[jx] = (*vid.fields)[ix];
+    }
 
   /* Go through all the ordinary virtual functions, building up
      initializers.  */
+  vec<constructor_elt, va_gc> *vfun_inits = NULL;
   for (v = BINFO_VIRTUALS (orig_binfo); v; v = TREE_CHAIN (v))
     {
       tree delta;
@@ -8770,7 +8905,7 @@  build_vtbl_initializer (tree binfo,
 	  int i;
 	  if (init == size_zero_node)
 	    for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
-	      CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
+	      CONSTRUCTOR_APPEND_ELT (vfun_inits, NULL_TREE, init);
 	  else
 	    for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
 	      {
@@ -8778,12 +8913,31 @@  build_vtbl_initializer (tree binfo,
 				     fn, build_int_cst (NULL_TREE, i));
 		TREE_CONSTANT (fdesc) = 1;
 
-		CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, fdesc);
+		CONSTRUCTOR_APPEND_ELT (vfun_inits, NULL_TREE, fdesc);
 	      }
 	}
       else
-	CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
+	CONSTRUCTOR_APPEND_ELT (vfun_inits, NULL_TREE, init);
     }
+
+  int n = vec_safe_length (vfun_inits);
+  /* Append alignment padding if necessary.  */
+  if (TARGET_VTABLE_DATA_ENTRY_DISTANCE == 1
+      && TYPE_ALIGN (const_ptr_type_node) > TYPE_ALIGN (size_type_node)
+      && (n & 1) != 0)
+    CONSTRUCTOR_APPEND_ELT (vfun_inits, NULL_TREE, integer_minus_one_node);
+
+  tree atype;
+  if (n == 0)
+    atype = vtbl_array_type_node;
+  else
+    atype = build_cplus_array_type (vtable_entry_type,
+				    build_index_type (size_int (n - 1)));
+  tree afield = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL, atype);
+  vec_safe_push (*fields, afield);
+
+  tree new_cons = build_constructor (vtbl_array_type_node, vfun_inits);
+  CONSTRUCTOR_APPEND_ELT (*inits, afield, new_cons);
 }
 
 /* Adds to vid->inits the initializers for the vbase and vcall
@@ -8871,10 +9025,7 @@  build_vbase_offset_vtbl_entries (tree binfo, vtbl_init_data* vid)
       BINFO_VTABLE_PATH_MARKED (b) = 1;
 
       /* Figure out where we can find this vbase offset.  */
-      delta = size_binop (MULT_EXPR,
-			  vid->index,
-			  convert (ssizetype,
-				   TYPE_SIZE_UNIT (vtable_entry_type)));
+      delta = vbase_offset_from_index (ssize_int (vid->index));
       if (vid->primary_vtbl_p)
 	BINFO_VPTR_FIELD (b) = delta;
 
@@ -8883,8 +9034,7 @@  build_vbase_offset_vtbl_entries (tree binfo, vtbl_init_data* vid)
 	gcc_assert (tree_int_cst_equal (delta, BINFO_VPTR_FIELD (vbase)));
 
       /* The next vbase will come at a more negative offset.  */
-      vid->index = size_binop (MINUS_EXPR, vid->index,
-			       ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));
+      vid->index -= TARGET_VTABLE_DATA_ENTRY_DISTANCE;
 
       /* The initializer is the delta from BINFO to this virtual base.
 	 The vbase offsets go in reverse inheritance-graph order, and
@@ -8893,9 +9043,10 @@  build_vbase_offset_vtbl_entries (tree binfo, vtbl_init_data* vid)
       delta = size_diffop_loc (input_location,
 			   BINFO_OFFSET (b), BINFO_OFFSET (non_primary_binfo));
 
-      CONSTRUCTOR_APPEND_ELT (vid->inits, NULL_TREE,
-			      fold_build1_loc (input_location, NOP_EXPR,
-					       vtable_entry_type, delta));
+      tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL,
+			       size_type_node);
+      CONSTRUCTOR_APPEND_ELT (vid->inits, field, delta);
+      vec_safe_push (vid->fields, field);
     }
 }
 
@@ -9089,14 +9240,13 @@  add_vcall_offset (tree orig_fn, tree binfo, vtbl_init_data *vid)
      offset.  */
   if (vid->binfo == TYPE_BINFO (vid->derived))
     {
-      tree_pair_s elt = {orig_fn, vid->index};
+      tree_pair_s elt = {orig_fn, ssize_int (vid->index) };
       vec_safe_push (CLASSTYPE_VCALL_INDICES (vid->derived), elt);
     }
 
   /* The next vcall offset will be found at a more negative
      offset.  */
-  vid->index = size_binop (MINUS_EXPR, vid->index,
-			   ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));
+  vid->index -= TARGET_VTABLE_DATA_ENTRY_DISTANCE;
 
   /* Keep track of this function.  */
   vec_safe_push (vid->fns, orig_fn);
@@ -9121,12 +9271,12 @@  add_vcall_offset (tree orig_fn, tree binfo, vtbl_init_data *vid)
 	  vcall_offset = size_diffop_loc (input_location,
 				      BINFO_OFFSET (base),
 				      BINFO_OFFSET (vid->binfo));
-	  vcall_offset = fold_build1_loc (input_location,
-				      NOP_EXPR, vtable_entry_type,
-				      vcall_offset);
 	}
       /* Add the initializer to the vtable.  */
-      CONSTRUCTOR_APPEND_ELT (vid->inits, NULL_TREE, vcall_offset);
+      tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL,
+			       size_type_node);
+      CONSTRUCTOR_APPEND_ELT (vid->inits, field, vcall_offset);
+      vec_safe_push (vid->fields, field);
     }
 }
 
@@ -9141,7 +9291,6 @@  build_rtti_vtbl_entries (tree binfo, vtbl_init_data* vid)
   tree t;
   tree offset;
   tree decl;
-  tree init;
 
   t = BINFO_TYPE (vid->rtti_binfo);
 
@@ -9165,18 +9314,19 @@  build_rtti_vtbl_entries (tree binfo, vtbl_init_data* vid)
   if (flag_rtti)
     decl = build_address (get_tinfo_decl (t));
   else
-    decl = integer_zero_node;
+    decl = null_pointer_node;
 
-  /* Convert the declaration to a type that can be stored in the
-     vtable.  */
-  init = build_nop (vfunc_ptr_type_node, decl);
-  CONSTRUCTOR_APPEND_ELT (vid->inits, NULL_TREE, init);
+  tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL,
+			   const_ptr_type_node);
+  CONSTRUCTOR_APPEND_ELT (vid->inits, field, decl);
+  vec_safe_push (vid->fields, field);
 
   /* Add the offset-to-top entry.  It comes earlier in the vtable than
-     the typeinfo entry.  Convert the offset to look like a
-     function pointer, so that we can put it in the vtable.  */
-  init = build_nop (vfunc_ptr_type_node, offset);
-  CONSTRUCTOR_APPEND_ELT (vid->inits, NULL_TREE, init);
+     the typeinfo entry.  */
+  tree field2 = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL,
+			    size_type_node);
+  CONSTRUCTOR_APPEND_ELT (vid->inits, field2, offset);
+  vec_safe_push (vid->fields, field2);
 }
 
 /* TRUE iff TYPE is uniquely derived from PARENT.  Ignores
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f7c65b6..8c90e3a8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -844,6 +844,7 @@  enum cp_tree_index
     CPTI_UNKNOWN_TYPE,
     CPTI_INIT_LIST_TYPE,
     CPTI_VTBL_TYPE,
+    CPTI_VTBL_ARRAY_TYPE,
     CPTI_VTBL_PTR_TYPE,
     CPTI_STD,
     CPTI_ABI,
@@ -868,6 +869,9 @@  enum cp_tree_index
     CPTI_PFN_IDENTIFIER,
     CPTI_VPTR_IDENTIFIER,
     CPTI_STD_IDENTIFIER,
+    CPTI_VOFFSET_IDENTIFIER,
+    CPTI_VTI_IDENTIFIER,
+    CPTI_ARRAY_IDENTIFIER,
 
     CPTI_LANG_NAME_C,
     CPTI_LANG_NAME_CPLUSPLUS,
@@ -915,6 +919,7 @@  extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define unknown_type_node		cp_global_trees[CPTI_UNKNOWN_TYPE]
 #define init_list_type_node		cp_global_trees[CPTI_INIT_LIST_TYPE]
 #define vtbl_type_node			cp_global_trees[CPTI_VTBL_TYPE]
+#define vtbl_array_type_node		cp_global_trees[CPTI_VTBL_ARRAY_TYPE]
 #define vtbl_ptr_type_node		cp_global_trees[CPTI_VTBL_PTR_TYPE]
 #define std_node			cp_global_trees[CPTI_STD]
 #define abi_node			cp_global_trees[CPTI_ABI]
@@ -957,6 +962,9 @@  extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define this_identifier			cp_global_trees[CPTI_THIS_IDENTIFIER]
 #define pfn_identifier			cp_global_trees[CPTI_PFN_IDENTIFIER]
 #define vptr_identifier			cp_global_trees[CPTI_VPTR_IDENTIFIER]
+#define voffset_identifier		cp_global_trees[CPTI_VOFFSET_IDENTIFIER]
+#define vti_identifier			cp_global_trees[CPTI_VTI_IDENTIFIER]
+#define array_identifier		cp_global_trees[CPTI_ARRAY_IDENTIFIER]
 /* The name of the std namespace.  */
 #define std_identifier			cp_global_trees[CPTI_STD_IDENTIFIER]
 #define lang_name_c			cp_global_trees[CPTI_LANG_NAME_C]
@@ -5039,7 +5047,10 @@  extern tree build_base_path			(enum tree_code, tree,
 extern tree convert_to_base			(tree, tree, bool, bool,
 						 tsubst_flags_t);
 extern tree convert_to_base_statically		(tree, tree);
+extern tree vbase_offset_from_index		(tree);
 extern tree build_vtbl_ref			(tree, tree);
+extern tree build_vtbl_rtti_offset_ref		(tree);
+extern tree build_vtbl_rtti_object_ref		(tree);
 extern tree build_vfn_ref			(tree, tree);
 extern tree get_vtable_decl			(tree, int);
 extern void resort_type_method_vec		(void *, void *,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 01804d2..cee6901 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -129,6 +129,7 @@  static void expand_static_init (tree, tree);
    Array type `vtable_entry_type[]'
 
 	tree vtbl_type_node;
+	tree vtbl_array_node;
 	tree vtbl_ptr_type_node;
 
    Namespaces,
@@ -3609,6 +3610,9 @@  initialize_predefined_identifiers (void)
     { "__comp_dtor ", &complete_dtor_identifier, 1 },
     { "__base_dtor ", &base_dtor_identifier, 1 },
     { "__deleting_dtor ", &deleting_dtor_identifier, 1 },
+    { "__voffset", &voffset_identifier, 0 },
+    { "__vti", &vti_identifier, 0 },
+    { "__array", &array_identifier, 0 },
     { IN_CHARGE_NAME, &in_charge_identifier, 0 },
     { "nelts", &nelts_identifier, 0 },
     { THIS_NAME, &this_identifier, 0 },
@@ -3629,6 +3633,39 @@  initialize_predefined_identifiers (void)
     }
 }
 
+/* Build and return the RECORD_TYPE for a vtable, using ATYPE as the
+   array type for the last member.  */
+
+static tree
+create_vtable_type (tree atype)
+{
+  tree field, fields, type;
+
+  field = build_decl (BUILTINS_LOCATION,
+		      FIELD_DECL, voffset_identifier, size_type_node);
+  fields = field;
+
+  field = build_decl (BUILTINS_LOCATION,
+		      FIELD_DECL, vti_identifier,
+		      build_pointer_type (void_type_node));
+  TREE_CHAIN (field) = fields;
+  fields = field;
+
+  field = build_decl (BUILTINS_LOCATION,
+		      FIELD_DECL, array_identifier,
+		      atype);
+  TREE_CHAIN (field) = fields;
+  fields = field;
+
+  type = make_class_type (RECORD_TYPE);
+  finish_builtin_struct (type, "vtbl type", fields, NULL_TREE);
+  TREE_PUBLIC (TYPE_MAIN_DECL (type)) = 1;
+  /* Ensure this is seen as an incomplete type by LTO.  */
+  TYPE_SIZE (type) = NULL_TREE;
+  return type;
+}
+
+
 /* Create the predefined scalar types of C,
    and some nodes representing standard constants (0, 1, (void *)0).
    Initialize the global binding level.
@@ -3731,11 +3768,13 @@  cxx_init_decl_processing (void)
   }
   record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type);
 
-  vtbl_type_node
+  vtbl_array_type_node
     = build_cplus_array_type (vtable_entry_type, NULL_TREE);
-  layout_type (vtbl_type_node);
-  vtbl_type_node = cp_build_qualified_type (vtbl_type_node, TYPE_QUAL_CONST);
-  record_builtin_type (RID_MAX, NULL, vtbl_type_node);
+  layout_type (vtbl_array_type_node);
+  vtbl_array_type_node
+    = cp_build_qualified_type (vtbl_array_type_node, TYPE_QUAL_CONST);
+  record_builtin_type (RID_MAX, NULL, vtbl_array_type_node);
+  vtbl_type_node = create_vtable_type (vtbl_array_type_node);
   vtbl_ptr_type_node = build_pointer_type (vtable_entry_type);
   layout_type (vtbl_ptr_type_node);
   record_builtin_type (RID_MAX, NULL, vtbl_ptr_type_node);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a5b2655..08b0459 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -1578,37 +1578,57 @@  coerce_delete_type (tree type)
   return type;
 }
 
+/* A subroutine of mark_vtable_entries.  Mark a single element we found
+   in a vtable as needed.  */
+
+static void
+mark_vtable_elt (tree elt)
+{
+  tree fn;
+
+  while (CONVERT_EXPR_P (elt))
+    elt = TREE_OPERAND (elt, 0);
+
+  if (TREE_CODE (elt) != ADDR_EXPR
+      && TREE_CODE (elt) != FDESC_EXPR)
+    /* This entry is an offset: a virtual base class offset, a
+       virtual call offset, an RTTI offset, etc.  */
+    return;
+
+  fn = TREE_OPERAND (elt, 0);
+  TREE_ADDRESSABLE (fn) = 1;
+  /* When we don't have vcall offsets, we output thunks whenever
+     we output the vtables that contain them.  With vcall offsets,
+     we know all the thunks we'll need when we emit a virtual
+     function, so we emit the thunks there instead.  */
+  if (DECL_THUNK_P (fn))
+    use_thunk (fn, /*emit_p=*/0);
+  mark_used (fn);
+}
+
 /* DECL is a VAR_DECL for a vtable: walk through the entries in the vtable
    and mark them as needed.  */
 
 static void
 mark_vtable_entries (tree decl)
 {
-  tree fnaddr;
-  unsigned HOST_WIDE_INT idx;
+  tree elt;
+  unsigned HOST_WIDE_INT outer_idx;
 
   FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (DECL_INITIAL (decl)),
-			      idx, fnaddr)
+			      outer_idx, elt)
     {
-      tree fn;
-
-      STRIP_NOPS (fnaddr);
-
-      if (TREE_CODE (fnaddr) != ADDR_EXPR
-	  && TREE_CODE (fnaddr) != FDESC_EXPR)
-	/* This entry is an offset: a virtual base class offset, a
-	   virtual call offset, an RTTI offset, etc.  */
-	continue;
+      tree fnaddr;
+      unsigned HOST_WIDE_INT idx;
 
-      fn = TREE_OPERAND (fnaddr, 0);
-      TREE_ADDRESSABLE (fn) = 1;
-      /* When we don't have vcall offsets, we output thunks whenever
-	 we output the vtables that contain them.  With vcall offsets,
-	 we know all the thunks we'll need when we emit a virtual
-	 function, so we emit the thunks there instead.  */
-      if (DECL_THUNK_P (fn))
-	use_thunk (fn, /*emit_p=*/0);
-      mark_used (fn);
+      if (TREE_CODE (elt) != CONSTRUCTOR)
+	{
+	  mark_vtable_elt (elt);
+	  continue;
+	}
+      FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (elt),
+				  idx, fnaddr)
+	mark_vtable_elt (fnaddr);
     }
 }
 
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 316c5d3..9128d38 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -87,13 +87,8 @@  make_thunk (tree function, bool this_adjusting,
   gcc_assert (!DECL_THIS_THUNK_P (function));
   gcc_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting);
 
-  /* Scale the VIRTUAL_OFFSET to be in terms of bytes.  */
   if (this_adjusting && virtual_offset)
-    virtual_offset
-      = size_binop (MULT_EXPR,
-		    virtual_offset,
-		    convert (ssizetype,
-			     TYPE_SIZE_UNIT (vtable_entry_type)));
+    virtual_offset = vbase_offset_from_index (virtual_offset);
 
   d = tree_low_cst (fixed_offset, 0);
 
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index b3c6687..99b7824 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -171,7 +171,6 @@  build_headof (tree exp)
 {
   tree type = TREE_TYPE (exp);
   tree offset;
-  tree index;
 
   gcc_assert (TYPE_PTR_P (type));
   type = TREE_TYPE (type);
@@ -182,13 +181,8 @@  build_headof (tree exp)
   /* We use this a couple of times below, protect it.  */
   exp = save_expr (exp);
 
-  /* The offset-to-top field is at index -2 from the vptr.  */
-  index = build_int_cst (NULL_TREE,
-			 -2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
-
-  offset = build_vtbl_ref (cp_build_indirect_ref (exp, RO_NULL, 
-                                                  tf_warning_or_error), 
-                           index);
+  offset = build_vtbl_rtti_offset_ref (cp_build_indirect_ref (exp, RO_NULL, 
+							      tf_warning_or_error));
 
   type = cp_build_qualified_type (ptr_type_node,
 				  cp_type_quals (TREE_TYPE (exp)));
@@ -263,12 +257,7 @@  get_tinfo_decl_dynamic (tree exp, tsubst_flags_t complain)
   if (TYPE_POLYMORPHIC_P (type) && ! resolves_to_fixed_type_p (exp, 0))
     {
       /* build reference to type_info from vtable.  */
-      tree index;
-
-      /* The RTTI information is at index -1.  */
-      index = build_int_cst (NULL_TREE,
-			     -1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
-      t = build_vtbl_ref (exp, index);
+      t = build_vtbl_rtti_object_ref (exp);
       t = convert (type_info_ptr_type, t);
     }
   else
@@ -904,6 +893,7 @@  tinfo_base_init (tinfo_s *ti, tree target)
   vtable_ptr = ti->vtable;
   if (!vtable_ptr)
     {
+      tree field;
       tree real_type;
       push_abi_namespace ();
       real_type = xref_tag (class_type, ti->name,
@@ -920,14 +910,11 @@  tinfo_base_init (tinfo_s *ti, tree target)
 	}
 
       vtable_ptr = get_vtable_decl (real_type, /*complete=*/1);
-      vtable_ptr = cp_build_addr_expr (vtable_ptr, tf_warning_or_error);
+      field = TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (vtable_ptr))));
+      vtable_ptr = build3 (COMPONENT_REF, TREE_TYPE (field), vtable_ptr,
+			   field, NULL_TREE);
 
-      /* We need to point into the middle of the vtable.  */
-      vtable_ptr = fold_build_pointer_plus
-	(vtable_ptr,
-	 size_binop (MULT_EXPR,
-		     size_int (2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE),
-		     TYPE_SIZE_UNIT (vtable_entry_type)));
+      vtable_ptr = cp_build_addr_expr (vtable_ptr, tf_warning_or_error);
 
       ti->vtable = vtable_ptr;
     }