OSDN Git Service

2004-12-03 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / java / class.c
index a1c7249..c314950 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions related to building classes and their related objects.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -42,6 +42,9 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "ggc.h"
 #include "stdio.h"
 #include "target.h"
+#include "except.h"
+#include "cgraph.h"
+#include "tree-iterator.h"
 
 /* DOS brain-damage */
 #ifndef O_BINARY
@@ -55,13 +58,11 @@ static tree make_field_value (tree);
 static tree get_dispatch_vector (tree);
 static tree get_dispatch_table (tree, tree);
 static int supers_all_compiled (tree type);
-static void add_interface_do (tree, tree, int);
 static tree maybe_layout_super_class (tree, tree);
 static void add_miranda_methods (tree, tree);
 static int assume_compiled (const char *);
-static tree build_method_symbols_entry (tree);
-
-static GTY(()) rtx registerClass_libfunc;
+static tree build_symbol_entry (tree);
+static tree emit_assertion_table (tree);
 
 struct obstack temporary_obstack;
 
@@ -69,30 +70,32 @@ struct obstack temporary_obstack;
    it can assume certain classes have been compiled down to native
    code or not.  The compiler options -fassume-compiled= and
    -fno-assume-compiled= are used to create a tree of
-   assume_compiled_node objects.  This tree is queried to determine if
+   class_flag_node objects.  This tree is queried to determine if
    a class is assume to be compiled or not.  Each node in the tree
    represents either a package or a specific class.  */
 
-typedef struct assume_compiled_node_struct
+typedef struct class_flag_node_struct
 {
   /* The class or package name.  */
   const char *ident;
 
   /* Nonzero if this represents an exclusion.  */
-  int excludep;
+  int value;
 
   /* Pointers to other nodes in the tree.  */
-  struct assume_compiled_node_struct *parent;
-  struct assume_compiled_node_struct *sibling;
-  struct assume_compiled_node_struct *child;
-} assume_compiled_node;
+  struct class_flag_node_struct *parent;
+  struct class_flag_node_struct *sibling;
+  struct class_flag_node_struct *child;
+} class_flag_node;
 
-static assume_compiled_node *find_assume_compiled_node (assume_compiled_node *,
-                                                       const char *);
+static class_flag_node *find_class_flag_node (class_flag_node *, const char *);
+static void add_class_flag (class_flag_node **, const char *, int);
 
 /* This is the root of the include/exclude tree.  */
 
-static assume_compiled_node *assume_compiled_tree;
+static class_flag_node *assume_compiled_tree;
+
+static class_flag_node *enable_assert_tree;
 
 static GTY(()) tree class_roots[5];
 #define registered_class class_roots[0]
@@ -102,11 +105,11 @@ static GTY(()) tree class_roots[5];
 #define class_dtable_decl class_roots[4]
 
 /* Return the node that most closely represents the class whose name
-   is IDENT.  Start the search from NODE.  Return NULL if an
-   appropriate node does not exist.  */
+   is IDENT.  Start the search from NODE (followed by its siblings).
+   Return NULL if an appropriate node does not exist.  */
 
