OSDN Git Service

PR java/12915:
[pf3gnuchains/gcc-fork.git] / gcc / java / class.c
index 45bb6df..2aacbd4 100644 (file)
@@ -1,21 +1,21 @@
 /* Functions related to building classes and their related objects.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.
 
@@ -27,6 +27,8 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "flags.h"
@@ -36,23 +38,31 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "toplev.h"
 #include "output.h"
 #include "parse.h"
+#include "function.h"
 #include "ggc.h"
+#include "stdio.h"
+#include "target.h"
+
+/* DOS brain-damage */
+#ifndef O_BINARY
+#define O_BINARY 0 /* MS-DOS brain-damage */
+#endif
+
+static tree make_method_value (tree);
+static tree build_java_method_type (tree, tree, int);
+static int32 hashUtf8String (const char *, int);
+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_symbol_entry (tree);
+
+static GTY(()) rtx registerClass_libfunc;
 
-static tree make_method_value PARAMS ((tree));
-static tree build_java_method_type PARAMS ((tree, tree, int));
-static int32 hashUtf8String PARAMS ((const char *, int));
-static tree make_field_value PARAMS ((tree));
-static tree get_dispatch_vector PARAMS ((tree));
-static tree get_dispatch_table PARAMS ((tree, tree));
-static void add_interface_do PARAMS ((tree, tree, int));
-static tree maybe_layout_super_class PARAMS ((tree, tree));
-static int assume_compiled PARAMS ((const char *));
-static struct hash_entry *init_test_hash_newfunc PARAMS ((struct hash_entry *,
-                                                         struct hash_table *,
-                                                         hash_table_key));
-static rtx registerClass_libfunc;
-
-extern struct obstack permanent_obstack;
 struct obstack temporary_obstack;
 
 /* The compiler generates different code depending on whether or not
@@ -68,7 +78,7 @@ typedef struct assume_compiled_node_struct
   /* The class or package name.  */
   const char *ident;
 
-  /* Non-zero if this represents an exclusion.  */
+  /* Nonzero if this represents an exclusion.  */
   int excludep;
 
   /* Pointers to other nodes in the tree.  */
@@ -77,15 +87,14 @@ typedef struct assume_compiled_node_struct
   struct assume_compiled_node_struct *child;
 } assume_compiled_node;
 
-static assume_compiled_node *find_assume_compiled_node
-                       PARAMS ((assume_compiled_node *, const char *));
+static assume_compiled_node *find_assume_compiled_node (assume_compiled_node *,
+                                                       const char *);
 
 /* This is the root of the include/exclude tree.  */
 
 static assume_compiled_node *assume_compiled_tree;
 