-static assume_compiled_node *
-find_assume_compiled_node (assume_compiled_node *node, const char *ident)
+static class_flag_node *
+find_class_flag_node (class_flag_node *node, const char *ident)
 {
   while (node)
     {
@@ -119,14 +122,13 @@ find_assume_compiled_node (assume_compiled_node *node, const char *ident)
 
       if (node_ident_length == 0
          || (strncmp (ident, node->ident, node_ident_length) == 0
-             && (strlen (ident) == node_ident_length
+             && (ident[node_ident_length] == '\0'
                  || ident[node_ident_length] == '.')))
        {
          /* We've found a match, however, there might be a more
              specific match.  */
 
-         assume_compiled_node *found = find_assume_compiled_node (node->child,
-                                                                  ident);
+         class_flag_node *found = find_class_flag_node (node->child, ident);
          if (found)
            return found;
          else
@@ -141,54 +143,77 @@ find_assume_compiled_node (assume_compiled_node *node, const char *ident)
   return NULL;
 }
 
-/* Add a new IDENT to the include/exclude tree.  It's an exclusion
-   if EXCLUDEP is nonzero.  */
-
 void
-add_assume_compiled (const char *ident, int excludep)
+add_class_flag (class_flag_node **rootp, const char *ident, int value)
 {
-  int len;
-  assume_compiled_node *parent;
-  assume_compiled_node *node = xmalloc (sizeof (assume_compiled_node));
-
-  node->ident = xstrdup (ident);
-  node->excludep = excludep;
-  node->child = NULL;
+  class_flag_node *root = *rootp;
+  class_flag_node *parent, *node;
 
   /* Create the root of the tree if it doesn't exist yet.  */
 
-  if (NULL == assume_compiled_tree)
+  if (NULL == root)
     {
-      assume_compiled_tree = xmalloc (sizeof (assume_compiled_node));
-      assume_compiled_tree->ident = "";
-      assume_compiled_tree->excludep = 0;
-      assume_compiled_tree->sibling = NULL;
-      assume_compiled_tree->child = NULL;
-      assume_compiled_tree->parent = NULL;
+      root = xmalloc (sizeof (class_flag_node));
+      root->ident = "";
+      root->value = 0;
+      root->sibling = NULL;
+      root->child = NULL;
+      root->parent = NULL;
+      *rootp = root;
     }
 
   /* Calling the function with the empty string means we're setting
-     excludep for the root of the hierarchy.  */
+     value for the root of the hierarchy.  */
 
   if (0 == ident[0])
     {
-      assume_compiled_tree->excludep = excludep;
+      root->value = value;
       return;
     }
 
   /* Find the parent node for this new node.  PARENT will either be a
      class or a package name.  Adjust PARENT accordingly.  */
 
-  parent = find_assume_compiled_node (assume_compiled_tree, ident);
-  len = strlen (parent->ident);
-  if (parent->ident[len] && parent->ident[len] != '.')
-    parent = parent->parent;
+  parent = find_class_flag_node (root, ident);
+  if (strcmp (ident, parent->ident) == 0)
+    parent->value = value;
+  else
+    {
+      /* Insert new node into the tree.  */
+      node = xmalloc (sizeof (class_flag_node));
+
+      node->ident = xstrdup (ident);
+      node->value = value;
+      node->child = NULL;
 
-  /* Insert NODE into the tree.  */
+      node->parent = parent;
+      node->sibling = parent->child;
+      parent->child = node;
+    }
+}
+
+/* Add a new IDENT to the include/exclude tree.  It's an exclusion
+   if EXCLUDEP is nonzero.  */
 
-  node->parent = parent;
-  node->sibling = parent->child;
-  parent->child = node;
+void
+add_assume_compiled (const char *ident, int excludep)
+{
+  add_class_flag (&assume_compiled_tree, ident, excludep);
+}
+
+/* The default value returned by enable_assertions. */
+
+#define DEFAULT_ENABLE_ASSERT (flag_emit_class_files || optimize == 0)
+
+/* Enter IDENT (a class or package name) into the enable-assertions table.
+   VALUE is true to enable and false to disable. */
+
+void
+add_enable_assert (const char *ident, int value)
+{
+  if (enable_assert_tree == NULL)
+    add_class_flag (&enable_assert_tree, "", DEFAULT_ENABLE_ASSERT);
+  add_class_flag (&enable_assert_tree, ident, value);
 }
 
 /* Returns nonzero if IDENT is the name of a class that the compiler
@@ -197,20 +222,39 @@ add_assume_compiled (const char *ident, int excludep)
 static int
 assume_compiled (const char *ident)
 {
-  assume_compiled_node *i;
+  class_flag_node *i;
   int result;
   
   if (NULL == assume_compiled_tree)
     return 1;
 
-  i = find_assume_compiled_node (assume_compiled_tree,
-                                ident);
+  i = find_class_flag_node (assume_compiled_tree, ident);
 
-  result = ! i->excludep;
+  result = ! i->value;
   
   return (result);
 }
 
+/* Return true if we should generate code to check assertions within KLASS. */
+
+bool
+enable_assertions (tree klass)
+{
+  /* Check if command-line specifies whether we should check assertions. */
+
+  if (klass != NULL_TREE && DECL_NAME (klass) && enable_assert_tree != NULL)
+    {
+      const char *ident = IDENTIFIER_POINTER (DECL_NAME (klass));
+      class_flag_node *node
+       = find_class_flag_node (enable_assert_tree, ident);
+      return node->value;
+    }
+
+  /* The default is to enable assertions if generating class files,
+     or not optimizing. */
+  return DEFAULT_ENABLE_ASSERT;
+}
+
 /* Return an IDENTIFIER_NODE the same as (OLD_NAME, OLD_LENGTH).
    except that characters matching OLD_CHAR are substituted by NEW_CHAR.
    Also, PREFIX is prepended, and SUFFIX is appended. */
@@ -226,11 +270,8 @@ ident_subst (const char* old_name,
   int prefix_len = strlen (prefix);
   int suffix_len = strlen (suffix);
   int i = prefix_len + old_length + suffix_len + 1;
-#ifdef __GNUC__
-  char buffer[i];
-#else
   char *buffer = alloca (i);
-#endif
+
   strcpy (buffer, prefix);
   for (i = 0; i < old_length; i++)
     {
@@ -275,7 +316,6 @@ make_class (void)
 {
   tree type;
   type = make_node (RECORD_TYPE);
-  TYPE_BINFO (type) = make_tree_vec (BINFO_ELTS);
   MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type);
 
   return type;
@@ -304,15 +344,83 @@ unmangle_classname (const char *name, int name_length)
   return to_return;
 }
 
+#define GEN_TABLE(TABLE, NAME, TABLE_TYPE, TYPE)                       \
+do                                                                     \
+{                                                                      \
+  const char *typename = IDENTIFIER_POINTER (mangled_classname ("", TYPE)); \
+  char *buf = alloca (strlen (typename) + strlen (#NAME "_syms_") + 1);        \
+  tree decl;                                                           \
+                                                                       \
+  sprintf (buf, #NAME "_%s", typename);                                        \
+  TYPE_## TABLE ##_DECL (type) = decl =                                        \
+    build_decl (VAR_DECL, get_identifier (buf), TABLE_TYPE);           \
+  DECL_EXTERNAL (decl) = 1;                                            \
+  TREE_STATIC (decl) = 1;                                              \
+  TREE_READONLY (decl) = 1;                                            \
+  TREE_CONSTANT (decl) = 1;                                            \
+  DECL_IGNORED_P (decl) = 1;                                           \
+  /* Mark the table as belonging to this class.  */                    \
+  pushdecl (decl);                                                     \
+  MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);                          \
+  DECL_OWNER (decl) = TYPE;                                            \
+  sprintf (buf, #NAME "_syms_%s", typename);                           \
+  TYPE_## TABLE ##_SYMS_DECL (TYPE) =                                  \
+    build_decl (VAR_DECL, get_identifier (buf), symbols_array_type);   \
+  TREE_STATIC (TYPE_## TABLE ##_SYMS_DECL (TYPE)) = 1;                 \
+  TREE_CONSTANT (TYPE_## TABLE ##_SYMS_DECL (TYPE)) = 1;               \
+  DECL_IGNORED_P (TYPE_## TABLE ##_SYMS_DECL (TYPE)) = 1;              \
+  pushdecl (TYPE_## TABLE ##_SYMS_DECL (TYPE));                                \
+}                                                                      \
+while (0)
+
+/* Given a class, create the DECLs for all its associated indirect
+   dispatch tables.  */
+void
+gen_indirect_dispatch_tables (tree type)
+{
+  const char *typename = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+  {  
+    tree field = NULL;
+    char *buf = alloca (strlen (typename) + strlen ("_catch_classes_") + 1);
+    tree catch_class_type = make_node (RECORD_TYPE);
+
+    sprintf (buf, "_catch_classes_%s", typename);
+    PUSH_FIELD (catch_class_type, field, "address", utf8const_ptr_type);
+    PUSH_FIELD (catch_class_type, field, "classname", ptr_type_node);
+    FINISH_RECORD (catch_class_type);
+    
+    TYPE_CTABLE_DECL (type) 
+      = build_decl (VAR_DECL, get_identifier (buf),
+                   build_array_type (catch_class_type, 0));
+    DECL_EXTERNAL (TYPE_CTABLE_DECL (type)) = 1;
+    TREE_STATIC (TYPE_CTABLE_DECL (type)) = 1;
+    TREE_READONLY (TYPE_CTABLE_DECL (type)) = 1;
+    TREE_CONSTANT (TYPE_CTABLE_DECL (type)) = 1;
+    DECL_IGNORED_P (TYPE_CTABLE_DECL (type)) = 1;
+    pushdecl (TYPE_CTABLE_DECL (type));  
+  }
+
+  if (flag_indirect_dispatch)
+    {
+      GEN_TABLE (ATABLE, _atable, atable_type, type);
+      GEN_TABLE (OTABLE, _otable, otable_type, type);
+      GEN_TABLE (ITABLE, _itable, itable_type, type);
+    }
+}
+
+#undef GEN_TABLE
+
 tree
 push_class (tree class_type, tree class_name)
 {
   tree decl, signature;
   location_t saved_loc = input_location;
+#ifndef USE_MAPPED_LOCATION
   tree source_name = identifier_subst (class_name, "", '.', '/', ".java");
-  CLASS_P (class_type) = 1;
   input_filename = IDENTIFIER_POINTER (source_name);
   input_line = 0;
+#endif
+  CLASS_P (class_type) = 1;
   decl = build_decl (TYPE_DECL, class_name, class_type);
 
   /* dbxout needs a DECL_SIZE if in gstabs mode */
@@ -352,18 +460,19 @@ set_super_info (int access_flags, tree this_class,
 {
   int total_supers = interfaces_count;
   tree class_decl = TYPE_NAME (this_class);
+  
   if (super_class)
     total_supers++;
 
-  TYPE_BINFO_BASETYPES (this_class) = make_tree_vec (total_supers);
+  TYPE_BINFO (this_class) = make_tree_binfo (total_supers);
+  TYPE_VFIELD (this_class) = TYPE_VFIELD (object_type_node);
   if (super_class)
     {
-      tree super_binfo = make_tree_vec (BINFO_ELTS);
+      tree super_binfo = make_tree_binfo (0);
       BINFO_TYPE (super_binfo) = super_class;
       BINFO_OFFSET (super_binfo) = integer_zero_node;
-      TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (this_class)), 0)
-       = super_binfo;
-      CLASS_HAS_SUPER (this_class) = 1;
+      BINFO_BASE_APPEND (TYPE_BINFO (this_class), super_binfo);
+      CLASS_HAS_SUPER_FLAG (TYPE_BINFO (this_class)) = 1;
     }
 
   set_class_decl_access_flags (access_flags, class_decl);
@@ -397,7 +506,7 @@ class_depth (tree clas)
   while (clas != object_type_node)
     {
       depth++;
-      clas = TYPE_BINFO_BASETYPE (clas, 0);
+      clas = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (clas), 0));
     }
   return depth;
 }
@@ -407,25 +516,23 @@ class_depth (tree clas)
 int
 interface_of_p (tree type1, tree type2)
 {
-  int n, i;
-  tree basetype_vec;
+  int i;
+  tree binfo, base_binfo;
 
-  if (!(basetype_vec = TYPE_BINFO_BASETYPES (type2)))
+  if (! TYPE_BINFO (type2))
     return 0;
-  n = TREE_VEC_LENGTH (basetype_vec);
-  for (i = 0; i < n; i++)
-    {
-      tree vec_elt = TREE_VEC_ELT (basetype_vec, i);
-      if (vec_elt && BINFO_TYPE (vec_elt) == type1)
-       return 1;
-    }
-  for (i = 0; i < n; i++)
-    {
-      tree vec_elt = TREE_VEC_ELT (basetype_vec, i);
-      if (vec_elt && BINFO_TYPE (vec_elt) 
-         && interface_of_p (type1, BINFO_TYPE (vec_elt)))
-       return 1;
-    }
+
+  for (binfo = TYPE_BINFO (type2), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+    if (BINFO_TYPE (base_binfo) == type1)
+      return 1;
+  
+  for (binfo = TYPE_BINFO (type2), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) /*  */
+    if (BINFO_TYPE (base_binfo)
+       && interface_of_p (type1, BINFO_TYPE (base_binfo)))
+      return 1;
+  
   return 0;
 }
 
@@ -463,10 +570,36 @@ enclosing_context_p (tree type1, tree type2)
   return 0;
 }
 
-/* Return 1 iff there exists a common enclosing context between TYPE1
-   and TYPE2.  */
 
-int common_enclosing_context_p (tree type1, tree type2)
+/* Return 1 iff TYPE1 and TYPE2 share a common enclosing class, regardless of
+   nesting level.  */
+
+int
+common_enclosing_context_p (tree type1, tree type2)
+{
+  while (type1)
+    {
+      tree current;
+      for (current = type2; current;
+          current = (INNER_CLASS_TYPE_P (current) ?
+                     TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current))) : 
+                     NULL_TREE))
+       if (type1 == current)
+         return 1;
+
+      if (INNER_CLASS_TYPE_P (type1))
+        type1 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1)));
+      else
+        break;
+    }
+  return 0;
+}
+
+/* Return 1 iff there exists a common enclosing "this" between TYPE1
+   and TYPE2, without crossing any static context.  */
+
+int
+common_enclosing_instance_p (tree type1, tree type2)
 {
   if (!PURE_INNER_CLASS_TYPE_P (type1) || !PURE_INNER_CLASS_TYPE_P (type2))
     return 0;
@@ -486,17 +619,6 @@ int common_enclosing_context_p (tree type1, tree type2)
   return 0;
 }
 
-static void
-add_interface_do (tree basetype_vec, tree interface_class, int i)
-{
-  tree interface_binfo = make_tree_vec (BINFO_ELTS);
-  BINFO_TYPE (interface_binfo) = interface_class;
-  BINFO_OFFSET (interface_binfo) = integer_zero_node;
-  BINFO_VPTR_FIELD (interface_binfo) = integer_zero_node;
-  TREE_VIA_VIRTUAL (interface_binfo) = 1;
-  TREE_VEC_ELT (basetype_vec, i) = interface_binfo;
-}
-
 /* Add INTERFACE_CLASS to THIS_CLASS iff INTERFACE_CLASS can't be
    found in THIS_CLASS. Returns NULL_TREE upon success, INTERFACE_CLASS
    if attempt is made to add it twice. */
@@ -504,22 +626,14 @@ add_interface_do (tree basetype_vec, tree interface_class, int i)
 tree
 maybe_add_interface (tree this_class, tree interface_class)
 {
-  tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
+  tree binfo, base_binfo;
   int i;
-  int n = TREE_VEC_LENGTH (basetype_vec);
-  for (i = 0; ; i++)
-    {
-      if (i >= n)
-       {
-         error ("internal error - too many interface type");
-         return NULL_TREE;
-       }
-      else if (TREE_VEC_ELT (basetype_vec, i) == NULL_TREE)
-       break;
-      else if (BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i)) == interface_class)
-       return interface_class;
-    } 
-  add_interface_do (basetype_vec, interface_class, i);
+
+  for (binfo = TYPE_BINFO (this_class), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+    if (BINFO_TYPE (base_binfo) == interface_class)
+      return interface_class;
+  add_interface (this_class, interface_class);
   return NULL_TREE;
 }
 
@@ -528,20 +642,14 @@ maybe_add_interface (tree this_class, tree interface_class)
 void
 add_interface (tree this_class, tree interface_class)
 {
-  tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
-  int i;
-  int n = TREE_VEC_LENGTH (basetype_vec);
-  for (i = 0; ; i++)
-    {
-      if (i >= n)
-       {
-         error ("internal error - too many interface type");
-         return;
-       }
-      else if (TREE_VEC_ELT (basetype_vec, i) == NULL_TREE)
-       break;
-    }
-  add_interface_do (basetype_vec, interface_class, i);
+  tree interface_binfo = make_tree_binfo (0);
+  
+  BINFO_TYPE (interface_binfo) = interface_class;
+  BINFO_OFFSET (interface_binfo) = integer_zero_node;
+  BINFO_VPTR_FIELD (interface_binfo) = integer_zero_node;
+  BINFO_VIRTUAL_P (interface_binfo) = 1;
+  
+  BINFO_BASE_APPEND (TYPE_BINFO (this_class), interface_binfo);
 }
 
 #if 0
@@ -723,8 +831,8 @@ strLengthUtf8 (char *str, int len)
 static int32
 hashUtf8String (const char *str, int len)
 {
-  register const unsigned char* ptr = (const unsigned char*) str;
-  register const unsigned char *limit = ptr + len;
+  const unsigned char* ptr = (const unsigned char*) str;
+  const unsigned char *limit = ptr + len;
   int32 hash = 0;
   for (; ptr < limit;)
     {
@@ -761,13 +869,14 @@ build_utf8_ref (tree name)
   FINISH_RECORD (ctype);
   START_RECORD_CONSTRUCTOR (cinit, ctype);
   name_hash = hashUtf8String (name_ptr, name_len) & 0xFFFF;
-  PUSH_FIELD_VALUE (cinit, "hash", build_int_2 (name_hash, 0));
-  PUSH_FIELD_VALUE (cinit, "length", build_int_2 (name_len, 0));
+  PUSH_FIELD_VALUE (cinit, "hash", build_int_cst (NULL_TREE, name_hash));
+  PUSH_FIELD_VALUE (cinit, "length", build_int_cst (NULL_TREE, name_len));
   string = build_string (name_len, name_ptr);
   TREE_TYPE (string) = str_type;
   PUSH_FIELD_VALUE (cinit, "data", string);
   FINISH_RECORD_CONSTRUCTOR (cinit);
   TREE_CONSTANT (cinit) = 1;
+  TREE_INVARIANT (cinit) = 1;
 
   /* Generate a unique-enough identifier.  */
   sprintf(buf, "_Utf%d", ++utf8_count);
@@ -779,34 +888,48 @@ build_utf8_ref (tree name)
   TREE_READONLY (decl) = 1;
   TREE_THIS_VOLATILE (decl) = 0;
   DECL_INITIAL (decl) = cinit;
-#ifdef HAVE_GAS_SHF_MERGE
-  {
-    int decl_size;
-    /* Ensure decl_size is a multiple of utf8const_type's alignment. */
-    decl_size = (name_len + 5 + TYPE_ALIGN_UNIT (utf8const_type) - 1)
-                & ~(TYPE_ALIGN_UNIT (utf8const_type) - 1);
-    if (flag_merge_constants && decl_size < 256)
-      {
-        char buf[32];
-        int flags = (SECTION_OVERRIDE
-                  | SECTION_MERGE | (SECTION_ENTSIZE & decl_size));
-        sprintf (buf, ".rodata.jutf8.%d", decl_size);
-        named_section_flags (buf, flags);
-        DECL_SECTION_NAME (decl) = build_string (strlen (buf), buf);
-      }
-  }
-#endif
+
+  if (HAVE_GAS_SHF_MERGE)
+    {
+      int decl_size;
+      /* Ensure decl_size is a multiple of utf8const_type's alignment. */
+      decl_size = (name_len + 5 + TYPE_ALIGN_UNIT (utf8const_type) - 1)
+       & ~(TYPE_ALIGN_UNIT (utf8const_type) - 1);
+      if (flag_merge_constants && decl_size < 256)
+       {
+         char buf[32];
+         int flags = (SECTION_OVERRIDE
+                      | SECTION_MERGE | (SECTION_ENTSIZE & decl_size));
+         sprintf (buf, ".rodata.jutf8.%d", decl_size);
+         named_section_flags (buf, flags);
+         DECL_SECTION_NAME (decl) = build_string (strlen (buf), buf);
+       }
+    }
+
   TREE_CHAIN (decl) = utf8_decl_list;
   layout_decl (decl, 0);
   pushdecl (decl);
-  rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
+  rest_of_decl_compilation (decl, global_bindings_p (), 0);
   utf8_decl_list = decl;
-  make_decl_rtl (decl, (char*) 0);
+  make_decl_rtl (decl);
   ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl);
   IDENTIFIER_UTF8_REF (name) = ref;
   return ref;
 }
 
+/* Like build_class_ref, but instead of a direct reference generate a
+   pointer into the constant pool.  */
+
+static tree
+build_indirect_class_ref (tree type)
+{
+  int index;
+  tree cl;
+  index = alloc_class_constant (type);
+  cl = build_ref_from_constant_pool (index); 
+  return convert (promote_type (class_ptr_type), cl);
+}
+
 /* Build a reference to the class TYPE.
    Also handles primitive types and array types. */
 
@@ -819,6 +942,12 @@ build_class_ref (tree type)
       tree ref, decl_name, decl;
       if (TREE_CODE (type) == POINTER_TYPE)
        type = TREE_TYPE (type);
+
+      if  (flag_indirect_dispatch
+          && type != output_class
+          && TREE_CODE (type) == RECORD_TYPE)
+       return build_indirect_class_ref (type);
+
       if (TREE_CODE (type) == RECORD_TYPE)
        {
          if (TYPE_SIZE (type) == error_mark_node)
@@ -840,7 +969,7 @@ build_class_ref (tree type)
              SET_DECL_ASSEMBLER_NAME (decl, 
                                       java_mangle_class_field
                                       (&temporary_obstack, type));
-             make_decl_rtl (decl, NULL);
+             make_decl_rtl (decl);
              pushdecl_top_level (decl);
            }
        }
@@ -874,8 +1003,8 @@ build_class_ref (tree type)
                abort ();
 
              prim_class = lookup_class (get_identifier (prim_class_name));
-             return build (COMPONENT_REF, NULL_TREE,
-                           prim_class, TYPE_identifier_node);
+             return build3 (COMPONENT_REF, NULL_TREE,
+                            prim_class, TYPE_identifier_node, NULL_TREE);
            }
          decl_name = TYPE_NAME (type);
          if (TREE_CODE (decl_name) == TYPE_DECL)
@@ -892,7 +1021,8 @@ build_class_ref (tree type)
              TREE_STATIC (decl) = 1;
              TREE_PUBLIC (decl) = 1;
              DECL_EXTERNAL (decl) = 1;
-             make_decl_rtl (decl, NULL);
+             DECL_ARTIFICIAL (decl) = 1;
+             make_decl_rtl (decl);
              pushdecl_top_level (decl);
            }
        }
@@ -901,14 +1031,7 @@ build_class_ref (tree type)
       return ref;
     }
   else
-    {
-      int index;
-      tree cl;
-      index = alloc_class_constant (type);
-      cl = build_ref_from_constant_pool (index); 
-      TREE_TYPE (cl) = promote_type (class_ptr_type);
-      return cl;
-    }
+    return build_indirect_class_ref (type);
 }
 
 tree
@@ -924,7 +1047,7 @@ build_static_field_ref (tree fdecl)
      However, currently sometimes gcj is too eager and will end up
      returning the field itself, leading to an incorrect external
      reference being generated.  */
-  if (is_compiled
+  if ((is_compiled && !flag_indirect_dispatch)
       || (FIELD_FINAL (fdecl) && DECL_INITIAL (fdecl) != NULL_TREE
          && (JSTRING_TYPE_P (TREE_TYPE (fdecl))
              || JNUMERIC_TYPE_P (TREE_TYPE (fdecl)))
@@ -934,20 +1057,37 @@ build_static_field_ref (tree fdecl)
        {
          if (is_compiled == 1)
            DECL_EXTERNAL (fdecl) = 1;
-         make_decl_rtl (fdecl, NULL);
+         make_decl_rtl (fdecl);
        }
       return fdecl;
     }
-  else
+
+  if (flag_indirect_dispatch)
+    {
+      tree table_index 
+       = build_int_cst (NULL_TREE, get_symbol_table_index 
+                        (fdecl, &TYPE_ATABLE_METHODS (output_class)));
+      tree field_address
+       = build4 (ARRAY_REF, 
+                 TREE_TYPE (TREE_TYPE (TYPE_ATABLE_DECL (output_class))), 
+                 TYPE_ATABLE_DECL (output_class), table_index,
+                 NULL_TREE, NULL_TREE);
+      field_address = convert (build_pointer_type (TREE_TYPE (fdecl)),
+                              field_address);
+      return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl), 
+                          field_address));
+    }
+  else  
     {
       /* Compile as:
-       * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */
+       *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */
       tree ref = build_class_ref (fclass);
       tree fld;
       int field_index = 0;
       ref = build1 (INDIRECT_REF, class_type_node, ref);
-      ref = build (COMPONENT_REF, field_ptr_type_node, ref,
-                  lookup_field (&class_type_node, fields_ident));
+      ref = build3 (COMPONENT_REF, field_ptr_type_node, ref,
+                   lookup_field (&class_type_node, fields_ident),
+                   NULL_TREE);
 
       for (fld = TYPE_FIELDS (fclass); ; fld = TREE_CHAIN (fld))
        {
@@ -960,13 +1100,16 @@ build_static_field_ref (tree fdecl)
            field_index++;
        }
       field_index *= int_size_in_bytes (field_type_node);
-      ref = fold (build (PLUS_EXPR, field_ptr_type_node,
-                        ref, build_int_2 (field_index, 0)));
+      ref = fold (build2 (PLUS_EXPR, field_ptr_type_node,
+                         ref, build_int_cst (NULL_TREE, field_index)));
       ref = build1 (INDIRECT_REF, field_type_node, ref);
-      ref = build (COMPONENT_REF, field_info_union_node,
-                  ref, lookup_field (&field_type_node, info_ident));
-      ref = build (COMPONENT_REF, ptr_type_node,
-                  ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)));
+      ref = build3 (COMPONENT_REF, field_info_union_node,
+                   ref, lookup_field (&field_type_node, info_ident), 
+                   NULL_TREE);
+      ref = build3 (COMPONENT_REF, ptr_type_node,
+                   ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)),
+                   NULL_TREE);
+      ref = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (fdecl)), ref);
       return fold (build1 (INDIRECT_REF, TREE_TYPE(fdecl), ref));
     }
 }
@@ -1042,13 +1185,62 @@ get_access_flags_from_decl (tree decl)
   abort ();
 }
 