-static tree class_roots[5]
-= { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
+static GTY(()) tree class_roots[5];
 #define registered_class class_roots[0]
 #define fields_ident class_roots[1]  /* get_identifier ("fields") */
 #define info_ident class_roots[2]  /* get_identifier ("info") */
@@ -97,9 +106,7 @@ static tree class_roots[5]
    appropriate node does not exist.  */
 
 static assume_compiled_node *
-find_assume_compiled_node (node, ident)
-     assume_compiled_node *node;
-     const char *ident;
+find_assume_compiled_node (assume_compiled_node *node, const char *ident)
 {
   while (node)
     {
@@ -135,16 +142,14 @@ find_assume_compiled_node (node, ident)
 }
 
 /* Add a new IDENT to the include/exclude tree.  It's an exclusion
-   if EXCLUDEP is non-zero.  */
+   if EXCLUDEP is nonzero.  */
 
 void
-add_assume_compiled (ident, excludep)
-     const char *ident;
-     int excludep;
+add_assume_compiled (const char *ident, int excludep)
 {
+  int len;
   assume_compiled_node *parent;
-  assume_compiled_node *node = 
-    (assume_compiled_node *) xmalloc (sizeof (assume_compiled_node));
+  assume_compiled_node *node = xmalloc (sizeof (assume_compiled_node));
 
   node->ident = xstrdup (ident);
   node->excludep = excludep;
@@ -154,8 +159,7 @@ add_assume_compiled (ident, excludep)
 
   if (NULL == assume_compiled_tree)
     {
-      assume_compiled_tree = 
-       (assume_compiled_node *) xmalloc (sizeof (assume_compiled_node));
+      assume_compiled_tree = xmalloc (sizeof (assume_compiled_node));
       assume_compiled_tree->ident = "";
       assume_compiled_tree->excludep = 0;
       assume_compiled_tree->sibling = NULL;
@@ -176,7 +180,8 @@ add_assume_compiled (ident, excludep)
      class or a package name.  Adjust PARENT accordingly.  */
 
   parent = find_assume_compiled_node (assume_compiled_tree, ident);
-  if (ident[strlen (parent->ident)] != '.')
+  len = strlen (parent->ident);
+  if (parent->ident[len] && parent->ident[len] != '.')
     parent = parent->parent;
 
   /* Insert NODE into the tree.  */
@@ -186,12 +191,11 @@ add_assume_compiled (ident, excludep)
   parent->child = node;
 }
 
-/* Returns non-zero if IDENT is the name of a class that the compiler
-   should assume has been compiled to FIXME  */
+/* Returns nonzero if IDENT is the name of a class that the compiler
+   should assume has been compiled to object code.  */
 
 static int
-assume_compiled (ident)
-     const char *ident;
+assume_compiled (const char *ident)
 {
   assume_compiled_node *i;
   int result;
@@ -212,13 +216,12 @@ assume_compiled (ident)
    Also, PREFIX is prepended, and SUFFIX is appended. */
 
 tree
-ident_subst (old_name, old_length, prefix, old_char, new_char, suffix)
-     const char* old_name;
-     int old_length;
-     const char *prefix;
-     int old_char;
-     int new_char;
-     const char *suffix;
+ident_subst (const char* old_name,
+            int old_length,
+            const char *prefix,
+            int old_char,
+            int new_char,
+            const char *suffix)
 {
   int prefix_len = strlen (prefix);
   int suffix_len = strlen (suffix);
@@ -226,7 +229,7 @@ ident_subst (old_name, old_length, prefix, old_char, new_char, suffix)
 #ifdef __GNUC__
   char buffer[i];
 #else
-  char *buffer = (char *)alloca  (i);
+  char *buffer = alloca (i);
 #endif
   strcpy (buffer, prefix);
   for (i = 0; i < old_length; i++)
@@ -245,12 +248,11 @@ ident_subst (old_name, old_length, prefix, old_char, new_char, suffix)
    Also, PREFIX is prepended, and SUFFIX is appended. */
 
 tree
-identifier_subst (old_id, prefix, old_char, new_char, suffix)
-     const tree old_id;
-     const char *prefix;
-     int old_char;
-     int new_char;
-     const char *suffix;
+identifier_subst (const tree old_id,
+                 const char *prefix,
+                 int old_char,
+                 int new_char,
+                 const char *suffix)
 {
   return ident_subst (IDENTIFIER_POINTER (old_id), IDENTIFIER_LENGTH (old_id),
                      prefix, old_char, new_char, suffix);
@@ -260,9 +262,7 @@ identifier_subst (old_id, prefix, old_char, new_char, suffix)
    prefixed by PREFIX. */
 
 tree
-mangled_classname (prefix, type)
-  const char *prefix;
-  tree type;
+mangled_classname (const char *prefix, tree type)
 {
   tree ident = TYPE_NAME (type);
   if (TREE_CODE (ident) != IDENTIFIER_NODE)
@@ -271,25 +271,11 @@ mangled_classname (prefix, type)
 }
 
 tree
-make_class ()
+make_class (void)
 {
   tree type;
   type = make_node (RECORD_TYPE);
-#ifdef JAVA_USE_HANDLES
-  tree field1 = build_decl (FIELD_DECL, get_identifier ("obj"),
-                           build_pointer_type (type));
-  tree field2 = build_decl (FIELD_DECL, get_identifier ("methods"),
-                           methodtable_ptr_type);
-  tree handle_type = make_node (RECORD_TYPE);
-  TREE_CHAIN (field1) = field2;
-  TYPE_FIELDS (handle_type) = field1;
-  TYPE_BINFO (type) = make_tree_vec (7);
-  TYPE_BINFO (handle_type) = make_tree_vec (7);
-  BINFO_HANDLE (TYPE_BINFO (handle_type)) = type;
-  BINFO_HANDLE (TYPE_BINFO (type)) = handle_type;
-#else
-  TYPE_BINFO (type) = make_tree_vec (6);
-#endif
+  TYPE_BINFO (type) = make_tree_vec (BINFO_ELTS);
   MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type);
 
   return type;
@@ -300,8 +286,7 @@ make_class ()
    return a corresponding IDENTIFIER_NODE, except using '.' as separator. */
 
 tree
-unmangle_classname (name, name_length)
-     const char *name;  int name_length;
+unmangle_classname (const char *name, int name_length)
 {
   tree to_return = ident_subst (name, name_length, "", '/', '.', "");
   /* It's not sufficient to compare to_return and get_identifier
@@ -320,37 +305,29 @@ unmangle_classname (name, name_length)
 }
 
 tree
-push_class (class_type, class_name)
-     tree class_type, class_name;
+push_class (tree class_type, tree class_name)
 {
   tree decl, signature;
-  const char *save_input_filename = input_filename;
-  int save_lineno = lineno;
+  location_t saved_loc = input_location;
   tree source_name = identifier_subst (class_name, "", '.', '/', ".java");
   CLASS_P (class_type) = 1;
   input_filename = IDENTIFIER_POINTER (source_name);
-  lineno = 0;
+  input_line = 0;
   decl = build_decl (TYPE_DECL, class_name, class_type);
-  input_filename = save_input_filename;
-  lineno = save_lineno;
+
+  /* dbxout needs a DECL_SIZE if in gstabs mode */
+  DECL_SIZE (decl) = integer_zero_node;
+
+  input_location = saved_loc;
   signature = identifier_subst (class_name, "L", '.', '/', ";");
   IDENTIFIER_SIGNATURE_TYPE (signature) = build_pointer_type (class_type);
 
-  /* Setting DECL_ARTIFICAL forces dbxout.c to specific the type is
+  /* Setting DECL_ARTIFICIAL forces dbxout.c to specific the type is
      both a typedef and in the struct name-space.  We may want to re-visit
      this later, but for now it reduces the changes needed for gdb. */
   DECL_ARTIFICIAL (decl) = 1;
 
   pushdecl_top_level (decl);
-#ifdef JAVA_USE_HANDLES
-  {
-    tree handle_name = identifier_subst (class_name,
-                                        "Handle$", '.', '.', "");
-    tree handle_decl = build_decl (TYPE_DECL, handle_name,
-                                  CLASS_TO_HANDLE_TYPE (class_type));
-    pushdecl (handle_decl);
-  }
-#endif
 
   return decl;
 }
@@ -361,8 +338,7 @@ push_class (class_type, class_name)
    fill in field or methods, or do layout_type. */
 
 tree
-lookup_class (name)
-     tree name;
+lookup_class (tree name)
 {
   tree decl = IDENTIFIER_CLASS_VALUE (name);
   if (decl == NULL_TREE)
@@ -371,11 +347,8 @@ lookup_class (name)
 }
 
 void
-set_super_info (access_flags, this_class, super_class, interfaces_count)
-     int access_flags;
-     tree this_class;
-     tree super_class;
-     int interfaces_count;
+set_super_info (int access_flags, tree this_class,
+               tree super_class, int interfaces_count)
 {
   int total_supers = interfaces_count;
   tree class_decl = TYPE_NAME (this_class);
@@ -385,10 +358,9 @@ set_super_info (access_flags, this_class, super_class, interfaces_count)
   TYPE_BINFO_BASETYPES (this_class) = make_tree_vec (total_supers);
   if (super_class)
     {
-      tree super_binfo = make_tree_vec (6);
+      tree super_binfo = make_tree_vec (BINFO_ELTS);
       BINFO_TYPE (super_binfo) = super_class;
       BINFO_OFFSET (super_binfo) = integer_zero_node;
-      TREE_VIA_PUBLIC (super_binfo) = 1;
       TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (this_class)), 0)
        = super_binfo;
       CLASS_HAS_SUPER (this_class) = 1;
@@ -398,9 +370,7 @@ set_super_info (access_flags, this_class, super_class, interfaces_count)
 }
 
 void
-set_class_decl_access_flags (access_flags, class_decl)
-     int access_flags;
-     tree class_decl;
+set_class_decl_access_flags (int access_flags, tree class_decl)
 {
   if (access_flags & ACC_PUBLIC)    CLASS_PUBLIC (class_decl) = 1;
   if (access_flags & ACC_FINAL)     CLASS_FINAL (class_decl) = 1;
@@ -410,14 +380,14 @@ set_class_decl_access_flags (access_flags, class_decl)
   if (access_flags & ACC_STATIC)    CLASS_STATIC (class_decl) = 1;
   if (access_flags & ACC_PRIVATE)   CLASS_PRIVATE (class_decl) = 1;
   if (access_flags & ACC_PROTECTED) CLASS_PROTECTED (class_decl) = 1;
+  if (access_flags & ACC_STRICT)    CLASS_STRICTFP (class_decl) = 1;
 }
 
 /* Return length of inheritance chain of CLAS, where java.lang.Object is 0,
    direct sub-classes of Object are 1, and so on. */
 
 int
-class_depth (clas)
-     tree clas;
+class_depth (tree clas)
 {
   int depth = 0;
   if (! CLASS_LOADED_P (clas))
@@ -435,8 +405,7 @@ class_depth (clas)
 /* Return true iff TYPE2 is an interface that extends interface TYPE1 */
 
 int
-interface_of_p (type1, type2)
-     tree type1, type2;
+interface_of_p (tree type1, tree type2)
 {
   int n, i;
   tree basetype_vec;
@@ -463,8 +432,7 @@ interface_of_p (type1, type2)
 /* Return true iff TYPE1 inherits from TYPE2. */
 
 int
-inherits_from_p (type1, type2)
-     tree type1, type2;
+inherits_from_p (tree type1, tree type2)
 {
   while (type1 != NULL_TREE && TREE_CODE (type1) == RECORD_TYPE)
     {
@@ -478,8 +446,7 @@ inherits_from_p (type1, type2)
 /* Return a 1 iff TYPE1 is an enclosing context for TYPE2 */
 
 int
-enclosing_context_p (type1, type2)
-     tree type1, type2;
+enclosing_context_p (tree type1, tree type2)
 {
   if (!INNER_CLASS_TYPE_P (type2))
     return 0;
@@ -499,8 +466,7 @@ enclosing_context_p (type1, type2)
 /* Return 1 iff there exists a common enclosing context between TYPE1
    and TYPE2.  */
 
-int common_enclosing_context_p (type1, type2)
-     tree type1, type2;
+int common_enclosing_context_p (tree type1, tree type2)
 {
   if (!PURE_INNER_CLASS_TYPE_P (type1) || !PURE_INNER_CLASS_TYPE_P (type2))
     return 0;
@@ -521,15 +487,13 @@ int common_enclosing_context_p (type1, type2)
 }
 
 static void
-add_interface_do (basetype_vec, interface_class, i)
-     tree basetype_vec, interface_class;
-     int i;
+add_interface_do (tree basetype_vec, tree interface_class, int i)
 {
-  tree interface_binfo = make_tree_vec (6);
+  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_VIA_PUBLIC (interface_binfo) = 1;
   TREE_VEC_ELT (basetype_vec, i) = interface_binfo;
 }
 
@@ -538,8 +502,7 @@ add_interface_do (basetype_vec, interface_class, i)
    if attempt is made to add it twice. */
 
 tree
-maybe_add_interface (this_class, interface_class)
-     tree this_class, interface_class;
+maybe_add_interface (tree this_class, tree interface_class)
 {
   tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
   int i;
@@ -563,8 +526,7 @@ maybe_add_interface (this_class, interface_class)
 /* Add the INTERFACE_CLASS as one of the interfaces of THIS_CLASS. */
 
 void
-add_interface (this_class, interface_class)
-     tree this_class, interface_class;
+add_interface (tree this_class, tree interface_class)
 {
   tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
   int i;
@@ -587,9 +549,7 @@ add_interface (this_class, interface_class)
    in the list (*LIST) whose DECL_NAME is NAME. */
 
 static tree *
-find_named_method (list, name)
-     tree *list;
-     tree name;
+find_named_method (tree *list, tree name)
 {
   while (*list && DECL_NAME (*list) != name)
     list = &TREE_CHAIN (*list);
@@ -598,78 +558,50 @@ find_named_method (list, name)
 #endif
 
 static tree
-build_java_method_type (fntype, this_class, access_flags)
-     tree fntype;
-     tree this_class;
-     int access_flags;
+build_java_method_type (tree fntype, tree this_class, int access_flags)
 {
   if (access_flags & ACC_STATIC)
     return fntype;
-  return build_method_type (CLASS_TO_HANDLE_TYPE (this_class), fntype);
-}
-
-static struct hash_entry *
-init_test_hash_newfunc (entry, table, string)
-     struct hash_entry *entry;
-     struct hash_table *table;
-     hash_table_key string ATTRIBUTE_UNUSED;
-{
-  struct init_test_hash_entry *ret = (struct init_test_hash_entry *) entry;
-  if (ret == NULL)
-    {
-      ret = ((struct init_test_hash_entry *)
-            hash_allocate (table, sizeof (struct init_test_hash_entry)));
-      if (ret == NULL)
-       return NULL;
-    }
-  ret->init_test_decl = 0;
-  return (struct hash_entry *) ret;
-}
-
-/* Hash table helpers. Also reused in find_applicable_accessible_methods_list 
-   (parse.y). The hash of a tree node is its pointer value, comparison
-   is direct. */
-
-unsigned long
-java_hash_hash_tree_node (k)
-     hash_table_key k;
-{
-  return (long) k;
-}
-
-bool
-java_hash_compare_tree_node (k1, k2)
-     hash_table_key k1;
-     hash_table_key k2;
-{
-  return ((char*) k1 == (char*) k2);
+  return build_method_type (this_class, fntype);
 }
 
 tree
-add_method_1 (handle_class, access_flags, name, function_type)
-     tree handle_class;
-     int access_flags;
-     tree name;
-     tree function_type;
+add_method_1 (tree this_class, int access_flags, tree name, tree function_type)
 {
   tree method_type, fndecl;
 
   method_type = build_java_method_type (function_type,
-                                       handle_class, access_flags);
+                                       this_class, access_flags);
 
   fndecl = build_decl (FUNCTION_DECL, name, method_type);
-  DECL_CONTEXT (fndecl) = handle_class;
+  DECL_CONTEXT (fndecl) = this_class;
 
   DECL_LANG_SPECIFIC (fndecl)
-    = (struct lang_decl *) ggc_alloc_cleared (sizeof (struct lang_decl));
+    = ggc_alloc_cleared (sizeof (struct lang_decl));
+  DECL_LANG_SPECIFIC (fndecl)->desc = LANG_DECL_FUNC;
 
   /* Initialize the static initializer test table.  */
-  hash_table_init (&DECL_FUNCTION_INIT_TEST_TABLE (fndecl),
-                  init_test_hash_newfunc, java_hash_hash_tree_node, 
-                  java_hash_compare_tree_node);
+  
+  DECL_FUNCTION_INIT_TEST_TABLE (fndecl) = 
+    java_treetreehash_create (10, 1);
+
+  /* Initialize the initialized (static) class table. */
+  if (access_flags & ACC_STATIC)
+    DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl) =
+      htab_create_ggc (50, htab_hash_pointer, htab_eq_pointer, NULL);
+
+  /* Initialize the static method invocation compound list */
+  DECL_FUNCTION_STATIC_METHOD_INVOCATION_COMPOUND (fndecl) = NULL_TREE;
 
-  TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class);
-  TYPE_METHODS (handle_class) = fndecl;
+  TREE_CHAIN (fndecl) = TYPE_METHODS (this_class);
+  TYPE_METHODS (this_class) = fndecl;
+
+  /* Notice that this is a finalizer and update the class type
+     accordingly. This is used to optimize instance allocation. */
+  if (name == finalize_identifier_node
+      && TREE_TYPE (function_type) == void_type_node
+      && TREE_VALUE (TYPE_ARG_TYPES (function_type)) == void_type_node)
+    HAS_FINALIZER_P (this_class) = 1;
 
   if (access_flags & ACC_PUBLIC) METHOD_PUBLIC (fndecl) = 1;
   if (access_flags & ACC_PROTECTED) METHOD_PROTECTED (fndecl) = 1;
@@ -686,7 +618,7 @@ add_method_1 (handle_class, access_flags, name, function_type)
     METHOD_FINAL (fndecl) = DECL_INLINE (fndecl) = 1;
   if (access_flags & ACC_SYNCHRONIZED) METHOD_SYNCHRONIZED (fndecl) = 1;
   if (access_flags & ACC_ABSTRACT) METHOD_ABSTRACT (fndecl) = 1;
-  if (access_flags & ACC_TRANSIENT) METHOD_TRANSIENT (fndecl) = 1;
+  if (access_flags & ACC_STRICT) METHOD_STRICTFP (fndecl) = 1;
   return fndecl;
 }
 
@@ -695,13 +627,8 @@ add_method_1 (handle_class, access_flags, name, function_type)
    Its signature (mangled type) is METHOD_SIG (an IDENTIFIER_NODE). */
 
 tree
-add_method (this_class, access_flags, name, method_sig)
-     tree this_class;
-     int access_flags;
-     tree name;
-     tree method_sig;
+add_method (tree this_class, int access_flags, tree name, tree method_sig)
 {
-  tree handle_class = CLASS_TO_HANDLE_TYPE (this_class);
   tree function_type, fndecl;
   const unsigned char *sig
     = (const unsigned char *) IDENTIFIER_POINTER (method_sig);
@@ -710,17 +637,13 @@ add_method (this_class, access_flags, name, method_sig)
     fatal_error ("bad method signature");
 
   function_type = get_type_from_signature (method_sig);
-  fndecl = add_method_1 (handle_class, access_flags, name, function_type);
+  fndecl = add_method_1 (this_class, access_flags, name, function_type);
   set_java_signature (TREE_TYPE (fndecl), method_sig);
   return fndecl;
 }
 
 tree
-add_field (class, name, field_type, flags)
-     tree class;
-     tree name;
-     tree field_type;
-     int flags;
+add_field (tree class, tree name, tree field_type, int flags)
 {
   int is_static = (flags & ACC_STATIC) != 0;
   tree field;
@@ -741,24 +664,35 @@ add_field (class, name, field_type, flags)
       /* Always make field externally visible.  This is required so
         that native methods can always access the field.  */
       TREE_PUBLIC (field) = 1;
+      /* Considered external until we know what classes are being
+        compiled into this object file.  */
+      DECL_EXTERNAL (field) = 1;
     }
+
   return field;
 }
 
 /* Associate a constant value CONSTANT with VAR_DECL FIELD. */
 
 void
-set_constant_value (field, constant)
-     tree field, constant;
+set_constant_value (tree field, tree constant)
 {
   if (field == NULL_TREE)
     warning ("misplaced ConstantValue attribute (not in any field)");
   else if (DECL_INITIAL (field) != NULL_TREE)
-    warning ("duplicate ConstanValue atribute for field '%s'",
+    warning ("duplicate ConstantValue attribute for field '%s'",
             IDENTIFIER_POINTER (DECL_NAME (field)));
   else
     {
       DECL_INITIAL (field) = constant;
+      if (TREE_TYPE (constant) != TREE_TYPE (field)
+         && ! (TREE_TYPE (constant) == int_type_node
+               && INTEGRAL_TYPE_P (TREE_TYPE (field))
+               && TYPE_PRECISION (TREE_TYPE (field)) <= 32)
+         && ! (TREE_TYPE (constant) == utf8const_ptr_type
+               && TREE_TYPE (field) == string_ptr_type_node))
+       error ("ConstantValue attribute of field '%s' has wrong type",
+              IDENTIFIER_POINTER (DECL_NAME (field)));
       if (FIELD_FINAL (field))
        DECL_FIELD_FINAL_IUD (field) = 1;
     }
@@ -768,9 +702,7 @@ set_constant_value (field, constant)
 
 #if 0
 int
-strLengthUtf8 (str, len)
-     char *str;
-     int len;
+strLengthUtf8 (char *str, int len)
 {
   register unsigned char* ptr = (unsigned char*) str;
   register unsigned char *limit = ptr + len;
@@ -789,9 +721,7 @@ strLengthUtf8 (str, len)
  */
 
 static int32
-hashUtf8String (str, len)
-     const char *str;
-     int len;
+hashUtf8String (const char *str, int len)
 {
   register const unsigned char* ptr = (const unsigned char*) str;
   register const unsigned char *limit = ptr + len;
@@ -806,11 +736,10 @@ hashUtf8String (str, len)
   return hash;
 }
 
-tree utf8_decl_list = NULL_TREE;
+static GTY(()) tree utf8_decl_list = NULL_TREE;
 
 tree
-build_utf8_ref (name)
-     tree name;
+build_utf8_ref (tree name)
 {
   const char * name_ptr = IDENTIFIER_POINTER(name);
   int name_len = IDENTIFIER_LENGTH(name);
@@ -844,13 +773,30 @@ build_utf8_ref (name)
   sprintf(buf, "_Utf%d", ++utf8_count);
 
   decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_type);
-  /* FIXME get some way to force this into .text, not .data. */
   TREE_STATIC (decl) = 1;
   DECL_ARTIFICIAL (decl) = 1;
   DECL_IGNORED_P (decl) = 1;
   TREE_READONLY (decl) = 1;
   TREE_THIS_VOLATILE (decl) = 0;
   DECL_INITIAL (decl) = cinit;
+
+  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);
@@ -862,12 +808,25 @@ build_utf8_ref (name)
   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); 
+  TREE_TYPE (cl) = promote_type (class_ptr_type);
+  return cl;
+}
+
 /* Build a reference to the class TYPE.
    Also handles primitive types and array types. */
 
 tree
-build_class_ref (type)
-     tree type;
+build_class_ref (tree type)
 {
   int is_compiled = is_compiled_class (type);
   if (is_compiled)
@@ -875,6 +834,12 @@ build_class_ref (type)
       tree ref, decl_name, decl;
       if (TREE_CODE (type) == POINTER_TYPE)
        type = TREE_TYPE (type);
+
+      if  (flag_indirect_dispatch 
+          && type != current_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)
@@ -891,13 +856,13 @@ build_class_ref (type)
              TREE_PUBLIC (decl) = 1;
              DECL_IGNORED_P (decl) = 1;
              DECL_ARTIFICIAL (decl) = 1;
+             if (is_compiled == 1)
+               DECL_EXTERNAL (decl) = 1;
              SET_DECL_ASSEMBLER_NAME (decl, 
                                       java_mangle_class_field
                                       (&temporary_obstack, type));
              make_decl_rtl (decl, NULL);
              pushdecl_top_level (decl);
-             if (is_compiled == 1)
-               DECL_EXTERNAL (decl) = 1;
            }
        }
       else
@@ -947,10 +912,9 @@ build_class_ref (type)
              decl = build_decl (VAR_DECL, decl_name, class_type_node);
              TREE_STATIC (decl) = 1;
              TREE_PUBLIC (decl) = 1;
+             DECL_EXTERNAL (decl) = 1;
              make_decl_rtl (decl, NULL);
              pushdecl_top_level (decl);
-             if (is_compiled == 1)
-               DECL_EXTERNAL (decl) = 1;
            }
        }
 
@@ -958,23 +922,28 @@ build_class_ref (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
-build_static_field_ref (fdecl)
-     tree fdecl;
+build_static_field_ref (tree fdecl)
 {
   tree fclass = DECL_CONTEXT (fdecl);
   int is_compiled = is_compiled_class (fclass);
-  if (is_compiled)
+
+  /* Allow static final fields to fold to a constant.  When using
+     -fno-assume-compiled, gcj will sometimes try to fold a field from
+     an uncompiled class.  This is required when the field in question
+     meets the appropriate criteria for a compile-time constant.
+     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 
+       && (! flag_indirect_dispatch || current_class == fclass))
+      || (FIELD_FINAL (fdecl) && DECL_INITIAL (fdecl) != NULL_TREE
+         && (JSTRING_TYPE_P (TREE_TYPE (fdecl))
+             || JNUMERIC_TYPE_P (TREE_TYPE (fdecl)))
+         && TREE_CONSTANT (DECL_INITIAL (fdecl))))
     {
       if (!DECL_RTL_SET_P (fdecl))
        {
@@ -984,7 +953,18 @@ build_static_field_ref (fdecl)
        }
       return fdecl;
     }
-  else
+
+  if (flag_indirect_dispatch)
+    {
+      tree table_index 
+       = build_int_2 (get_symbol_table_index (fdecl, &atable_methods), 0);
+      tree field_address
+       = build (ARRAY_REF, build_pointer_type (TREE_TYPE (fdecl)), 
+                atable_decl, table_index);
+      return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl), 
+                          field_address));
+    }
+  else  
     {
       /* Compile as:
        * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */
@@ -1018,8 +998,7 @@ build_static_field_ref (fdecl)
 }
 
 int
-get_access_flags_from_decl (decl)
-     tree decl;
+get_access_flags_from_decl (tree decl)
 {
   int access_flags = 0;
   if (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL)
@@ -1058,6 +1037,8 @@ get_access_flags_from_decl (decl)
        access_flags |= ACC_PRIVATE;
       if (CLASS_PROTECTED (decl))
        access_flags |= ACC_PROTECTED;
+      if (CLASS_STRICTFP (decl))
+       access_flags |= ACC_STRICT;
       return access_flags;
     }
   if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -1078,21 +1059,22 @@ get_access_flags_from_decl (decl)
        access_flags |= ACC_NATIVE;
       if (METHOD_ABSTRACT (decl))
        access_flags |= ACC_ABSTRACT;
-      if (METHOD_TRANSIENT (decl))
-       access_flags |= ACC_TRANSIENT;
+      if (METHOD_STRICTFP (decl))
+       access_flags |= ACC_STRICT;
+      if (METHOD_INVISIBLE (decl))
+       access_flags |= ACC_INVISIBLE;
       return access_flags;
     }
   abort ();
 }
 
 static tree
-make_field_value (fdecl)
-  tree fdecl;
+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)));
@@ -1117,7 +1099,7 @@ make_field_value (fdecl)
 
   PUSH_FIELD_VALUE
     (finit, "info",
-     build (CONSTRUCTOR, field_info_union_node, NULL_TREE,
+     build_constructor (field_info_union_node,
            build_tree_list
            ((FIELD_STATIC (fdecl)
              ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node))
@@ -1131,13 +1113,20 @@ make_field_value (fdecl)
 }
 
 static tree
-make_method_value (mdecl)
-     tree mdecl;
+make_method_value (tree mdecl)
 {
+  static int method_name_count = 0;
   tree minit;
+  tree index;
   tree code;
 #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);
+  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);
@@ -1155,17 +1144,56 @@ make_method_value (mdecl)
                         IDENTIFIER_LENGTH(signature)))));
   }
   PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0));
+  PUSH_FIELD_VALUE (minit, "index", index);
   PUSH_FIELD_VALUE (minit, "ncode", code);
+
+  {
+    /* Compute the `throws' information for the method.  */
+    tree table = null_pointer_node;
+    if (DECL_FUNCTION_THROWS (mdecl) != NULL_TREE)
+      {
+       int length = 1 + list_length (DECL_FUNCTION_THROWS (mdecl));
+       tree iter, type, array;
+       char buf[60];
+
+       table = tree_cons (NULL_TREE, table, NULL_TREE);
+       for (iter = DECL_FUNCTION_THROWS (mdecl);
+            iter != NULL_TREE;
+            iter = TREE_CHAIN (iter))
+         {
+           tree sig = DECL_NAME (TYPE_NAME (TREE_VALUE (iter)));
+           tree utf8
+             = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (sig),
+                                                   IDENTIFIER_LENGTH (sig)));
+           table = tree_cons (NULL_TREE, utf8, table);
+         }
+       type = build_prim_array_type (ptr_type_node, length);
+       table = build_constructor (type, table);
+       /* Compute something unique enough.  */
+       sprintf (buf, "_methods%d", method_name_count++);
+       array = build_decl (VAR_DECL, get_identifier (buf), type);
+       DECL_INITIAL (array) = table;
+       TREE_STATIC (array) = 1;
+       DECL_ARTIFICIAL (array) = 1;
+       DECL_IGNORED_P (array) = 1;
+       rest_of_decl_compilation (array, (char*) 0, 1, 0);
+
+       table = build1 (ADDR_EXPR, ptr_type_node, array);
+      }
+
+    PUSH_FIELD_VALUE (minit, "throws", table);
+  }
+
   FINISH_RECORD_CONSTRUCTOR (minit);
   return minit;
 }
 
 static tree