+static GTY (()) int alias_labelno = 0;
+
+/* Create a private alias for METHOD. Using this alias instead of the method
+   decl ensures that ncode entries in the method table point to the real function 
+   at runtime, not a PLT entry.  */
+
+static tree
+make_local_function_alias (tree method)
+{
+#ifdef ASM_OUTPUT_DEF
+  tree alias;
+  
+  const char *method_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (method));
+  char *name = alloca (strlen (method_name) + 2);
+  char *buf = alloca (strlen (method_name) + 128);
+
+  /* Only create aliases for local functions.  */
+  if (DECL_EXTERNAL (method))
+    return method;
+    
+  /* Prefix method_name with 'L' for the alias label.  */
+  *name = 'L';
+  strcpy (name + 1, method_name);
+
+  ASM_GENERATE_INTERNAL_LABEL (buf, name, alias_labelno++);  
+  alias = build_decl (FUNCTION_DECL, get_identifier (buf),
+                     TREE_TYPE (method));
+  DECL_CONTEXT (alias) = NULL;
+  TREE_READONLY (alias) = TREE_READONLY (method);
+  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (method);
+  TREE_PUBLIC (alias) = 0;
+  DECL_EXTERNAL (alias) = 0;
+  DECL_ARTIFICIAL (alias) = 1;
+  DECL_INLINE (alias) = 0;
+  DECL_INITIAL (alias) = error_mark_node;
+  TREE_ADDRESSABLE (alias) = 1;
+  TREE_USED (alias) = 1;
+  SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
+  TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1;
+  if (!flag_syntax_only)
+    assemble_alias (alias, DECL_ASSEMBLER_NAME (method));
+  return alias;
+#else
+  return method;
+#endif
+}
+
+/** Make reflection data (_Jv_Field) for field FDECL. */
+
 static tree
 make_field_value (tree fdecl)
 {
   tree finit;
   int flags;
   tree type = TREE_TYPE (fdecl);
-  int resolved = is_compiled_class (type);
+  int resolved = is_compiled_class (type) && ! flag_indirect_dispatch;
 
   START_RECORD_CONSTRUCTOR (finit, field_type_node);
   PUSH_FIELD_VALUE (finit, "name", build_utf8_ref (DECL_NAME (fdecl)));
@@ -1068,7 +1260,7 @@ make_field_value (tree fdecl)
   if (! resolved)
     flags |= 0x8000 /* FIELD_UNRESOLVED_FLAG */;
 
-  PUSH_FIELD_VALUE (finit, "accflags", build_int_2 (flags, 0));
+  PUSH_FIELD_VALUE (finit, "accflags", build_int_cst (NULL_TREE, flags));
   PUSH_FIELD_VALUE (finit, "bsize", TYPE_SIZE_UNIT (TREE_TYPE (fdecl)));
 
   PUSH_FIELD_VALUE
@@ -1079,13 +1271,15 @@ make_field_value (tree fdecl)
              ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
              : TYPE_FIELDS (field_info_union_node)),
             (FIELD_STATIC (fdecl)
-             ? build_address_of (build_static_field_ref (fdecl))
+             ? build_address_of (fdecl)
              : byte_position (fdecl)))));
 
   FINISH_RECORD_CONSTRUCTOR (finit);
   return finit;
 }
 
+/** Make reflection data (_Jv_Method) for method MDECL. */
+
 static tree
 make_method_value (tree mdecl)
 {
@@ -1093,17 +1287,24 @@ make_method_value (tree mdecl)
   tree minit;
   tree index;
   tree code;
+  tree class_decl;
 #define ACC_TRANSLATED          0x4000
   int accflags = get_access_flags_from_decl (mdecl) | ACC_TRANSLATED;
 
-  if (!flag_indirect_dispatch && DECL_VINDEX (mdecl) != NULL_TREE)
-    index = DECL_VINDEX (mdecl);
+  class_decl = DECL_CONTEXT (mdecl);
+  /* For interfaces, the index field contains the dispatch index. */
+  if (CLASS_INTERFACE (TYPE_NAME (class_decl)))
+    index = build_int_cst (NULL_TREE,
+                          get_interface_method_index (mdecl, class_decl));
+  else if (!flag_indirect_dispatch && get_method_index (mdecl) != NULL_TREE)
+    index = get_method_index (mdecl);
   else
     index = integer_minus_one_node;
 
   code = null_pointer_node;
   if (DECL_RTL_SET_P (mdecl))
-    code = build1 (ADDR_EXPR, nativecode_ptr_type_node, mdecl);
+    code = build1 (ADDR_EXPR, nativecode_ptr_type_node, 
+                  make_local_function_alias (mdecl));
   START_RECORD_CONSTRUCTOR (minit, method_type_node);
   PUSH_FIELD_VALUE (minit, "name",
                    build_utf8_ref (DECL_CONSTRUCTOR_P (mdecl) ?
@@ -1117,7 +1318,7 @@ make_method_value (tree mdecl)
                        (IDENTIFIER_POINTER(signature),
                         IDENTIFIER_LENGTH(signature)))));
   }
-  PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0));
+  PUSH_FIELD_VALUE (minit, "accflags", build_int_cst (NULL_TREE, accflags));
   PUSH_FIELD_VALUE (minit, "index", index);
   PUSH_FIELD_VALUE (minit, "ncode", code);
 
@@ -1150,7 +1351,7 @@ make_method_value (tree mdecl)
        TREE_STATIC (array) = 1;
        DECL_ARTIFICIAL (array) = 1;
        DECL_IGNORED_P (array) = 1;
-       rest_of_decl_compilation (array, (char*) 0, 1, 0);
+       rest_of_decl_compilation (array, 1, 0);
 
        table = build1 (ADDR_EXPR, ptr_type_node, array);
       }
@@ -1185,10 +1386,12 @@ get_dispatch_vector (tree type)
 
       for (method = TYPE_METHODS (type);  method != NULL_TREE;
           method = TREE_CHAIN (method))
-       if (DECL_VINDEX (method) != NULL_TREE
-           && host_integerp (DECL_VINDEX (method), 0))
-         TREE_VEC_ELT (vtable, tree_low_cst (DECL_VINDEX (method), 0))
-           = method;
+       {
+         tree method_index = get_method_index (method);
+         if (method_index != NULL_TREE
+             && host_integerp (method_index, 0))
+           TREE_VEC_ELT (vtable, tree_low_cst (method_index, 0)) = method;
+       }
     }
 
   return vtable;
@@ -1211,8 +1414,7 @@ get_dispatch_table (tree type, tree this_class_addr)
       if (METHOD_ABSTRACT (method))
        {
          if (! abstract_p)
-           warning ("%Habstract method in non-abstract class",
-                     &DECL_SOURCE_FILE (method));
+           warning ("%Jabstract method in non-abstract class", method);
 
          if (TARGET_VTABLE_USES_DESCRIPTORS)
            for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
@@ -1223,14 +1425,15 @@ get_dispatch_table (tree type, tree this_class_addr)
       else
        {
          if (!DECL_RTL_SET_P (method))
-           make_decl_rtl (method, NULL);
+           make_decl_rtl (method);
 
          if (TARGET_VTABLE_USES_DESCRIPTORS)
            for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
              {
-               tree fdesc = build (FDESC_EXPR, nativecode_ptr_type_node, 
-                                   method, build_int_2 (j, 0));
+               tree fdesc = build2 (FDESC_EXPR, nativecode_ptr_type_node, 
+                                    method, build_int_cst (NULL_TREE, j));
                TREE_CONSTANT (fdesc) = 1;
+               TREE_INVARIANT (fdesc) = 1;
                list = tree_cons (NULL_TREE, fdesc, list);
              }
          else
@@ -1268,6 +1471,42 @@ get_dispatch_table (tree type, tree this_class_addr)
                                                   arraysize), list);
 }
 
+
+/* Set the method_index for a method decl.  */
+void
+set_method_index (tree decl, tree method_index)
+{
+  method_index = fold (convert (sizetype, method_index));
+
+  if (TARGET_VTABLE_USES_DESCRIPTORS)
+    /* Add one to skip bogus descriptor for class and GC descriptor. */
+    method_index = size_binop (PLUS_EXPR, method_index, size_int (1));
+  else
+    /* Add 1 to skip "class" field of dtable, and 1 to skip GC descriptor.  */
+    method_index = size_binop (PLUS_EXPR, method_index, size_int (2));
+
+  DECL_VINDEX (decl) = method_index;
+}
+
+/* Get the method_index for a method decl.  */
+tree
+get_method_index (tree decl)
+{
+  tree method_index = DECL_VINDEX (decl);
+
+  if (! method_index)
+    return NULL;
+
+  if (TARGET_VTABLE_USES_DESCRIPTORS)
+    /* Sub one to skip bogus descriptor for class and GC descriptor. */
+    method_index = size_binop (MINUS_EXPR, method_index, size_int (1));
+  else
+    /* Sub 1 to skip "class" field of dtable, and 1 to skip GC descriptor.  */
+    method_index = size_binop (MINUS_EXPR, method_index, size_int (2));
+
+  return method_index;
+}
+
 static int
 supers_all_compiled (tree type)
 {
@@ -1305,14 +1544,17 @@ make_class_data (tree type)
   tree type_decl = TYPE_NAME (type);
   /** Offset from start of virtual function table declaration
       to where objects actually point at, following new g++ ABI. */
-  tree dtable_start_offset = build_int_2 (2 * POINTER_SIZE / BITS_PER_UNIT, 0);
+  tree dtable_start_offset = build_int_cst (NULL_TREE,
+                                           2 * POINTER_SIZE / BITS_PER_UNIT);
 
   this_class_addr = build_class_ref (type);
   decl = TREE_OPERAND (this_class_addr, 0);
 
   /* Build Field array. */
   field = TYPE_FIELDS (type);
-  if (DECL_NAME (field) == NULL_TREE)
+  while (field && DECL_ARTIFICIAL (field))
+    field = TREE_CHAIN (field);  /* Skip dummy fields.  */
+  if (field && DECL_NAME (field) == NULL_TREE)
     field = TREE_CHAIN (field);  /* Skip dummy field for inherited data. */
   for ( ;  field != NULL_TREE;  field = TREE_CHAIN (field))
     {
@@ -1329,7 +1571,7 @@ make_class_data (tree type)
              if (initial != NULL_TREE
                  && TREE_TYPE (initial) == string_ptr_type_node)
                DECL_INITIAL (field) = NULL_TREE;
-             rest_of_decl_compilation (field, (char*) 0, 1, 1);
+             rest_of_decl_compilation (field, 1, 1);
              DECL_INITIAL (field) = initial;
            }
          else
@@ -1353,7 +1595,7 @@ make_class_data (tree type)
       TREE_STATIC (fields_decl) = 1;
       DECL_ARTIFICIAL (fields_decl) = 1;
       DECL_IGNORED_P (fields_decl) = 1;
-      rest_of_decl_compilation (fields_decl, (char*) 0, 1, 0);
+      rest_of_decl_compilation (fields_decl, 1, 0);
     }
   else
     fields_decl = NULL_TREE;
@@ -1365,7 +1607,12 @@ make_class_data (tree type)
       tree init;
       if (METHOD_PRIVATE (method)
          && ! flag_keep_inline_functions
-         && (flag_inline_functions || optimize))
+         && optimize)
+       continue;
+      /* Even if we have a decl, we don't necessarily have the code.
+        This can happen if we inherit a method from a superclass for
+        which we don't have a .class file.  */
+      if (METHOD_DUMMY (method))
        continue;
       init = make_method_value (method);
       method_count++;
@@ -1379,7 +1626,7 @@ make_class_data (tree type)
   TREE_STATIC (methods_decl) = 1;
   DECL_ARTIFICIAL (methods_decl) = 1;
   DECL_IGNORED_P (methods_decl) = 1;
-  rest_of_decl_compilation (methods_decl, (char*) 0, 1, 0);
+  rest_of_decl_compilation (methods_decl, 1, 0);
 
   if (supers_all_compiled (type) && ! CLASS_INTERFACE (type_decl)
       && !flag_indirect_dispatch)
@@ -1391,7 +1638,7 @@ make_class_data (tree type)
       DECL_ARTIFICIAL (dtable_decl) = 1;
       DECL_IGNORED_P (dtable_decl) = 1;
       TREE_PUBLIC (dtable_decl) = 1;
-      rest_of_decl_compilation (dtable_decl, (char*) 0, 1, 0);
+      rest_of_decl_compilation (dtable_decl, 1, 0);
       if (type == class_type_node)
        class_dtable_decl = dtable_decl;
     }
@@ -1404,25 +1651,26 @@ make_class_data (tree type)
       DECL_IGNORED_P (class_dtable_decl) = 1;
       if (is_compiled_class (class_type_node) != 2)
        DECL_EXTERNAL (class_dtable_decl) = 1;
-      rest_of_decl_compilation (class_dtable_decl, (char*) 0, 1, 0);
+      rest_of_decl_compilation (class_dtable_decl, 1, 0);
     }
 
   super = CLASSTYPE_SUPER (type);
   if (super == NULL_TREE)
     super = null_pointer_node;
-  else if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
+  else if (! flag_indirect_dispatch
+          && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
           && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (super)))))
     super = build_class_ref (super);
   else
     {
       int super_index = alloc_class_constant (super);
-      super = build_int_2 (super_index, 0);
-      TREE_TYPE (super) = ptr_type_node;
+      super = build_int_cst (ptr_type_node, super_index);
     }
 
   /* Build and emit the array of implemented interfaces. */
   if (type != object_type_node)
-      interface_len = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)) - 1;
+    interface_len = BINFO_N_BASE_BINFOS (TYPE_BINFO (type)) - 1;
+  
   if (interface_len > 0)
     {
       tree init = NULL_TREE;
@@ -1432,18 +1680,20 @@ make_class_data (tree type)
        = build_prim_array_type (class_ptr_type, interface_len);
       idecl = build_decl (VAR_DECL, mangled_classname ("_IF_", type),
                          interface_array_type);
+      
       for (i = interface_len;  i > 0; i--)
        {
-         tree child = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i);
+         tree child = BINFO_BASE_BINFO (TYPE_BINFO (type), i);
          tree iclass = BINFO_TYPE (child);
          tree index;
-         if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (iclass)))))
+         if (! flag_indirect_dispatch
+             && (assume_compiled 
+                 (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (iclass))))))
            index = build_class_ref (iclass);
          else
            {
-               int int_index = alloc_class_constant (iclass);
-               index = build_int_2 (int_index, 0);
-               TREE_TYPE (index) = ptr_type_node;
+             int int_index = alloc_class_constant (iclass);
+             index = build_int_cst (ptr_type_node, int_index);
            }
          init = tree_cons (NULL_TREE, index, init); 
        }
@@ -1452,16 +1702,40 @@ make_class_data (tree type)
       DECL_ARTIFICIAL (idecl) = 1;
       DECL_IGNORED_P (idecl) = 1;
       interfaces = build1 (ADDR_EXPR, ptr_type_node, idecl);
-      rest_of_decl_compilation (idecl,  (char*) 0, 1, 0);
+      rest_of_decl_compilation (idecl, 1, 0);
     }
 
   constant_pool_constructor = build_constants_constructor ();
 
+  if (flag_indirect_dispatch)
+    {
+      TYPE_OTABLE_DECL (type) 
+       = emit_symbol_table 
+       (DECL_NAME (TYPE_OTABLE_DECL (type)), 
+        TYPE_OTABLE_DECL (type), TYPE_OTABLE_METHODS (type), 
+        TYPE_OTABLE_SYMS_DECL (type), integer_type_node, 1);
+       
+      TYPE_ATABLE_DECL (type) 
+       = emit_symbol_table 
+       (DECL_NAME (TYPE_ATABLE_DECL (type)), 
+        TYPE_ATABLE_DECL (type), TYPE_ATABLE_METHODS (type), 
+        TYPE_ATABLE_SYMS_DECL (type), ptr_type_node, 1);
+       
+      TYPE_ITABLE_DECL (type) 
+       = emit_symbol_table 
+       (DECL_NAME (TYPE_ITABLE_DECL (type)), 
+        TYPE_ITABLE_DECL (type), TYPE_ITABLE_METHODS (type), 
+        TYPE_ITABLE_SYMS_DECL (type), ptr_type_node, 2);
+    }
+  
+  TYPE_CTABLE_DECL (type) = emit_catch_table (type);
+
   START_RECORD_CONSTRUCTOR (temp, object_type_node);
   PUSH_FIELD_VALUE (temp, "vtable",
-                   build (PLUS_EXPR, dtable_ptr_type,
-                          build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl),
-                          dtable_start_offset));
+                   build2 (PLUS_EXPR, dtable_ptr_type,
+                           build1 (ADDR_EXPR, dtable_ptr_type,
+                                   class_dtable_decl),
+                           dtable_start_offset));
   if (! flag_hash_synchronization)
     PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node);
   FINISH_RECORD_CONSTRUCTOR (temp);
@@ -1470,38 +1744,46 @@ make_class_data (tree type)
   PUSH_FIELD_VALUE (cons, "next", null_pointer_node);
   PUSH_FIELD_VALUE (cons, "name", build_utf8_ref (DECL_NAME (type_decl)));
   PUSH_FIELD_VALUE (cons, "accflags",
-                   build_int_2 (get_access_flags_from_decl (type_decl), 0));
+                   build_int_cst (NULL_TREE,
+                                  get_access_flags_from_decl (type_decl)));
 
   PUSH_FIELD_VALUE (cons, "superclass", 
                    CLASS_INTERFACE (type_decl) ? null_pointer_node : super);
   PUSH_FIELD_VALUE (cons, "constants", constant_pool_constructor);
   PUSH_FIELD_VALUE (cons, "methods",
                    build1 (ADDR_EXPR, method_ptr_type_node, methods_decl));
-  PUSH_FIELD_VALUE (cons, "method_count",  build_int_2 (method_count, 0));
+  PUSH_FIELD_VALUE (cons, "method_count",
+                   build_int_cst (NULL_TREE, method_count));
 
   if (flag_indirect_dispatch)
-    PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node)
+    PUSH_FIELD_VALUE (cons, "vtable_method_count", integer_minus_one_node);
   else
     PUSH_FIELD_VALUE (cons, "vtable_method_count", TYPE_NVIRTUALS (type));
     
   PUSH_FIELD_VALUE (cons, "fields",
                    fields_decl == NULL_TREE ? null_pointer_node
                    : build1 (ADDR_EXPR, field_ptr_type_node, fields_decl));
-  PUSH_FIELD_VALUE (cons, "size_in_bytes", size_in_bytes (type));
-  PUSH_FIELD_VALUE (cons, "field_count", build_int_2 (field_count, 0));
+  /* If we're using the binary compatibility ABI we don't know the
+     size until load time.  */
+  PUSH_FIELD_VALUE (cons, "size_in_bytes", 
+                   (flag_indirect_dispatch 
+                    ? integer_minus_one_node 
+                    : size_in_bytes (type)));
+  PUSH_FIELD_VALUE (cons, "field_count", 
+                   build_int_cst (NULL_TREE, field_count));
   PUSH_FIELD_VALUE (cons, "static_field_count",
-                   build_int_2 (static_field_count, 0));
+                   build_int_cst (NULL_TREE, static_field_count));
 
   if (flag_indirect_dispatch)
-    PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node)
+    PUSH_FIELD_VALUE (cons, "vtable", null_pointer_node);
   else
     PUSH_FIELD_VALUE (cons, "vtable",
                      dtable_decl == NULL_TREE ? null_pointer_node
-                     : build (PLUS_EXPR, dtable_ptr_type,
-                              build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl),
-                              dtable_start_offset));
-  
-  if (otable_methods == NULL_TREE)
+                     : build2 (PLUS_EXPR, dtable_ptr_type,
+                               build1 (ADDR_EXPR, dtable_ptr_type,
+                                       dtable_decl),
+                               dtable_start_offset));
+  if (TYPE_OTABLE_METHODS (type) == NULL_TREE)
     {
       PUSH_FIELD_VALUE (cons, "otable", null_pointer_node);
       PUSH_FIELD_VALUE (cons, "otable_syms", null_pointer_node);
@@ -1509,15 +1791,57 @@ make_class_data (tree type)
   else
     {
       PUSH_FIELD_VALUE (cons, "otable",
-                       build1 (ADDR_EXPR, otable_ptr_type, otable_decl));
+                       build1 (ADDR_EXPR, otable_ptr_type, TYPE_OTABLE_DECL (type)));
       PUSH_FIELD_VALUE (cons, "otable_syms",
-                       build1 (ADDR_EXPR, method_symbols_array_ptr_type,
-                               otable_syms_decl));
+                       build1 (ADDR_EXPR, symbols_array_ptr_type,
+                               TYPE_OTABLE_SYMS_DECL (type)));
+      TREE_CONSTANT (TYPE_OTABLE_DECL (type)) = 1;
+      TREE_INVARIANT (TYPE_OTABLE_DECL (type)) = 1;
+    }
+  if (TYPE_ATABLE_METHODS(type) == NULL_TREE)
+    {
+      PUSH_FIELD_VALUE (cons, "atable", null_pointer_node);
+      PUSH_FIELD_VALUE (cons, "atable_syms", null_pointer_node);
+    }
+  else
+    {
+      PUSH_FIELD_VALUE (cons, "atable",
+                       build1 (ADDR_EXPR, atable_ptr_type, TYPE_ATABLE_DECL (type)));
+      PUSH_FIELD_VALUE (cons, "atable_syms",
+                       build1 (ADDR_EXPR, symbols_array_ptr_type,
+                               TYPE_ATABLE_SYMS_DECL (type)));
+      TREE_CONSTANT (TYPE_ATABLE_DECL (type)) = 1;
+      TREE_INVARIANT (TYPE_ATABLE_DECL (type)) = 1;
     }