-get_dispatch_vector (type)
-     tree type;
+get_dispatch_vector (tree type)
 {
   tree vtable = TYPE_VTABLE (type);
-  if (vtable == NULL)
+
+  if (vtable == NULL_TREE)
     {
       HOST_WIDE_INT i;
       tree method;
@@ -1193,48 +1221,92 @@ get_dispatch_vector (type)
 }
 
 static tree
-get_dispatch_table (type, this_class_addr)
-     tree type, this_class_addr;
+get_dispatch_table (tree type, tree this_class_addr)
 {
   int abstract_p = CLASS_ABSTRACT (TYPE_NAME (type));
   tree vtable = get_dispatch_vector (type);
-  int i;
+  int i, j;
   tree list = NULL_TREE;
   int nvirtuals = TREE_VEC_LENGTH (vtable);
+  int arraysize;
+  tree gc_descr;
+
   for (i = nvirtuals;  --i >= 0; )
     {
       tree method = TREE_VEC_ELT (vtable, i);
       if (METHOD_ABSTRACT (method))
        {
          if (! abstract_p)
-           warning_with_decl (method,
-                              "abstract method in non-abstract class");
-         method = null_pointer_node;
+           warning ("%Jabstract method in non-abstract class", method);
+
+         if (TARGET_VTABLE_USES_DESCRIPTORS)
+           for (j = 0; j < TARGET_VTABLE_USES_DESCRIPTORS; ++j)
+             list = tree_cons (NULL_TREE, null_pointer_node, list);
+         else
+           list = tree_cons (NULL_TREE, null_pointer_node, list);
        }
       else
        {
          if (!DECL_RTL_SET_P (method))
            make_decl_rtl (method, NULL);
-         method = build1 (ADDR_EXPR, nativecode_ptr_type_node, 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_CONSTANT (fdesc) = 1;
+               list = tree_cons (NULL_TREE, fdesc, list);
+             }
+         else
+           list = tree_cons (NULL_TREE,
+                             build1 (ADDR_EXPR, nativecode_ptr_type_node,
+                                     method),
+                             list);
        }
-      list = tree_cons (NULL_TREE /*DECL_VINDEX (method) + 2*/,
-                       method, list);
     }
+
   /* Dummy entry for compatibility with G++ -fvtable-thunks.  When
      using the Boehm GC we sometimes stash a GC type descriptor
      there. We set the PURPOSE to NULL_TREE not to interfere (reset)
      the emitted byte count during the output to the assembly file. */
-  list = tree_cons (NULL_TREE, get_boehm_type_descriptor (type),
-                   list);
-  list = tree_cons (integer_zero_node, this_class_addr, list);
-  return build (CONSTRUCTOR, build_prim_array_type (nativecode_ptr_type_node,
-                                                   nvirtuals + 2),
-                NULL_TREE, list);
+  /* With TARGET_VTABLE_USES_DESCRIPTORS, we only add one extra
+     fake "function descriptor".  It's first word is the is the class
+     pointer, and subsequent words (usually one) contain the GC descriptor.
+     In all other cases, we reserve two extra vtable slots. */
+  gc_descr =  get_boehm_type_descriptor (type);
+  list = tree_cons (NULL_TREE, gc_descr, list);
+  for (j = 1; j < TARGET_VTABLE_USES_DESCRIPTORS-1; ++j)
+    list = tree_cons (NULL_TREE, gc_descr, list);
+  list = tree_cons (NULL_TREE, this_class_addr, list);
+
+  /** Pointer to type_info object (to be implemented), according to g++ ABI. */
+  list = tree_cons (NULL_TREE, null_pointer_node, list);
+  /** Offset to start of whole object.  Always (ptrdiff_t)0 for Java. */
+  list = tree_cons (integer_zero_node, null_pointer_node, list);
+
+  arraysize = (TARGET_VTABLE_USES_DESCRIPTORS? nvirtuals + 1 : nvirtuals + 2);
+  if (TARGET_VTABLE_USES_DESCRIPTORS)
+    arraysize *= TARGET_VTABLE_USES_DESCRIPTORS;
+  arraysize += 2;
+  return build_constructor (build_prim_array_type (nativecode_ptr_type_node,
+                                                  arraysize), list);
+}
+
+static int
+supers_all_compiled (tree type)
+{
+  while (type != NULL_TREE)
+    {
+      if (!assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))))
+       return 0;
+      type = CLASSTYPE_SUPER (type);
+    }
+  return 1;
 }
 
 void