+   if (TYPE_ITABLE_METHODS(type) == NULL_TREE)
+    {
+      PUSH_FIELD_VALUE (cons, "itable", null_pointer_node);
+      PUSH_FIELD_VALUE (cons, "itable_syms", null_pointer_node);
+    }
+  else
+    {
+      PUSH_FIELD_VALUE (cons, "itable",
+                       build1 (ADDR_EXPR, itable_ptr_type, TYPE_ITABLE_DECL (type)));
+      PUSH_FIELD_VALUE (cons, "itable_syms",
+                       build1 (ADDR_EXPR, symbols_array_ptr_type,
+                               TYPE_ITABLE_SYMS_DECL (type)));
+      TREE_CONSTANT (TYPE_ITABLE_DECL (type)) = 1;
+      TREE_INVARIANT (TYPE_ITABLE_DECL (type)) = 1;
+    }
+  PUSH_FIELD_VALUE (cons, "catch_classes",
+                   build1 (ADDR_EXPR, ptr_type_node, TYPE_CTABLE_DECL (type))); 
   PUSH_FIELD_VALUE (cons, "interfaces", interfaces);
   PUSH_FIELD_VALUE (cons, "loader", null_pointer_node);
-  PUSH_FIELD_VALUE (cons, "interface_count", build_int_2 (interface_len, 0));
-  PUSH_FIELD_VALUE (cons, "state", integer_zero_node);
+  PUSH_FIELD_VALUE (cons, "interface_count",
+                   build_int_cst (NULL_TREE, interface_len));
+  PUSH_FIELD_VALUE 
+    (cons, "state",
+     convert (byte_type_node,
+             build_int_cst (NULL_TREE,
+                            flag_indirect_dispatch
+                            ? JV_STATE_PRELOADING
+                            : JV_STATE_COMPILED)));
 
   PUSH_FIELD_VALUE (cons, "thread", null_pointer_node);
   PUSH_FIELD_VALUE (cons, "depth", integer_zero_node);
@@ -1525,7 +1849,23 @@ make_class_data (tree type)
   PUSH_FIELD_VALUE (cons, "idt", null_pointer_node);
   PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node);
   PUSH_FIELD_VALUE (cons, "protectionDomain", null_pointer_node);
+
+  {
+    tree assertion_table_ref;
+    if (TYPE_ASSERTIONS (type) == NULL)
+      assertion_table_ref = null_pointer_node;
+    else
+      assertion_table_ref = build1 (ADDR_EXPR, 
+                                   build_pointer_type (assertion_table_type),
+                                   emit_assertion_table (type));
+    
+    PUSH_FIELD_VALUE (cons, "assertion_table", assertion_table_ref);
+  }
+
+  PUSH_FIELD_VALUE (cons, "hack_signers", null_pointer_node);
   PUSH_FIELD_VALUE (cons, "chain", null_pointer_node);
+  PUSH_FIELD_VALUE (cons, "aux_info", null_pointer_node);
+  PUSH_FIELD_VALUE (cons, "engine", null_pointer_node);
 
   FINISH_RECORD_CONSTRUCTOR (cons);
 
@@ -1535,47 +1875,33 @@ make_class_data (tree type)
   if (flag_hash_synchronization && POINTER_SIZE < 64)
     DECL_ALIGN (decl) = 64; 
   
-  rest_of_decl_compilation (decl, (char*) 0, 1, 0);
+  rest_of_decl_compilation (decl, 1, 0);
+  
+  TYPE_OTABLE_DECL (type) = NULL_TREE;
+  TYPE_ATABLE_DECL (type) = NULL_TREE;
+  TYPE_CTABLE_DECL (type) = NULL_TREE;
 }
 
 void
 finish_class (void)
 {
-  tree method;
-  tree type_methods = TYPE_METHODS (current_class);
-  int saw_native_method = 0;
-
-  /* Find out if we have any native methods.  We use this information
-     later.  */
-  for (method = type_methods;
-       method != NULL_TREE;
-       method = TREE_CHAIN (method))
+  if (TYPE_VERIFY_METHOD (output_class))
     {
-      if (METHOD_NATIVE (method))
-       {
-         saw_native_method = 1;
-         break;
-       }
+      tree verify_method = TYPE_VERIFY_METHOD (output_class);
+      DECL_SAVED_TREE (verify_method) 
+       = add_stmt_to_compound (DECL_SAVED_TREE (verify_method), void_type_node,
+                               build (RETURN_EXPR, void_type_node, NULL));
+      java_genericize (verify_method);
+      cgraph_finalize_function (verify_method, false);
+      TYPE_ASSERTIONS (current_class) = NULL;
     }
 
-  /* Emit deferred inline methods. */  
-  for (method = type_methods; method != NULL_TREE; )
-    {
-      if (! TREE_ASM_WRITTEN (method) && DECL_SAVED_INSNS (method) != 0)
-       {
-         output_inline_function (method);
-         /* Scan the list again to see if there are any earlier
-            methods to emit. */
-         method = type_methods;
-         continue;
-       }
-      method = TREE_CHAIN (method);
-    }
+  java_expand_catch_classes (current_class);
 
   current_function_decl = NULL_TREE;
   make_class_data (current_class);
   register_class ();
-  rest_of_decl_compilation (TYPE_NAME (current_class), (char*) 0, 1, 0);
+  rest_of_decl_compilation (TYPE_NAME (current_class), 1, 0);
 }
 
 /* Return 2 if CLASS is compiled by this compilation job;
@@ -1728,9 +2054,14 @@ maybe_layout_super_class (tree super_class, tree this_class)
          if (this_class)
            {
              tree this_decl = TYPE_NAME (this_class);
+#ifdef USE_MAPPED_LOCATION
+             this_wrap = build_expr_wfl (this_class,
+                                         DECL_SOURCE_LOCATION (this_decl));
+#else
              this_wrap = build_expr_wfl (this_class,
                                          DECL_SOURCE_FILE (this_decl),
                                          DECL_SOURCE_LINE (this_decl), 0);
+#endif
            }
          super_class = do_resolve_class (NULL_TREE, /* FIXME? */
                                          super_class, NULL_TREE, this_wrap);
@@ -1758,7 +2089,7 @@ layout_class (tree this_class)
       char *report;
       tree current;
 
-      sprintf (buffer, " with `%s'",
+      sprintf (buffer, " with '%s'",
               IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))));
       obstack_grow (&temporary_obstack, buffer, strlen (buffer));
 