-make_class_data (type)
-     tree type;
+make_class_data (tree type)
 {
   tree decl, cons, temp;
   tree field, fields_decl;
@@ -1256,6 +1328,9 @@ make_class_data (type)
   tree interfaces = null_pointer_node;
   int interface_len = 0;
   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);
 
   this_class_addr = build_class_ref (type);
   decl = TREE_OPERAND (this_class_addr, 0);
@@ -1298,8 +1373,8 @@ make_class_data (type)
       field_array_type = build_prim_array_type (field_type_node, field_count);
       fields_decl = build_decl (VAR_DECL, mangled_classname ("_FL_", type),
                                field_array_type);
-      DECL_INITIAL (fields_decl) = build (CONSTRUCTOR, field_array_type,
-                                         NULL_TREE, static_fields);
+      DECL_INITIAL (fields_decl) = build_constructor (field_array_type,
+                                                     static_fields);
       TREE_STATIC (fields_decl) = 1;
       DECL_ARTIFICIAL (fields_decl) = 1;
       DECL_IGNORED_P (fields_decl) = 1;
@@ -1309,7 +1384,7 @@ make_class_data (type)
     fields_decl = NULL_TREE;
 
   /* Build Method array. */
-  for (method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (type));
+  for (method = TYPE_METHODS (type);
        method != NULL_TREE; method = TREE_CHAIN (method))
     {
       tree init;
@@ -1324,15 +1399,15 @@ make_class_data (type)
   method_array_type = build_prim_array_type (method_type_node, method_count);
   methods_decl = build_decl (VAR_DECL, mangled_classname ("_MT_", type),
                             method_array_type);
-  DECL_INITIAL (methods_decl) = build (CONSTRUCTOR, method_array_type,
-                                      NULL_TREE, nreverse (methods));
+  DECL_INITIAL (methods_decl) = build_constructor (method_array_type,
+                                                  nreverse (methods));
   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);
 
-  if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
-      && ! CLASS_INTERFACE (type_decl))
+  if (supers_all_compiled (type) && ! CLASS_INTERFACE (type_decl)
+      && !flag_indirect_dispatch)
     {
       tree dtable = get_dispatch_table (type, this_class_addr);
       dtable_decl = build_dtable_decl (type);
@@ -1360,7 +1435,9 @@ make_class_data (type)
   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
     {
@@ -1396,8 +1473,7 @@ make_class_data (type)
            }
          init = tree_cons (NULL_TREE, index, init); 
        }
-      DECL_INITIAL (idecl) = build (CONSTRUCTOR, interface_array_type,
-                                   NULL_TREE, init);
+      DECL_INITIAL (idecl) = build_constructor (interface_array_type, init);
       TREE_STATIC (idecl) = 1;
       DECL_ARTIFICIAL (idecl) = 1;
       DECL_IGNORED_P (idecl) = 1;
@@ -1409,7 +1485,9 @@ make_class_data (type)
 
   START_RECORD_CONSTRUCTOR (temp, object_type_node);
   PUSH_FIELD_VALUE (temp, "vtable",
-                   build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl));
+                   build (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);
@@ -1426,7 +1504,12 @@ make_class_data (type)
   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, "vtable_method_count", TYPE_NVIRTUALS (type));
+
+  if (flag_indirect_dispatch)
+    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));
@@ -1434,9 +1517,46 @@ make_class_data (type)
   PUSH_FIELD_VALUE (cons, "field_count", build_int_2 (field_count, 0));
   PUSH_FIELD_VALUE (cons, "static_field_count",
                    build_int_2 (static_field_count, 0));
-  PUSH_FIELD_VALUE (cons, "vtable",
-                   dtable_decl == NULL_TREE ? null_pointer_node
-                   : build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl));
+
+  if (flag_indirect_dispatch)
+    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)
+    {
+      PUSH_FIELD_VALUE (cons, "otable", null_pointer_node);
+      PUSH_FIELD_VALUE (cons, "otable_syms", null_pointer_node);
+    }
+  else
+    {
+      PUSH_FIELD_VALUE (cons, "otable",
+                       build1 (ADDR_EXPR, otable_ptr_type, otable_decl));
+      PUSH_FIELD_VALUE (cons, "otable_syms",
+                       build1 (ADDR_EXPR, symbols_array_ptr_type,
+                               otable_syms_decl));
+      TREE_CONSTANT (otable_decl) = 1;
+    }
+  if (atable_methods == 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, atable_decl));
+      PUSH_FIELD_VALUE (cons, "atable_syms",
+                       build1 (ADDR_EXPR, symbols_array_ptr_type,
+                               atable_syms_decl));
+      TREE_CONSTANT (atable_decl) = 1;
+    }
+  PUSH_FIELD_VALUE (cons, "catch_classes",
+                   build1 (ADDR_EXPR, ptr_type_node, ctable_decl)); 
   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));
@@ -1448,18 +1568,25 @@ make_class_data (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);
+  PUSH_FIELD_VALUE (cons, "signers", null_pointer_node);
+  PUSH_FIELD_VALUE (cons, "chain", null_pointer_node);
 
   FINISH_RECORD_CONSTRUCTOR (cons);
 
   DECL_INITIAL (decl) = cons;
+  
+  /* Hash synchronization requires at least 64-bit alignment. */
+  if (flag_hash_synchronization && POINTER_SIZE < 64)
+    DECL_ALIGN (decl) = 64; 
+  
   rest_of_decl_compilation (decl, (char*) 0, 1, 0);
 }
 
 void
-finish_class ()
+finish_class (void)
 {
   tree method;
-  tree type_methods = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class));
+  tree type_methods = TYPE_METHODS (current_class);
   int saw_native_method = 0;
 
   /* Find out if we have any native methods.  We use this information
@@ -1480,18 +1607,11 @@ finish_class ()
     {
       if (! TREE_ASM_WRITTEN (method) && DECL_SAVED_INSNS (method) != 0)
        {
-         /* It's a deferred inline method.  Decide if we need to emit it. */
-         if (flag_keep_inline_functions
-             || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (method))
-             || ! METHOD_PRIVATE (method)
-             || saw_native_method)
-           {
-             output_inline_function (method);
-             /* Scan the list again to see if there are any earlier
-                 methods to emit. */
-             method = type_methods;
-             continue;
-           }
+         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);
     }
@@ -1507,8 +1627,7 @@ finish_class ()
    return 0 if we cannot assume that CLASS is compiled.
    Returns 1 for primitive and 0 for array types.  */
 int
-is_compiled_class (class)
-     tree class;
+is_compiled_class (tree class)
 {
   int seen_in_zip;
   if (TREE_CODE (class) == POINTER_TYPE)
@@ -1554,25 +1673,51 @@ is_compiled_class (class)
 /* Build a VAR_DECL for the dispatch table (vtable) for class TYPE. */
 
 tree
-build_dtable_decl (type)
-     tree type;
+build_dtable_decl (tree type)
 {
   tree dtype;
 
   /* We need to build a new dtable type so that its size is uniquely
      computed when we're dealing with the class for real and not just
      faking it (like java.lang.Class during the initialization of the
-     compiler.) We now we're not faking a class when CURRENT_CLASS is
+     compiler.) We know we're not faking a class when CURRENT_CLASS is
      TYPE. */
   if (current_class == type)
     {
-      tree dummy = NULL_TREE, aomt, n;
+      tree dummy = NULL_TREE;
+      int n;
 
       dtype = make_node (RECORD_TYPE);
+
+      PUSH_FIELD (dtype, dummy, "top_offset", ptr_type_node);
+      PUSH_FIELD (dtype, dummy, "type_info", ptr_type_node);
+
       PUSH_FIELD (dtype, dummy, "class", class_ptr_type);
-      n = build_int_2 (TREE_VEC_LENGTH (get_dispatch_vector (type)), 0);
-      aomt = build_array_type (ptr_type_node, build_index_type (n));
-      PUSH_FIELD (dtype, dummy, "methods", aomt);
+      for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n)
+       {
+         tree tmp_field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node);
+         TREE_CHAIN (dummy) = tmp_field;
+         DECL_CONTEXT (tmp_field) = dtype;
+         DECL_ARTIFICIAL (tmp_field) = 1;
+         dummy = tmp_field;
+       }
+
+      PUSH_FIELD (dtype, dummy, "gc_descr", ptr_type_node);
+      for (n = 1; n < TARGET_VTABLE_USES_DESCRIPTORS; ++n)
+       {
+         tree tmp_field = build_decl (FIELD_DECL, NULL_TREE, ptr_type_node);
+         TREE_CHAIN (dummy) = tmp_field;
+         DECL_CONTEXT (tmp_field) = dtype;
+         DECL_ARTIFICIAL (tmp_field) = 1;
+         dummy = tmp_field;
+       }
+
+      n = TREE_VEC_LENGTH (get_dispatch_vector (type));
+      if (TARGET_VTABLE_USES_DESCRIPTORS)
+       n *= TARGET_VTABLE_USES_DESCRIPTORS;
+
+      PUSH_FIELD (dtype, dummy, "methods",
+                 build_prim_array_type (nativecode_ptr_type_node, n));
       layout_type (dtype);
     }
   else