@@ -1766,7 +2097,7 @@ layout_class (tree this_class)
           current = TREE_CHAIN (current))
        {
          tree decl = TYPE_NAME (TREE_PURPOSE (current));
-         sprintf (buffer, "\n  which inherits from `%s' (%s:%d)",
+         sprintf (buffer, "\n  which inherits from '%s' (%s:%d)",
                   IDENTIFIER_POINTER (DECL_NAME (decl)),
                   DECL_SOURCE_FILE (decl),
                   DECL_SOURCE_LINE (decl));
@@ -1816,17 +2147,13 @@ layout_class (tree this_class)
      of this itself.  */
   if (!CLASS_FROM_SOURCE_P (this_class))
     {
-      tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
-
-      if (basetype_vec)
+      int i;
+            if (TYPE_BINFO (this_class))
        {
-         int n = TREE_VEC_LENGTH (basetype_vec) - 1;
-         int i;
-         for (i = n; i > 0; i--)
+         for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (this_class)) - 1; i > 0; i--)
            {
-             tree vec_elt = TREE_VEC_ELT (basetype_vec, i);
-             tree super_interface = BINFO_TYPE (vec_elt);
-
+             tree binfo = BINFO_BASE_BINFO (TYPE_BINFO (this_class), i);
+             tree super_interface = BINFO_TYPE (binfo);
              tree maybe_super_interface 
                = maybe_layout_super_class (super_interface, NULL_TREE);
              if (maybe_super_interface == NULL
@@ -1852,17 +2179,26 @@ layout_class (tree this_class)
 static void
 add_miranda_methods (tree base_class, tree search_class)
 {
-  tree basetype_vec = TYPE_BINFO_BASETYPES (search_class);
-  int i, n = TREE_VEC_LENGTH (basetype_vec);
-  for (i = 1; i < n; ++i)
+  int i;
+  tree binfo, base_binfo;
+
+  if (!CLASS_PARSED_P (search_class))
+    load_class (search_class, 1);
+  
+  for (binfo = TYPE_BINFO (search_class), i = 1;
+       BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
     {
       tree method_decl;
-      tree elt = TREE_VEC_ELT (basetype_vec, i);
-      if (elt == NULL_TREE)
-       break;
-      elt = BINFO_TYPE (elt);
+      tree elt = BINFO_TYPE (base_binfo);
+
+      /* FIXME: This is totally bogus.  We should not be handling
+        Miranda methods at all if we're using the BC ABI.  */
+      if (TYPE_DUMMY (elt))
+       continue;
 
       /* Ensure that interface methods are seen in declared order.  */
+      if (!CLASS_LOADED_P (elt))
+       load_class (elt, 1);
       layout_class_methods (elt);
 
       /* All base classes will have been laid out at this point, so the order 
@@ -1902,7 +2238,7 @@ void
 layout_class_methods (tree this_class)
 {
   tree method_decl, dtable_count;
-  tree super_class;
+  tree super_class, type_name;
 
   if (TYPE_NVIRTUALS (this_class))
     return;
@@ -1919,7 +2255,9 @@ layout_class_methods (tree this_class)
   else
     dtable_count = integer_zero_node;
 
-  if (CLASS_ABSTRACT (TYPE_NAME (this_class)))
+  type_name = TYPE_NAME (this_class);
+  if (!flag_indirect_dispatch
+      && (CLASS_ABSTRACT (type_name) || CLASS_INTERFACE (type_name)))
     {
       /* An abstract class can have methods which are declared only in
         an implemented interface.  These are called "Miranda
@@ -1938,6 +2276,23 @@ layout_class_methods (tree this_class)
   TYPE_NVIRTUALS (this_class) = dtable_count;
 }
 
+/* Return the index of METHOD in INTERFACE.  This index begins at 1 and is used as an
+   argument for _Jv_LookupInterfaceMethodIdx(). */
+int
+get_interface_method_index (tree method, tree interface)
+{
+  tree meth;
+  int i = 1;
+
+  for (meth = TYPE_METHODS (interface); ; meth = TREE_CHAIN (meth), i++)
+    {
+      if (meth == method)
+       return i;
+      if (meth == NULL_TREE)
+       abort ();
+    }
+}
+
 /* Lay METHOD_DECL out, returning a possibly new value of
    DTABLE_COUNT. Also mangle the method's name. */
 
@@ -1961,7 +2316,7 @@ layout_class_method (tree this_class, tree super_class,
   if (! METHOD_ABSTRACT (method_decl) 
       || (CLASS_INTERFACE (TYPE_NAME (this_class)) 
          && (DECL_CLINIT_P (method_decl))))
-    make_decl_rtl (method_decl, NULL);
+    make_decl_rtl (method_decl);
 
   if (ID_INIT_P (method_name))
     {
@@ -1975,28 +2330,54 @@ layout_class_method (tree this_class, tree super_class,
       DECL_CONSTRUCTOR_P (method_decl) = 1;
       build_java_argument_signature (TREE_TYPE (method_decl));
     }
-  else if (! METHOD_STATIC (method_decl) && !DECL_ARTIFICIAL (method_decl))
+  else if (! METHOD_STATIC (method_decl))
     {
       tree method_sig =
        build_java_argument_signature (TREE_TYPE (method_decl));
+      bool method_override = false;
       tree super_method = lookup_argument_method (super_class, method_name,
                                                  method_sig);
-      if (super_method != NULL_TREE && ! METHOD_PRIVATE (super_method))
+      if (super_method != NULL_TREE
+         && ! METHOD_DUMMY (super_method))
+        {
+         method_override = true;
+         if (! METHOD_PUBLIC (super_method) && 
+             ! METHOD_PROTECTED (super_method))
+           {
+             /* Don't override private method, or default-access method in 
+                another package.  */
+             if (METHOD_PRIVATE (super_method) ||
+                 ! in_same_package (TYPE_NAME (this_class), 
+                                    TYPE_NAME (super_class)))
+               method_override = false;
+          }
+       }
+      if (method_override)
+       {
+         tree method_index = get_method_index (super_method);
+         set_method_index (method_decl, method_index);
+         if (method_index == NULL_TREE 
+             && !CLASS_FROM_SOURCE_P (this_class)
+             && ! DECL_ARTIFICIAL (super_method))
+           error ("%Jnon-static method '%D' overrides static method",
+                   method_decl, method_decl);
+       }
+      else if (this_class == object_type_node
+              && (METHOD_FINAL (method_decl)
+                  || METHOD_PRIVATE (method_decl)))
        {
-         DECL_VINDEX (method_decl) = DECL_VINDEX (super_method);
-         if (DECL_VINDEX (method_decl) == NULL_TREE 
-             && !CLASS_FROM_SOURCE_P (this_class))
-           error ("%Hnon-static method '%D' overrides static method",
-                   &DECL_SOURCE_LOCATION (method_decl), method_decl);
+         /* We don't generate vtable entries for final Object
+            methods.  This is simply to save space, since every
+            object would otherwise have to define them.  */
        }
-      else if (! METHOD_FINAL (method_decl)
-              && ! METHOD_PRIVATE (method_decl)
-              && ! CLASS_FINAL (TYPE_NAME (this_class))
+      else if (! METHOD_PRIVATE (method_decl)
               && dtable_count)
        {
-         DECL_VINDEX (method_decl) = dtable_count;
-         dtable_count = fold (build (PLUS_EXPR, integer_type_node,
-                                     dtable_count, integer_one_node));
+         /* We generate vtable entries for final methods because they
+            may one day be changed to non-final.  */
+         set_method_index (method_decl, dtable_count);
+         dtable_count = fold (build2 (PLUS_EXPR, integer_type_node,
+                                      dtable_count, integer_one_node));
        }
     }
 
@@ -2025,14 +2406,19 @@ register_class (void)
 /* Emit something to register classes at start-up time.
 
    The preferred mechanism is through the .jcr section, which contain
-   a list of pointers to classes which get registered during
-   constructor invocation time.  The fallback mechanism is to generate
-   a `constructor' function which calls _Jv_RegisterClass for each
-   class in this file.  */
+   a list of pointers to classes which get registered during constructor
+   invocation time.
+
+   The fallback mechanism is to add statements to *LIST_P to call
+   _Jv_RegisterClass for each class in this file.  These statements will
+   be added to a static constructor function for this translation unit.  */
 
 void
-emit_register_classes (void)
+emit_register_classes (tree *list_p)
 {
+  if (registered_class == NULL)
+    return;
+
   /* ??? This isn't quite the correct test.  We also have to know
      that the target is using gcc's crtbegin/crtend objects rather
      than the ones that come with the operating system.  */
@@ -2051,140 +2437,259 @@ emit_register_classes (void)
     }
   else
     {
-      extern tree get_file_function_name (int);
-      tree init_name = get_file_function_name ('I');
-      tree init_type = build_function_type (void_type_node, end_params_node);
-      tree init_decl;
-      tree t;
-      location_t saved_loc = input_location;
-      
-      init_decl = build_decl (FUNCTION_DECL, init_name, init_type);
-      SET_DECL_ASSEMBLER_NAME (init_decl, init_name);
-      DECL_SOURCE_LINE (init_decl) = 0;
-      TREE_STATIC (init_decl) = 1;
-      current_function_decl = init_decl;
-      DECL_RESULT (init_decl) = build_decl (RESULT_DECL, NULL_TREE,
-                                           void_type_node);
-
-      /* It can be a static function as long as collect2 does not have
-         to scan the object file to find its ctor/dtor routine.  */
-      TREE_PUBLIC (init_decl) = ! targetm.have_ctors_dtors;
-
-      /* Suppress spurious warnings.  */
-      TREE_USED (init_decl) = 1;
-
-      pushlevel (0);
-      make_decl_rtl (init_decl, NULL);
-      init_function_start (init_decl);
-      expand_function_start (init_decl, 0);
-
-      /* Do not allow the function to be deferred.  */
-      current_function_cannot_inline
-       = "static constructors and destructors cannot be inlined";
-
-      for ( t = registered_class; t; t = TREE_CHAIN (t))
-       emit_library_call (registerClass_libfunc, 0, VOIDmode, 1,
-                          XEXP (DECL_RTL (t), 0), Pmode);
-      input_location = DECL_SOURCE_LOCATION (init_decl);
-      expand_function_end ();
-      poplevel (1, 0, 1);
-      rest_of_compilation (init_decl);
-      current_function_decl = NULL_TREE;
-
-      if (targetm.have_ctors_dtors)
-       (* targetm.asm_out.constructor) (XEXP (DECL_RTL (init_decl), 0),
-                                        DEFAULT_INIT_PRIORITY);
-      input_location = saved_loc;
+      tree klass, t, register_class_fn;
+
+      t = build_function_type_list (void_type_node, class_ptr_type, NULL);
+      t = build_decl (FUNCTION_DECL, get_identifier ("_Jv_RegisterClass"), t);
+      TREE_PUBLIC (t) = 1;
+      DECL_EXTERNAL (t) = 1;
+      register_class_fn = t;
+
+      for (klass = registered_class; klass; klass = TREE_CHAIN (klass))
+       {
+         t = build_fold_addr_expr (klass);
+         t = tree_cons (NULL, t, NULL);
+         t = build_function_call_expr (register_class_fn, t);
+         append_to_statement_list (t, list_p);
+       }
     }
 }
 
-/* Make a method_symbol_type (_Jv_MethodSymbol) node for METHOD. */
+/* Make a symbol_type (_Jv_MethodSymbol) node for DECL. */
 
 static tree
-build_method_symbols_entry (tree method)
+build_symbol_entry (tree decl)
 {
-  tree clname, name, signature, method_symbol;
-  
-  clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (method))));
-  name = build_utf8_ref (DECL_NAME (method));
-  signature = build_java_signature (TREE_TYPE (method));
+  tree clname, name, signature, sym;
+  clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))));
+  /* ???  Constructors are given the name foo.foo all the way through
+     the compiler, but in the method table they're all renamed
+     foo.<init>.  So, we have to do the same here unless we want an
+     unresolved reference at runtime.  */
+  name = build_utf8_ref ((TREE_CODE (decl) == FUNCTION_DECL 
+                         && DECL_CONSTRUCTOR_P (decl))
+                        ? init_identifier_node
+                        : DECL_NAME (decl));
+  signature = build_java_signature (TREE_TYPE (decl));
   signature = build_utf8_ref (unmangle_classname 
                              (IDENTIFIER_POINTER (signature),
                               IDENTIFIER_LENGTH (signature)));
-
-  START_RECORD_CONSTRUCTOR (method_symbol, method_symbol_type);
-  PUSH_FIELD_VALUE (method_symbol, "clname", clname);
-  PUSH_FIELD_VALUE (method_symbol, "name", name);
-  PUSH_FIELD_VALUE (method_symbol, "signature", signature);
-  FINISH_RECORD_CONSTRUCTOR (method_symbol);
-  TREE_CONSTANT (method_symbol) = 1;
-
-  return method_symbol;
+      
+  START_RECORD_CONSTRUCTOR (sym, symbol_type);
+  PUSH_FIELD_VALUE (sym, "clname", clname);
+  PUSH_FIELD_VALUE (sym, "name", name);
+  PUSH_FIELD_VALUE (sym, "signature", signature);
+  FINISH_RECORD_CONSTRUCTOR (sym);
+  TREE_CONSTANT (sym) = 1;
+  TREE_INVARIANT (sym) = 1;
+
+  return sym;
 } 
 
-/* Emit the offset symbols table for indirect virtual dispatch. */
+/* Emit a symbol table: used by -findirect-dispatch.  */
 
-void
-emit_offset_symbol_table (void)
+tree
+emit_symbol_table (tree name, tree the_table, tree decl_list,
+                   tree the_syms_decl, tree the_array_element_type,
+                  int element_size)
 {
   tree method_list, method, table, list, null_symbol;
-  tree otable_bound, otable_array_type;
+  tree table_size, the_array_type;
   int index;
   
-  /* Only emit an offset table if this translation unit actually made virtual 
-     calls. */
-  if (otable_methods == NULL_TREE)
-    return;
+  /* Only emit a table if this translation unit actually made any
+     references via it. */
+  if (decl_list == NULL_TREE)
+    return the_table;
 
   /* Build a list of _Jv_MethodSymbols for each entry in otable_methods. */
   index = 0;
-  method_list = otable_methods;
+  method_list = decl_list;
   list = NULL_TREE;  
   while (method_list != NULL_TREE)
     {
       method = TREE_VALUE (method_list);
-      list = tree_cons (NULL_TREE, build_method_symbols_entry (method), list);
+      list = tree_cons (NULL_TREE, build_symbol_entry (method), list);
       method_list = TREE_CHAIN (method_list);
       index++;
     }
 
   /* Terminate the list with a "null" entry. */
-  START_RECORD_CONSTRUCTOR (null_symbol, method_symbol_type);
+  START_RECORD_CONSTRUCTOR (null_symbol, symbol_type);
   PUSH_FIELD_VALUE (null_symbol, "clname", null_pointer_node);
   PUSH_FIELD_VALUE (null_symbol, "name", null_pointer_node);
   PUSH_FIELD_VALUE (null_symbol, "signature", null_pointer_node);
   FINISH_RECORD_CONSTRUCTOR (null_symbol);
   TREE_CONSTANT (null_symbol) = 1;  
+  TREE_INVARIANT (null_symbol) = 1;  
   list = tree_cons (NULL_TREE, null_symbol, list);
 
   /* Put the list in the right order and make it a constructor. */
   list = nreverse (list);
-  table = build_constructor (method_symbols_array_type, list);  
+  table = build_constructor (symbols_array_type, list);  
 
   /* Make it the initial value for otable_syms and emit the decl. */
-  DECL_INITIAL (otable_syms_decl) = table;
-  DECL_ARTIFICIAL (otable_syms_decl) = 1;
-  DECL_IGNORED_P (otable_syms_decl) = 1;
-  rest_of_decl_compilation (otable_syms_decl, NULL, 1, 0);
+  DECL_INITIAL (the_syms_decl) = table;
+  DECL_ARTIFICIAL (the_syms_decl) = 1;
+  DECL_IGNORED_P (the_syms_decl) = 1;
+  rest_of_decl_compilation (the_syms_decl, 1, 0);
+  
+  /* Now that its size is known, redefine the table as an
+     uninitialized static array of INDEX + 1 elements. The extra entry
+     is used by the runtime to track whether the table has been
+     initialized. */
+  table_size 
+    = build_index_type (build_int_cst (NULL_TREE, index * element_size + 1));
+  the_array_type = build_array_type (the_array_element_type, table_size);
+  the_table = build_decl (VAR_DECL, name, the_array_type);
+  TREE_STATIC (the_table) = 1;
+  TREE_READONLY (the_table) = 1;  
+  rest_of_decl_compilation (the_table, 1, 0);
+
+  return the_table;
+}
+
+/* Make an entry for the catch_classes list.  */
+tree
+make_catch_class_record (tree catch_class, tree classname)
+{
+  tree entry;
+  tree type = TREE_TYPE (TREE_TYPE (TYPE_CTABLE_DECL (output_class)));
+  START_RECORD_CONSTRUCTOR (entry, type);
+  PUSH_FIELD_VALUE (entry, "address", catch_class);
+  PUSH_FIELD_VALUE (entry, "classname", classname);
+  FINISH_RECORD_CONSTRUCTOR (entry);
+  return entry;
+}
+
+
+/* Generate the list of Throwable classes that are caught by exception
+   handlers in this class.  */
+tree 
+emit_catch_table (tree this_class)
+{
+  tree table, table_size, array_type;
+  TYPE_CATCH_CLASSES (this_class) =
+    tree_cons (NULL,
+              make_catch_class_record (null_pointer_node, null_pointer_node),
+              TYPE_CATCH_CLASSES (this_class));
+  TYPE_CATCH_CLASSES (this_class) = nreverse (TYPE_CATCH_CLASSES (this_class));
+  TYPE_CATCH_CLASSES (this_class) = 
+    tree_cons (NULL,
+              make_catch_class_record (null_pointer_node, null_pointer_node),
+              TYPE_CATCH_CLASSES (this_class));
+  table_size = build_index_type
+    (build_int_cst (NULL_TREE,
+                   list_length (TYPE_CATCH_CLASSES (this_class))));
+  array_type 
+    = build_array_type (TREE_TYPE (TREE_TYPE (TYPE_CTABLE_DECL (this_class))),
+                       table_size);
+  table = 
+    build_decl (VAR_DECL, DECL_NAME (TYPE_CTABLE_DECL (this_class)), array_type);
+  DECL_INITIAL (table) = 
+    build_constructor (array_type, TYPE_CATCH_CLASSES (this_class));
+  TREE_STATIC (table) = 1;
+  TREE_READONLY (table) = 1;  
+  DECL_IGNORED_P (table) = 1;
+  rest_of_decl_compilation (table, 1, 0);
+  return table;
+}
+
+/* Given a type, return the signature used by
+   _Jv_FindClassFromSignature() in libgcj.  This isn't exactly the
+   same as build_java_signature() because we want the canonical array
+   type.  */
+
+static tree
+build_signature_for_libgcj (tree type)
+{
+  tree sig, ref;
+
+  sig = build_java_signature (type);
+  ref = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (sig),
+                                           IDENTIFIER_LENGTH (sig)));
+  return ref;
+}
+
+/* Add an entry to the type assertion table. Callback used during hashtable
+   traversal.  */
+
+static int
+add_assertion_table_entry (void **htab_entry, void *ptr)
+{
+  tree entry;
+  tree code_val, op1_utf8, op2_utf8;
+  tree *list = (tree *) ptr;
+  type_assertion *as = (type_assertion *) *htab_entry;
+
+  code_val = build_int_cst (NULL_TREE, as->assertion_code);
+
+  if (as->op1 == NULL_TREE)
+    op1_utf8 = null_pointer_node;
+  else
+    op1_utf8 = build_signature_for_libgcj (as->op1);
+
+  if (as->op2 == NULL_TREE)
+    op2_utf8 = null_pointer_node;
+  else
+    op2_utf8 = build_signature_for_libgcj (as->op2);
+  
+  START_RECORD_CONSTRUCTOR (entry, assertion_entry_type);
+  PUSH_FIELD_VALUE (entry, "assertion_code", code_val);
+  PUSH_FIELD_VALUE (entry, "op1", op1_utf8);
+  PUSH_FIELD_VALUE (entry, "op2", op2_utf8);
+  FINISH_RECORD_CONSTRUCTOR (entry);
+  
+  *list = tree_cons (NULL_TREE, entry, *list);
+  return true;
+}
+
+/* Generate the type assertion table for CLASS, and return its DECL.  */
+
+static tree
+emit_assertion_table (tree class)
+{
+  tree null_entry, ctor, table_decl;
+  tree list = NULL_TREE;
+  htab_t assertions_htab = TYPE_ASSERTIONS (class);
+
+  /* Iterate through the hash table.  */
+  htab_traverse (assertions_htab, add_assertion_table_entry, &list);
+
+  /* Finish with a null entry.  */
+  START_RECORD_CONSTRUCTOR (null_entry, assertion_entry_type);
+  PUSH_FIELD_VALUE (null_entry, "assertion_code", integer_zero_node);
+  PUSH_FIELD_VALUE (null_entry, "op1", null_pointer_node);
+  PUSH_FIELD_VALUE (null_entry, "op2", null_pointer_node);
+  FINISH_RECORD_CONSTRUCTOR (null_entry);
+  
+  list = tree_cons (NULL_TREE, null_entry, list);
   
-  /* Now that its size is known, redefine otable as an uninitialized static 
-     array of INDEX + 1 integers. The extra entry is used by the runtime 
-     to track whether the otable has been initialized. */
-  otable_bound = build_index_type (build_int_2 (index, 0));
-  otable_array_type = build_array_type (integer_type_node, otable_bound);
-  otable_decl = build_decl (VAR_DECL, get_identifier ("otable"), 
-                           otable_array_type);
-  TREE_STATIC (otable_decl) = 1;
-  TREE_READONLY (otable_decl) = 1;  
-  rest_of_decl_compilation (otable_decl, NULL, 1, 0);
+  /* Put the list in the right order and make it a constructor. */
+  list = nreverse (list);
+  ctor = build_constructor (assertion_table_type, list);
+
+  table_decl = build_decl (VAR_DECL, mangled_classname ("_type_assert_", class),
+                          assertion_table_type);
+
+  TREE_STATIC (table_decl) = 1;
+  TREE_READONLY (table_decl) = 1;
+  TREE_CONSTANT (table_decl) = 1;
+  DECL_IGNORED_P (table_decl) = 1;
+
+  DECL_INITIAL (table_decl) = ctor;
+  DECL_ARTIFICIAL (table_decl) = 1;
+  rest_of_decl_compilation (table_decl, 1, 0);
+
+  return table_decl;
 }
 
 void
 init_class_processing (void)
 {
-  registerClass_libfunc = gen_rtx_SYMBOL_REF (Pmode, "_Jv_RegisterClass");
   fields_ident = get_identifier ("fields");
   info_ident = get_identifier ("info");
+
   gcc_obstack_init (&temporary_obstack);
 }
 \f