@@ -1586,8 +1731,7 @@ build_dtable_decl (type)
    fields inherited from SUPER_CLASS. */
 
 void
-push_super_field (this_class, super_class)
-     tree this_class, super_class;
+push_super_field (tree this_class, tree super_class)
 {
   tree base_decl;
   /* Don't insert the field if we're just re-laying the class out. */ 
@@ -1604,9 +1748,7 @@ push_super_field (this_class, super_class)
 /* Handle the different manners we may have to lay out a super class.  */
 
 static tree
-maybe_layout_super_class (super_class, this_class)
-     tree super_class;
-     tree this_class;
+maybe_layout_super_class (tree super_class, tree this_class)
 {
   if (TREE_CODE (super_class) == RECORD_TYPE)
     {
@@ -1623,8 +1765,19 @@ maybe_layout_super_class (super_class, this_class)
        super_class = TREE_TYPE (super_class);
       else
        {
+         /* do_resolve_class expects an EXPR_WITH_FILE_LOCATION, so
+            we give it one.  */
+         tree this_wrap = NULL_TREE;
+
+         if (this_class)
+           {
+             tree this_decl = TYPE_NAME (this_class);
+             this_wrap = build_expr_wfl (this_class,
+                                         DECL_SOURCE_FILE (this_decl),
+                                         DECL_SOURCE_LINE (this_decl), 0);
+           }
          super_class = do_resolve_class (NULL_TREE, /* FIXME? */
-                                         super_class, NULL_TREE, this_class);
+                                         super_class, NULL_TREE, this_wrap);
          if (!super_class)
            return NULL_TREE;   /* FIXME, NULL_TREE not checked by caller. */
          super_class = TREE_TYPE (super_class);
@@ -1637,19 +1790,18 @@ maybe_layout_super_class (super_class, this_class)
 }
 
 void
-layout_class (this_class)
-     tree this_class;
+layout_class (tree this_class)
 {
   tree super_class = CLASSTYPE_SUPER (this_class);
   tree field;
-  
+
   class_list = tree_cons (this_class, NULL_TREE, class_list);
   if (CLASS_BEING_LAIDOUT (this_class))
     {
       char buffer [1024];
       char *report;
       tree current;
-      
+
       sprintf (buffer, " with `%s'",
               IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))));
       obstack_grow (&temporary_obstack, buffer, strlen (buffer));
@@ -1703,8 +1855,9 @@ layout_class (this_class)
 
   layout_type (this_class);
 
-  /* Also recursively load/layout any superinterfaces, but only if class was
-  loaded from bytecode. The source parser will take care of this itself. */
+  /* Also recursively load/layout any superinterfaces, but only if
+     class was loaded from bytecode.  The source parser will take care
+     of this itself.  */
   if (!CLASS_FROM_SOURCE_P (this_class))
     {
       tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
@@ -1732,26 +1885,73 @@ layout_class (this_class)
        }
     }
 
-  /* Convert the size back to an SI integer value */
-  TYPE_SIZE_UNIT (this_class) = 
+  /* Convert the size back to an SI integer value */
+  TYPE_SIZE_UNIT (this_class) =
     fold (convert (int_type_node, TYPE_SIZE_UNIT (this_class)));
 
   CLASS_BEING_LAIDOUT (this_class) = 0;
   class_list = TREE_CHAIN (class_list);
 }
 
+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)
+    {
+      tree method_decl;
+      tree elt = TREE_VEC_ELT (basetype_vec, i);
+      if (elt == NULL_TREE)
+       break;
+      elt = BINFO_TYPE (elt);
+
+      /* Ensure that interface methods are seen in declared order.  */
+      layout_class_methods (elt);
+
+      /* All base classes will have been laid out at this point, so the order 
+         will be correct.  This code must match similar layout code in the 
+         runtime.  */
+      for (method_decl = TYPE_METHODS (elt);
+          method_decl; method_decl = TREE_CHAIN (method_decl))
+       {
+         tree sig, override;
+
+         /* An interface can have <clinit>.  */
+         if (ID_CLINIT_P (DECL_NAME (method_decl)))
+           continue;
+
+         sig = build_java_argument_signature (TREE_TYPE (method_decl));
+         override = lookup_argument_method (base_class,
+                                            DECL_NAME (method_decl), sig);
+         if (override == NULL_TREE)
+           {
+             /* Found a Miranda method.  Add it.  */
+             tree new_method;
+             sig = build_java_signature (TREE_TYPE (method_decl));
+             new_method
+               = add_method (base_class,
+                             get_access_flags_from_decl (method_decl),
+                             DECL_NAME (method_decl), sig);
+             METHOD_INVISIBLE (new_method) = 1;
+           }
+       }
+
+      /* Try superinterfaces.  */
+      add_miranda_methods (base_class, elt);
+    }
+}
+
 void
-layout_class_methods (this_class)
-     tree this_class;
+layout_class_methods (tree this_class)
 {
   tree method_decl, dtable_count;
-  tree super_class, handle_type;
+  tree super_class;
 
   if (TYPE_NVIRTUALS (this_class))
     return;
 
   super_class = CLASSTYPE_SUPER (this_class);
-  handle_type = CLASS_TO_HANDLE_TYPE (this_class);
 
   if (super_class)
     {
@@ -1763,33 +1963,38 @@ layout_class_methods (this_class)
   else
     dtable_count = integer_zero_node;
 
-  TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type));
+  if (CLASS_ABSTRACT (TYPE_NAME (this_class)))
+    {
+      /* An abstract class can have methods which are declared only in
+        an implemented interface.  These are called "Miranda
+        methods".  We make a dummy method entry for such methods
+        here.  */
+      add_miranda_methods (this_class, this_class);
+    }
+
+  TYPE_METHODS (this_class) = nreverse (TYPE_METHODS (this_class));
 