@@ -2252,4 +2757,63 @@ java_treetreehash_create (size_t size, int gc)
                              java_treetreehash_compare, free, xcalloc, free);
 }
 
+/* Break down qualified IDENTIFIER into package and class-name components.
+   For example, given SOURCE "pkg.foo.Bar", LEFT will be set to
+   "pkg.foo", and RIGHT to "Bar". */
+
+int
+split_qualified_name (tree *left, tree *right, tree source)
+{
+  char *p, *base;
+  int l = IDENTIFIER_LENGTH (source);
+
+  base = alloca (l + 1);
+  memcpy (base, IDENTIFIER_POINTER (source), l + 1);
+
+  /* Breakdown NAME into REMAINDER . IDENTIFIER.  */
+  p = base + l - 1;
+  while (*p != '.' && p != base)
+    p--;
+
+  /* We didn't find a '.'. Return an error.  */
+  if (p == base)
+    return 1;
+
+  *p = '\0';
+  if (right)
+    *right = get_identifier (p+1);
+  *left = get_identifier (base);
+
+  return 0;
+}
+
+/* Given two classes (TYPE_DECL) or class names (IDENTIFIER), return TRUE 
+   if the classes are from the same package. */
+
+int
+in_same_package (tree name1, tree name2)
+{
+  tree tmp;
+  tree pkg1;
+  tree pkg2;
+
+  if (TREE_CODE (name1) == TYPE_DECL)
+    name1 = DECL_NAME (name1);
+  if (TREE_CODE (name2) == TYPE_DECL)
+    name2 = DECL_NAME (name2);
+
+  if (QUALIFIED_P (name1) != QUALIFIED_P (name2))
+    /* One in empty package. */
+    return 0;
+
+  if (QUALIFIED_P (name1) == 0 && QUALIFIED_P (name2) == 0)
+    /* Both in empty package. */
+    return 1;
+
+  split_qualified_name (&pkg1, &tmp, name1);
+  split_qualified_name (&pkg2, &tmp, name2);
+
+  return (pkg1 == pkg2);
+}
+
 #include "gt-java-class.h"