-  for (method_decl = TYPE_METHODS (handle_type);
+  for (method_decl = TYPE_METHODS (this_class);
        method_decl; method_decl = TREE_CHAIN (method_decl))
-    dtable_count = layout_class_method (this_class, super_class, 
+    dtable_count = layout_class_method (this_class, super_class,
                                        method_decl, dtable_count);
 
   TYPE_NVIRTUALS (this_class) = dtable_count;
-
-#ifdef JAVA_USE_HANDLES
-  layout_type (handle_type);
-#endif
 }
 
-/* Return 0 if NAME is equal to STR, -1 if STR is "less" than NAME,
-   and 1 if STR is "greater" than NAME.  */
-
 /* Lay METHOD_DECL out, returning a possibly new value of
    DTABLE_COUNT. Also mangle the method's name. */
 
 tree
-layout_class_method (this_class, super_class, method_decl, dtable_count)
-     tree this_class, super_class, method_decl, dtable_count;
+layout_class_method (tree this_class, tree super_class,
+                    tree method_decl, tree dtable_count)
 {
   tree method_name = DECL_NAME (method_decl);
 
   TREE_PUBLIC (method_decl) = 1;
+  /* Considered external until we know what classes are being
+     compiled into this object file.  */
+  DECL_EXTERNAL (method_decl) = 1;
 
   /* This is a good occasion to mangle the method's name */
   SET_DECL_ASSEMBLER_NAME (method_decl,
@@ -1816,7 +2021,7 @@ layout_class_method (this_class, super_class, method_decl, dtable_count)
     }
   else if (! METHOD_STATIC (method_decl) && !DECL_ARTIFICIAL (method_decl))
     {
-      tree method_sig = 
+      tree method_sig =
        build_java_argument_signature (TREE_TYPE (method_decl));
       tree super_method = lookup_argument_method (super_class, method_name,
                                                  method_sig);
@@ -1825,8 +2030,8 @@ layout_class_method (this_class, super_class, method_decl, dtable_count)
          DECL_VINDEX (method_decl) = DECL_VINDEX (super_method);
          if (DECL_VINDEX (method_decl) == NULL_TREE 
              && !CLASS_FROM_SOURCE_P (this_class))
-           error_with_decl (method_decl,
-                            "non-static method '%s' overrides static method");
+           error ("%Jnon-static method '%D' overrides static method",
+                   method_decl, method_decl);
        }
       else if (! METHOD_FINAL (method_decl)
               && ! METHOD_PRIVATE (method_decl)
@@ -1843,7 +2048,7 @@ layout_class_method (this_class, super_class, method_decl, dtable_count)
 }
 
 void
-register_class ()
+register_class (void)
 {
   /* END does not need to be registered with the garbage collector
      because it always points into the list given by REGISTERED_CLASS,
@@ -1861,54 +2066,278 @@ register_class ()
   end = current;
 }
 
-/* Generate a function that gets called at start-up (static contructor) time,
-   which calls registerClass for all the compiled classes. */
+/* 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.  */
 
 void
-emit_register_classes ()
+emit_register_classes (void)
 {
-  extern tree get_file_function_name PARAMS ((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;
-
-  init_decl = build_decl (FUNCTION_DECL, init_name, init_type);
-  SET_DECL_ASSEMBLER_NAME (init_decl, init_name);
-  TREE_STATIC (init_decl) = 1;
-  current_function_decl = init_decl;
-  DECL_RESULT (init_decl) = build_decl(RESULT_DECL, NULL_TREE, void_type_node);
-  /*  DECL_EXTERNAL (init_decl) = 1;*/
-  TREE_PUBLIC (init_decl) = 1;
-  pushlevel (0);
-  make_decl_rtl (init_decl, NULL);
-  init_function_start (init_decl, input_filename, 0);
-  expand_function_start (init_decl, 0);
-
-  for ( t = registered_class; t; t = TREE_CHAIN (t))
-    emit_library_call (registerClass_libfunc, 0, VOIDmode, 1,
-                      XEXP (DECL_RTL (t), 0), Pmode);
-
-  expand_function_end (input_filename, 0, 0);
-  poplevel (1, 0, 1);
-  { 
-    /* Force generation, even with -O3 or deeper. Gross hack. FIXME */
-    int saved_flag = flag_inline_functions;
-    flag_inline_functions = 0; 
-    rest_of_compilation (init_decl);
-    flag_inline_functions = saved_flag;
-  }
-  current_function_decl = NULL_TREE;
-  assemble_constructor (IDENTIFIER_POINTER (init_name));
+  /* ??? 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.  */
+  if (SUPPORTS_WEAK && targetm.have_named_sections)
+    {
+#ifdef JCR_SECTION_NAME
+      tree t;
+      named_section_flags (JCR_SECTION_NAME, SECTION_WRITE);
+      assemble_align (POINTER_SIZE);
+      for (t = registered_class; t; t = TREE_CHAIN (t))
+       assemble_integer (XEXP (DECL_RTL (t), 0),
+                         POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
+#else
+      abort ();
+#endif
+    }
+  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;
+    }
 }
 
+/* Make a symbol_type (_Jv_MethodSymbol) node for DECL. */
+
+static tree
+build_symbol_entry (tree decl)
+{
+  tree clname, name, signature, sym;
+  
+  clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))));
+  name = build_utf8_ref (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 (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;
+
+  return sym;
+} 
+
+/* Emit a symbol table: used by -findirect-dispatch.  */
+
+tree
+emit_symbol_table (tree name, tree the_table, tree decl_list, tree the_syms_decl, 
+                         tree the_array_element_type)
+{
+  tree method_list, method, table, list, null_symbol;
+  tree table_size, the_array_type;
+  int index;
+  
+  /* 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 = decl_list;
+  list = NULL_TREE;  
+  while (method_list != NULL_TREE)
+    {
+      method = TREE_VALUE (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, 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;  
+  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 (symbols_array_type, list);  
+
+  /* Make it the initial value for otable_syms and emit the decl. */
+  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, NULL, 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_2 (index, 0));
+  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, NULL, 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 (ctable_decl));
+  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 compilation.  */
+void 
+emit_catch_table (void)
+{
+  tree table, table_size, array_type;
+  catch_classes 
+    = tree_cons (NULL, 
+                make_catch_class_record (null_pointer_node, null_pointer_node),
+                catch_classes);
+  catch_classes = nreverse (catch_classes);
+  catch_classes 
+    = tree_cons (NULL, 
+                make_catch_class_record (null_pointer_node, null_pointer_node),
+                catch_classes);
+  table_size = build_index_type (build_int_2 (list_length (catch_classes), 0));
+  array_type 
+    = build_array_type (TREE_TYPE (TREE_TYPE (ctable_decl)), table_size);
+  table = build_decl (VAR_DECL, DECL_NAME (ctable_decl), array_type);
+  DECL_INITIAL (table) = build_constructor (array_type, catch_classes);
+  TREE_STATIC (table) = 1;
+  TREE_READONLY (table) = 1;  
+  rest_of_decl_compilation (table, NULL, 1, 0);
+  ctable_decl = table;
+}
+
 void
-init_class_processing ()
+init_class_processing (void)
 {
-  registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterClass");
-  ggc_add_tree_root (class_roots, sizeof (class_roots) / sizeof (tree));
+  registerClass_libfunc = gen_rtx_SYMBOL_REF (Pmode, "_Jv_RegisterClass");
   fields_ident = get_identifier ("fields");
   info_ident = get_identifier ("info");
-  ggc_add_rtx_root (&registerClass_libfunc, 1);
   gcc_obstack_init (&temporary_obstack);
 }
+\f
+static hashval_t java_treetreehash_hash (const void *);
+static int java_treetreehash_compare (const void *, const void *);
+
+/* A hash table mapping trees to trees.  Used generally.  */
+
+#define JAVA_TREEHASHHASH_H(t) (htab_hash_pointer (t))
+
+static hashval_t
+java_treetreehash_hash (const void *k_p)
+{
+  struct treetreehash_entry *k = (struct treetreehash_entry *) k_p;
+  return JAVA_TREEHASHHASH_H (k->key);
+}
+
+static int
+java_treetreehash_compare (const void * k1_p, const void * k2_p)
+{
+  struct treetreehash_entry * k1 = (struct treetreehash_entry *) k1_p;
+  tree k2 = (tree) k2_p;
+  return (k1->key == k2);
+}
+
+tree 
+java_treetreehash_find (htab_t ht, tree t)
+{
+  struct treetreehash_entry *e;
+  hashval_t hv = JAVA_TREEHASHHASH_H (t);
+  e = htab_find_with_hash (ht, t, hv);
+  if (e == NULL)
+    return NULL;
+  else
+    return e->value;
+}
+
+tree *
+java_treetreehash_new (htab_t ht, tree t)
+{
+  void **e;
+  struct treetreehash_entry *tthe;
+  hashval_t hv = JAVA_TREEHASHHASH_H (t);
+
+  e = htab_find_slot_with_hash (ht, t, hv, INSERT);
+  if (*e == NULL)
+    {
+      tthe = (*ht->alloc_f) (1, sizeof (*tthe));
+      tthe->key = t;
+      *e = tthe;
+    }
+  else
+    tthe = (struct treetreehash_entry *) *e;
+  return &tthe->value;
+}
+
+htab_t
+java_treetreehash_create (size_t size, int gc)
+{
+  if (gc)
+    return htab_create_ggc (size, java_treetreehash_hash,
+                           java_treetreehash_compare, NULL);
+  else
+    return htab_create_alloc (size, java_treetreehash_hash,
+                             java_treetreehash_compare, free, xcalloc, free);
+}
+
+#include "gt-java-class.h"