OSDN Git Service

In gcc/java:
[pf3gnuchains/gcc-fork.git] / gcc / java / class.c
index a441040..ae715f1 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions related to building classes and their related objects.
-   Copyright (C) 1996, 97-99, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -35,6 +35,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc.  */
 #include "toplev.h"
 #include "output.h"
 #include "parse.h"
+#include "ggc.h"
 
 static tree mangle_class_field PARAMS ((tree class));
 static tree make_method_value PARAMS ((tree));
@@ -48,11 +49,17 @@ static tree mangle_static_field PARAMS ((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 int utf8_cmp PARAMS ((const unsigned char *, int, const char *));
+static int cxx_keyword_p PARAMS ((const char *, int));
+static tree mangle_field PARAMS ((tree, tree));
 
 static rtx registerClass_libfunc;
 
 extern struct obstack permanent_obstack;
-extern struct obstack temporary_obstack;
+struct obstack temporary_obstack;
 
 /* The compiler generates different code depending on whether or not
    it can assume certain classes have been compiled down to native
@@ -265,7 +272,6 @@ tree
 make_class ()
 {
   tree type;
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   type = make_node (RECORD_TYPE);
 #ifdef JAVA_USE_HANDLES
   tree field1 = build_decl (FIELD_DECL, get_identifier ("obj"),
@@ -282,7 +288,7 @@ make_class ()
 #else
   TYPE_BINFO (type) = make_tree_vec (6);
 #endif
-  pop_obstacks ();
+  MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type);
 
   return type;
 }
@@ -316,10 +322,9 @@ push_class (class_type, class_name)
      tree class_type, class_name;
 {
   tree decl, signature;
-  char *save_input_filename = input_filename;
+  const char *save_input_filename = input_filename;
   int save_lineno = lineno;
   tree source_name = identifier_subst (class_name, "", '.', '/', ".java");
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   CLASS_P (class_type) = 1;
   input_filename = IDENTIFIER_POINTER (source_name);
   lineno = 0;
@@ -345,7 +350,6 @@ push_class (class_type, class_name)
   }
 #endif
 
-  pop_obstacks ();
   return decl;
 }
 
@@ -376,7 +380,6 @@ set_super_info (access_flags, this_class, super_class, interfaces_count)
   if (super_class)
     total_supers++;
 
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   TYPE_BINFO_BASETYPES (this_class) = make_tree_vec (total_supers);
   if (super_class)
     {
@@ -388,13 +391,15 @@ set_super_info (access_flags, this_class, super_class, interfaces_count)
        = super_binfo;
       CLASS_HAS_SUPER (this_class) = 1;
     }
-  pop_obstacks ();
-  
+
   if (access_flags & ACC_PUBLIC)    CLASS_PUBLIC (class_decl) = 1;
   if (access_flags & ACC_FINAL)     CLASS_FINAL (class_decl) = 1;
   if (access_flags & ACC_SUPER)     CLASS_SUPER (class_decl) = 1;
   if (access_flags & ACC_INTERFACE) CLASS_INTERFACE (class_decl) = 1;
   if (access_flags & ACC_ABSTRACT)  CLASS_ABSTRACT (class_decl) = 1;
+  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;
 }
 
 /* Return length of inheritance chain of CLAS, where java.lang.Object is 0,
@@ -460,6 +465,51 @@ inherits_from_p (type1, type2)
   return 0;
 }
 
+/* Return a 1 iff TYPE1 is an enclosing context for TYPE2 */
+
+int
+enclosing_context_p (type1, type2)
+     tree type1, type2;
+{
+  if (!INNER_CLASS_TYPE_P (type2))
+    return 0;
+
+  for (type2 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type2)));
+       type2; 
+       type2 = (INNER_CLASS_TYPE_P (type2) ?
+               TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type2))) : NULL_TREE))
+    {
+      if (type2 == type1)
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Return 1 iff there exists a common enclosing context between TYPE1
+   and TYPE2.  */
+
+int common_enclosing_context_p (type1, type2)
+     tree type1, type2;
+{
+  if (!PURE_INNER_CLASS_TYPE_P (type1) || !PURE_INNER_CLASS_TYPE_P (type2))
+    return 0;
+  
+  for (type1 = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1))); type1; 
+       type1 = (PURE_INNER_CLASS_TYPE_P (type1) ?
+               TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type1))) : NULL_TREE))
+    {
+      tree current;
+      for (current = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (type2))); current;
+          current = (PURE_INNER_CLASS_TYPE_P (current) ?
+                     TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current))) : 
+                     NULL_TREE))
+       if (type1 == current)
+         return 1;
+    }
+  return 0;
+}
+
 static void
 add_interface_do (basetype_vec, interface_class, i)
      tree basetype_vec, interface_class;
@@ -548,6 +598,43 @@ build_java_method_type (fntype, this_class, access_flags)
   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 it's pointer value,
+   comparison is direct. */
+
+unsigned long
+java_hash_hash_tree_node (k)
+     hash_table_key k;
+{
+  return (long) k;
+}
+
+boolean
+java_hash_compare_tree_node (k1, k2)
+     hash_table_key k1;
+     hash_table_key k2;
+{
+  return ((char*) k1 == (char*) k2);
+}
+
 tree
 add_method_1 (handle_class, access_flags, name, function_type)
      tree handle_class;
@@ -556,7 +643,6 @@ add_method_1 (handle_class, access_flags, name, function_type)
      tree function_type;
 {
   tree method_type, fndecl;
-  push_obstacks (&permanent_obstack, &permanent_obstack);
 
   method_type = build_java_method_type (function_type,
                                        handle_class, access_flags);
@@ -565,18 +651,25 @@ add_method_1 (handle_class, access_flags, name, function_type)
   DECL_CONTEXT (fndecl) = handle_class;
 
   DECL_LANG_SPECIFIC (fndecl)
-    = (struct lang_decl *) permalloc (sizeof (struct lang_decl));
-  bzero ((PTR) DECL_LANG_SPECIFIC (fndecl), sizeof (struct lang_decl));
+    = (struct lang_decl *) ggc_alloc_cleared (sizeof (struct lang_decl));
+
+  /* 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);
 
   TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class);
   TYPE_METHODS (handle_class) = fndecl;
-  pop_obstacks ();
 
   if (access_flags & ACC_PUBLIC) METHOD_PUBLIC (fndecl) = 1;
   if (access_flags & ACC_PROTECTED) METHOD_PROTECTED (fndecl) = 1;
   if (access_flags & ACC_PRIVATE)
     METHOD_PRIVATE (fndecl) = DECL_INLINE (fndecl) = 1;
-  if (access_flags & ACC_NATIVE) METHOD_NATIVE (fndecl) = 1;
+  if (access_flags & ACC_NATIVE)
+    {
+      METHOD_NATIVE (fndecl) = 1;
+      DECL_EXTERNAL (fndecl) = 1;
+    }
   if (access_flags & ACC_STATIC) 
     METHOD_STATIC (fndecl) = DECL_INLINE (fndecl) = 1;
   if (access_flags & ACC_FINAL) 
@@ -601,13 +694,11 @@ add_method (this_class, access_flags, name, 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);
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   if (sig[0] != '(')
     fatal ("bad method signature");
   function_type = get_type_from_signature (method_sig);
   fndecl = add_method_1 (handle_class, access_flags, name, function_type);
   set_java_signature (TREE_TYPE (fndecl), method_sig);
-  pop_obstacks ();
   return fndecl;
 }
 
@@ -620,10 +711,7 @@ add_field (class, name, field_type, flags)
 {
   int is_static = (flags & ACC_STATIC) != 0;
   tree field;
-  /* Push the obstack of field_type ? FIXME */
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   field = build_decl (is_static ? VAR_DECL : FIELD_DECL, name, field_type);
-  pop_obstacks ();
   TREE_CHAIN (field) = TYPE_FIELDS (class);
   TYPE_FIELDS (class) = field;
   DECL_CONTEXT (field) = class;
@@ -719,7 +807,6 @@ build_utf8_ref (name)
   if (ref != NULL_TREE)
     return ref;
 
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   ctype = make_node (RECORD_TYPE);
   str_type = build_prim_array_type (unsigned_byte_type_node,
                                    name_len + 1); /* Allow for final '\0'. */
@@ -771,7 +858,6 @@ build_utf8_ref (name)
   make_decl_rtl (decl, (char*) 0, 1);
   ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl);
   IDENTIFIER_UTF8_REF (name) = ref;
-  pop_obstacks ();
   return ref;
 }
 
@@ -797,9 +883,9 @@ build_class_ref (type)
          decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
          if (decl == NULL_TREE)
            {
-             push_obstacks (&permanent_obstack, &permanent_obstack);
              decl = build_decl (VAR_DECL, decl_name, class_type_node);
              DECL_SIZE (decl) = TYPE_SIZE (class_type_node);
+             DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (class_type_node);
              TREE_STATIC (decl) = 1;
              TREE_PUBLIC (decl) = 1;
              DECL_IGNORED_P (decl) = 1;
@@ -809,7 +895,6 @@ build_class_ref (type)
              pushdecl_top_level (decl);
              if (is_compiled == 1)
                DECL_EXTERNAL (decl) = 1;
-             pop_obstacks ();
            }
        }
       else
@@ -855,7 +940,6 @@ build_class_ref (type)
          decl = IDENTIFIER_GLOBAL_VALUE (decl_name);
          if (decl == NULL_TREE)
            {
-             push_obstacks (&permanent_obstack, &permanent_obstack);
              decl = build_decl (VAR_DECL, decl_name, class_type_node);
              TREE_STATIC (decl) = 1;
              TREE_PUBLIC (decl) = 1;
@@ -863,7 +947,6 @@ build_class_ref (type)
              pushdecl_top_level (decl);
              if (is_compiled == 1)
                DECL_EXTERNAL (decl) = 1;
-             pop_obstacks ();
            }
        }
 
@@ -874,11 +957,9 @@ build_class_ref (type)
     {
       int index;
       tree cl;
-      push_obstacks (&permanent_obstack, &permanent_obstack);
       index = alloc_class_constant (type);
       cl = build_ref_from_constant_pool (index); 
       TREE_TYPE (cl) = promote_type (class_ptr_type);
-      pop_obstacks ();
       return cl;
     }
 }
@@ -893,9 +974,7 @@ build_static_field_ref (fdecl)
     {
       if (DECL_RTL (fdecl) == 0)
        {
-         push_obstacks (&permanent_obstack, &permanent_obstack);
          make_decl_rtl (fdecl, NULL, 1);
-         pop_obstacks ();
          if (is_compiled == 1)
            DECL_EXTERNAL (fdecl) = 1;
        }
@@ -904,8 +983,7 @@ build_static_field_ref (fdecl)
   else
     {
       /* Compile as:
-       * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr
-       */
+       * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */
       static tree fields_ident = NULL_TREE;
       static tree info_ident = NULL_TREE;
       tree ref = build_class_ref (fclass);
@@ -913,9 +991,15 @@ build_static_field_ref (fdecl)
       int field_index = 0;
       ref = build1 (INDIRECT_REF, class_type_node, ref);
       if (fields_ident == NULL_TREE)
-       fields_ident = get_identifier ("fields");
+       {
+         fields_ident = get_identifier ("fields");
+         ggc_add_tree_root (&fields_ident, 1);
+       }
       if (info_ident == NULL_TREE)
-       info_ident = get_identifier ("info");
+       {
+         info_ident = get_identifier ("info");
+         ggc_add_tree_root (&info_ident, 1);
+       }
       ref = build (COMPONENT_REF, field_ptr_type_node, ref,
                   lookup_field (&class_type_node, fields_ident));
 
@@ -976,6 +1060,12 @@ get_access_flags_from_decl (decl)
        access_flags |= ACC_INTERFACE;
       if (CLASS_ABSTRACT (decl))
        access_flags |= ACC_ABSTRACT;
+      if (CLASS_STATIC (decl))
+       access_flags |= ACC_STATIC;
+      if (CLASS_PRIVATE (decl))
+       access_flags |= ACC_PRIVATE;
+      if (CLASS_PROTECTED (decl))
+       access_flags |= ACC_PROTECTED;
       return access_flags;
     }
   if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -1007,10 +1097,11 @@ static tree
 make_field_value (fdecl)
   tree fdecl;
 {
-  tree finit, info;
-  int bsize, flags;
+  tree finit;
+  int flags;
   tree type = TREE_TYPE (fdecl);
   int resolved = is_compiled_class (type);
+
   START_RECORD_CONSTRUCTOR (finit, field_type_node);
   PUSH_FIELD_VALUE (finit, "name", build_utf8_ref (DECL_NAME (fdecl)));
   if (resolved)
@@ -1018,33 +1109,30 @@ make_field_value (fdecl)
   else
     {
       tree signature = build_java_signature (type);
+
       type = build_utf8_ref (unmangle_classname 
-                            (IDENTIFIER_POINTER(signature),
-                             IDENTIFIER_LENGTH(signature)));
+                            (IDENTIFIER_POINTER (signature),
+                             IDENTIFIER_LENGTH (signature)));
     }
   PUSH_FIELD_VALUE (finit, "type", type);
+
   flags = get_access_flags_from_decl (fdecl);
   if (! resolved)
     flags |= 0x8000 /* FIELD_UNRESOLVED_FLAG */;
+
   PUSH_FIELD_VALUE (finit, "accflags", build_int_2 (flags, 0));
-  bsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (fdecl))) / BITS_PER_UNIT;
-  PUSH_FIELD_VALUE (finit, "bsize", build_int_2 (bsize, 0));
-  if (FIELD_STATIC (fdecl))
-    {
-      tree cfield = TREE_CHAIN (TYPE_FIELDS(field_info_union_node));
-      tree faddr = build_address_of (build_static_field_ref (fdecl));
-      info = build (CONSTRUCTOR, field_info_union_node, NULL_TREE,
-                   build_tree_list (cfield, faddr));
-    }
-  else
-    {
-      int boffset
-       = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (fdecl)) / BITS_PER_UNIT;
-      info = build (CONSTRUCTOR, field_info_union_node, NULL_TREE,
-                   build_tree_list (TYPE_FIELDS(field_info_union_node),
-                                    build_int_2 (boffset, 0)));
-    }
-  PUSH_FIELD_VALUE (finit, "info", info);
+  PUSH_FIELD_VALUE (finit, "bsize", TYPE_SIZE_UNIT (TREE_TYPE (fdecl)));
+
+  PUSH_FIELD_VALUE
+    (finit, "info",
+     build (CONSTRUCTOR, field_info_union_node, NULL_TREE,
+           build_tree_list
+           ((FIELD_STATIC (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))
+             : byte_position (fdecl)))));
 
   FINISH_RECORD_CONSTRUCTOR (finit);
   return finit;
@@ -1087,29 +1175,28 @@ get_dispatch_vector (type)
   tree vtable = TYPE_VTABLE (type);
   if (vtable == NULL)
     {
-      int i;
+      HOST_WIDE_INT i;
       tree method;
       tree super = CLASSTYPE_SUPER (type);
-      int nvirtuals = TREE_INT_CST_LOW (TYPE_NVIRTUALS (type));
+      HOST_WIDE_INT nvirtuals = tree_low_cst (TYPE_NVIRTUALS (type), 0);
       vtable = make_tree_vec (nvirtuals);
       TYPE_VTABLE (type) = vtable;
       if (super != NULL_TREE)
        {
          tree super_vtable = get_dispatch_vector (super);
-         for ( i = TREE_INT_CST_LOW (TYPE_NVIRTUALS (super));  --i >= 0; )
+
+         for (i = tree_low_cst (TYPE_NVIRTUALS (super), 0); --i >= 0; )
            TREE_VEC_ELT (vtable, i) = TREE_VEC_ELT (super_vtable, i);
        }
+
       for (method = TYPE_METHODS (type);  method != NULL_TREE;
           method = TREE_CHAIN (method))
-       {
-         if (DECL_VINDEX (method) != NULL_TREE
-             && TREE_CODE (DECL_VINDEX (method)) == INTEGER_CST)
-           {
-             TREE_VEC_ELT (vtable, TREE_INT_CST_LOW (DECL_VINDEX (method)))
-               = 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;
     }
+
   return vtable;
 }
 
@@ -1117,6 +1204,7 @@ static tree
 get_dispatch_table (type, this_class_addr)
      tree type, this_class_addr;
 {
+  int abstract_p = CLASS_ABSTRACT (TYPE_NAME (type));
   tree vtable = get_dispatch_vector (type);
   int i;
   tree list = NULL_TREE;
@@ -1125,15 +1213,27 @@ get_dispatch_table (type, this_class_addr)
     {
       tree method = TREE_VEC_ELT (vtable, i);
       if (METHOD_ABSTRACT (method))
-       warning_with_decl (method, "abstract method in non-abstract class");
-      if (DECL_RTL (method) == 0)
-       make_decl_rtl (method, NULL, 1);
+       {
+         if (! abstract_p)
+           warning_with_decl (method,
+                              "abstract method in non-abstract class");
+         method = null_pointer_node;
+       }
+      else
+       {
+         if (DECL_RTL (method) == 0)
+           make_decl_rtl (method, NULL, 1);
+         method = build1 (ADDR_EXPR, nativecode_ptr_type_node, method);
+       }
       list = tree_cons (NULL_TREE /*DECL_VINDEX (method) + 2*/,
-                       build1 (ADDR_EXPR, nativecode_ptr_type_node, method),
-                       list);
+                       method, list);
     }
-  /* Dummy entry for compatibility with G++ -fvtable-thunks. */
-  list = tree_cons (integer_zero_node, null_pointer_node, 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),
@@ -1240,7 +1340,7 @@ make_class_data (type)
   rest_of_decl_compilation (methods_decl, (char*) 0, 1, 0);
 
   if (assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl)))
-      && ! CLASS_ABSTRACT (type_decl) && ! CLASS_INTERFACE (type_decl))
+      && ! CLASS_INTERFACE (type_decl))
     {
       tree dtable = get_dispatch_table (type, this_class_addr);
       dtable_decl = build_dtable_decl (type);
@@ -1303,13 +1403,10 @@ make_class_data (type)
   constant_pool_constructor = build_constants_constructor ();
 
   START_RECORD_CONSTRUCTOR (temp, object_type_node);
-#if 0
-  PUSH_FIELD_VALUE (temp, "vtable", NULL_TREE);
-#else
   PUSH_FIELD_VALUE (temp, "vtable",
                    build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl));
-#endif
-  PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node);
+  if (! flag_hash_synchronization)
+    PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node);
   FINISH_RECORD_CONSTRUCTOR (temp);
   START_RECORD_CONSTRUCTOR (cons, class_type_node);
   PUSH_SUPER_VALUE (cons, temp);
@@ -1341,6 +1438,10 @@ make_class_data (type)
   PUSH_FIELD_VALUE (cons, "state", integer_zero_node);
 
   PUSH_FIELD_VALUE (cons, "thread", null_pointer_node);
+  PUSH_FIELD_VALUE (cons, "depth", integer_zero_node);
+  PUSH_FIELD_VALUE (cons, "ancestors", null_pointer_node);
+  PUSH_FIELD_VALUE (cons, "idt", null_pointer_node);
+  PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node);
 
   FINISH_RECORD_CONSTRUCTOR (cons);
 
@@ -1379,9 +1480,7 @@ finish_class ()
              || ! METHOD_PRIVATE (method)
              || saw_native_method)
            {
-             temporary_allocation ();
              output_inline_function (method);
-             permanent_allocation (1);
              /* Scan the list again to see if there are any earlier
                  methods to emit. */
              method = type_methods;
@@ -1415,8 +1514,7 @@ is_compiled_class (class)
   if (class == current_class)
     return 2;
 
-  seen_in_zip = (TYPE_LANG_SPECIFIC (class) && TYPE_LANG_SPECIFIC (class)->jcf
-                && TYPE_LANG_SPECIFIC (class)->jcf->seen_in_zip);
+  seen_in_zip = (TYPE_JCF (class) && TYPE_JCF (class)->seen_in_zip);
   if (CLASS_FROM_CURRENTLY_COMPILED_SOURCE_P (class) || seen_in_zip)
     {
       /* The class was seen in the current ZIP file and will be
@@ -1507,29 +1605,13 @@ append_gpp_mangled_type (obstack, type)
     }
 }
 
-/* Build the mangled name of the `class' field.  */
+/* Build the mangled name of a field, given the class name and the
+   field name.  */
 
 static tree
-mangle_class_field (class)
-     tree class;
+mangle_field (class, name)
+     tree class, name;
 {
-  tree name;
-  obstack_grow (&temporary_obstack, "_CL_", 4);
-  append_gpp_mangled_type (&temporary_obstack, class);
-  obstack_1grow (&temporary_obstack, '\0');
-  name = get_identifier (obstack_base (&temporary_obstack));
-  obstack_free (&temporary_obstack, obstack_base (&temporary_obstack));
-  return name;
-}
-
-/* Build the mangled (assembly-level) name of the static field FIELD. */
-
-static tree
-mangle_static_field (field)
-     tree field;
-{
-  tree class = DECL_CONTEXT (field);
-  tree name = DECL_NAME (field);
   int encoded_len;
 #if ! defined (NO_DOLLAR_IN_LABEL) || ! defined (NO_DOT_IN_LABEL)
   obstack_1grow (&temporary_obstack, '_');
@@ -1564,25 +1646,72 @@ mangle_static_field (field)
                    IDENTIFIER_POINTER (name),
                    IDENTIFIER_LENGTH (name));
     }
+
+  /* Mangle C++ keywords by appending a `$'.  */
+  /* FIXME: NO_DOLLAR_IN_LABEL */
+  if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
+    obstack_grow (&temporary_obstack, "$", 1);
+
   obstack_1grow (&temporary_obstack, '\0');
   name = get_identifier (obstack_base (&temporary_obstack));
   obstack_free (&temporary_obstack, obstack_base (&temporary_obstack));
   return name;
 }
 
+/* Build the mangled name of the `class' field.  */
+
+static tree
+mangle_class_field (class)
+     tree class;
+{
+  /* We know that we can use `class$' to mangle the class object,
+     because `class' is a reserved word in Java and thus can't appear
+     as a field or method name.  */
+  return mangle_field (class, get_identifier ("class$"));
+}
+
+/* Build the mangled (assembly-level) name of the static field FIELD. */
+
+static tree
+mangle_static_field (field)
+     tree field;
+{
+  return mangle_field (DECL_CONTEXT (field), DECL_NAME (field));
+}
+
 /* Build a VAR_DECL for the dispatch table (vtable) for class TYPE. */
 
 tree
 build_dtable_decl (type)
      tree type;
 {
-  tree name;
+  tree name, 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
+     TYPE. */
+  if (current_class == type)
+    {
+      tree dummy = NULL_TREE, aomt, n;
+
+      dtype = make_node (RECORD_TYPE);
+      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);
+      layout_type (dtype);
+    }
+  else
+    dtype = dtable_type;
+
   obstack_grow (&temporary_obstack, "__vt_", 5);
   append_gpp_mangled_type (&temporary_obstack, type);
   obstack_1grow (&temporary_obstack, '\0');
   name = get_identifier (obstack_base (&temporary_obstack));
   obstack_free (&temporary_obstack, obstack_base (&temporary_obstack));
-  return build_decl (VAR_DECL, name, dtable_type);
+  return build_decl (VAR_DECL, name, dtype);
 }
 
 /* Pre-pend the TYPE_FIELDS of THIS_CLASS with a dummy FIELD_DECL for the
@@ -1593,13 +1722,15 @@ push_super_field (this_class, super_class)
      tree this_class, super_class;
 {
   tree base_decl;
-  push_obstacks (&permanent_obstack, &permanent_obstack);
+  /* Don't insert the field if we're just re-laying the class out. */ 
+  if (TYPE_FIELDS (this_class) && !DECL_NAME (TYPE_FIELDS (this_class)))
+    return;
   base_decl = build_decl (FIELD_DECL, NULL_TREE, super_class);
-  pop_obstacks ();
   DECL_IGNORED_P (base_decl) = 1;
   TREE_CHAIN (base_decl) = TYPE_FIELDS (this_class);
   TYPE_FIELDS (this_class) = base_decl;
   DECL_SIZE (base_decl) = TYPE_SIZE (super_class);
+  DECL_SIZE_UNIT (base_decl) = TYPE_SIZE_UNIT (super_class);
 }
 
 /* Handle the different manners we may have to lay out a super class.  */
@@ -1611,8 +1742,7 @@ maybe_layout_super_class (super_class, this_class)
 {
   if (TREE_CODE (super_class) == RECORD_TYPE)
     {
-      if (!CLASS_LOADED_P (super_class) 
-         && CLASS_FROM_SOURCE_P (super_class))
+      if (!CLASS_LOADED_P (super_class) && CLASS_FROM_SOURCE_P (super_class))
        safe_layout_class (super_class);
       if (!CLASS_LOADED_P (super_class))
        load_class (super_class, 1);
@@ -1625,7 +1755,8 @@ maybe_layout_super_class (super_class, this_class)
        super_class = TREE_TYPE (super_class);
       else
        {
-         super_class = do_resolve_class (super_class, NULL_TREE, this_class);
+         super_class = do_resolve_class (NULL_TREE, /* FIXME? */
+                                         super_class, NULL_TREE, this_class);
          if (!super_class)
            return NULL_TREE;   /* FIXME, NULL_TREE not checked by caller. */
          super_class = TREE_TYPE (super_class);
@@ -1641,15 +1772,58 @@ void
 layout_class (this_class)
      tree this_class;
 {
+  static tree list = NULL_TREE;
+  static int initialized_p;
   tree super_class = CLASSTYPE_SUPER (this_class);
   tree field;
+  
+  /* Register LIST with the garbage collector.  */
+  if (!initialized_p)
+    {
+      ggc_add_tree_root (&list, 1);
+      initialized_p = 1;
+    }
+
+  list = tree_cons (this_class, NULL_TREE, 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));
+
+      for (current = TREE_CHAIN (list); current; 
+          current = TREE_CHAIN (current))
+       {
+         tree decl = TYPE_NAME (TREE_PURPOSE (current));
+         sprintf (buffer, "\n  which inherits from `%s' (%s:%d)",
+                  IDENTIFIER_POINTER (DECL_NAME (decl)),
+                  DECL_SOURCE_FILE (decl),
+                  DECL_SOURCE_LINE (decl));
+         obstack_grow (&temporary_obstack, buffer, strlen (buffer));
+       }
+      obstack_1grow (&temporary_obstack, '\0');
+      report = obstack_finish (&temporary_obstack);
+      cyclic_inheritance_report = ggc_strdup (report);
+      obstack_free (&temporary_obstack, report);
+      TYPE_SIZE (this_class) = error_mark_node;
+      return;
+    }
+  CLASS_BEING_LAIDOUT (this_class) = 1;
 
   if (super_class)
     {
-      super_class = maybe_layout_super_class (super_class, this_class);
-      if (TREE_CODE (TYPE_SIZE (super_class)) == ERROR_MARK)
+      tree maybe_super_class 
+       = maybe_layout_super_class (super_class, this_class);
+      if (maybe_super_class == NULL
+         || TREE_CODE (TYPE_SIZE (maybe_super_class)) == ERROR_MARK)
        {
          TYPE_SIZE (this_class) = error_mark_node;
+         CLASS_BEING_LAIDOUT (this_class) = 0;
+         list = TREE_CHAIN (list);
          return;
        }
       if (TYPE_SIZE (this_class) == NULL_TREE)
@@ -1668,9 +1842,41 @@ 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. */
+  if (!CLASS_FROM_SOURCE_P (this_class))
+    {
+      tree basetype_vec = TYPE_BINFO_BASETYPES (this_class);
+
+      if (basetype_vec)
+       {
+         int n = TREE_VEC_LENGTH (basetype_vec) - 1;
+         int i;
+         for (i = n; i > 0; i--)
+           {
+             tree vec_elt = TREE_VEC_ELT (basetype_vec, i);
+             tree super_interface = BINFO_TYPE (vec_elt);
+
+             tree maybe_super_interface 
+               = maybe_layout_super_class (super_interface, NULL_TREE);
+             if (maybe_super_interface == NULL
+                 || TREE_CODE (TYPE_SIZE (maybe_super_interface)) == ERROR_MARK)
+               {
+                 TYPE_SIZE (this_class) = error_mark_node;
+                 CLASS_BEING_LAIDOUT (this_class) = 0;
+                 list = TREE_CHAIN (list);
+                 return;
+               }
+           }
+       }
+    }
+
   /* 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;
+  list = TREE_CHAIN (list);
 }
 
 void
@@ -1683,7 +1889,6 @@ layout_class_methods (this_class)
   if (TYPE_NVIRTUALS (this_class))
     return;
 
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   super_class = CLASSTYPE_SUPER (this_class);
   handle_type = CLASS_TO_HANDLE_TYPE (this_class);
 
@@ -1696,7 +1901,7 @@ layout_class_methods (this_class)
     }
   else
     dtable_count = integer_zero_node;
-  
+
   TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type));
 
   for (method_decl = TYPE_METHODS (handle_type);
@@ -1709,7 +1914,105 @@ layout_class_methods (this_class)
 #ifdef JAVA_USE_HANDLES
   layout_type (handle_type);
 #endif
-  pop_obstacks ();
+}
+
+/* A sorted list of all C++ keywords.  */
+
+static const char *cxx_keywords[] =
+{
+  "asm",
+  "auto",
+  "bool",
+  "const_cast",
+  "delete",
+  "dynamic_cast",
+  "enum",
+  "explicit",
+  "extern",
+  "friend",
+  "inline",
+  "mutable",
+  "namespace",
+  "overload",
+  "register",
+  "reinterpret_cast",
+  "signed",
+  "sizeof",
+  "static_cast",
+  "struct",
+  "template",
+  "typedef",
+  "typeid",
+  "typename",
+  "typenameopt",
+  "union",
+  "unsigned",
+  "using",
+  "virtual",
+  "volatile",
+  "wchar_t"
+};
+
+/* Return 0 if NAME is equal to STR, -1 if STR is "less" than NAME,
+   and 1 if STR is "greater" than NAME.  */
+
+static int
+utf8_cmp (str, length, name)
+     const unsigned char *str;
+     int length;
+     const char *name;
+{
+  const unsigned char *limit = str + length;
+  int i;
+
+  for (i = 0; name[i]; ++i)
+    {
+      int ch = UTF8_GET (str, limit);
+      if (ch != name[i])
+       return ch - name[i];
+    }
+
+  return str == limit ? 0 : 1;
+}
+
+/* Return true if NAME is a C++ keyword.  */
+
+static int
+cxx_keyword_p (name, length)
+     const char *name;
+     int length;
+{
+  int last = ARRAY_SIZE (cxx_keywords);
+  int first = 0;
+  int mid = (last + first) / 2;
+  int old = -1;
+
+  for (mid = (last + first) / 2;
+       mid != old;
+       old = mid, mid = (last + first) / 2)
+    {
+      int kwl = strlen (cxx_keywords[mid]);
+      int min_length = kwl > length ? length : kwl;
+      int r = utf8_cmp (name, min_length, cxx_keywords[mid]);
+
+      if (r == 0)
+       {
+         int i;
+         /* We've found a match if all the remaining characters are
+            `$'.  */
+         for (i = min_length; i < length && name[i] == '$'; ++i)
+           ;
+         if (i == length)
+           return 1;
+         r = 1;
+       }
+
+      if (r < 0)
+       last = mid;
+      else
+       first = mid;
+    }
+  return 0;
 }
 
 /* Lay METHOD_DECL out, returning a possibly new value of
@@ -1729,8 +2032,7 @@ layout_class_method (this_class, super_class, method_decl, dtable_count)
   if (method_name_is_wfl)
     method_name = java_get_real_method_name (method_decl);
 
-  if (method_name != init_identifier_node 
-      && method_name != finit_identifier_node)
+  if (!ID_INIT_P (method_name) && !ID_FINIT_P (method_name))
     {
       int encoded_len
        = unicode_mangling_length (IDENTIFIER_POINTER (method_name), 
@@ -1748,10 +2050,16 @@ layout_class_method (this_class, super_class, method_decl, dtable_count)
                        IDENTIFIER_POINTER (method_name),
                        IDENTIFIER_LENGTH (method_name));
        }
+
+      /* Mangle C++ keywords by appending a `$'.  */
+      /* FIXME: NO_DOLLAR_IN_LABEL */
+      if (cxx_keyword_p (IDENTIFIER_POINTER (method_name),
+                        IDENTIFIER_LENGTH (method_name)))
+       obstack_grow (&temporary_obstack, "$", 1);
     }
-      
+
   obstack_grow (&temporary_obstack, "__", 2);
-  if (method_name == finit_identifier_node)
+  if (ID_FINIT_P (method_name))
     obstack_grow (&temporary_obstack, "finit", 5);
   append_gpp_mangled_type (&temporary_obstack, this_class);
   TREE_PUBLIC (method_decl) = 1;
@@ -1813,11 +2121,11 @@ layout_class_method (this_class, super_class, method_decl, dtable_count)
      it's an interface method that isn't clinit. */
   if (! METHOD_ABSTRACT (method_decl) 
       || (CLASS_INTERFACE (TYPE_NAME (this_class)) 
-         && (IS_CLINIT (method_decl))))
+         && (DECL_CLINIT_P (method_decl))))
     make_function_rtl (method_decl);
   obstack_free (&temporary_obstack, asm_name);
 
-  if (method_name == init_identifier_node)
+  if (ID_INIT_P (method_name))
     {
       const char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class)));
       for (ptr = p; *ptr; )
@@ -1862,9 +2170,11 @@ layout_class_method (this_class, super_class, method_decl, dtable_count)
               && dtable_count)
        {
          DECL_VINDEX (method_decl) = dtable_count;
-         dtable_count = build_int_2 (1+TREE_INT_CST_LOW (dtable_count), 0);
+         dtable_count = fold (build (PLUS_EXPR, integer_type_node,
+                                     dtable_count, integer_one_node));
        }
     }
+
   return dtable_count;
 }
 
@@ -1873,6 +2183,9 @@ static tree registered_class = NULL_TREE;
 void
 register_class ()
 {
+  /* END does not need to be registered with the garbage collector
+     because it always points into the list given by REGISTERED_CLASS,
+     and that variable is registered with the collector.  */
   static tree end;
   tree node    = TREE_OPERAND (build_class_ref (current_class), 0);
   tree current = copy_node (node);
@@ -1931,4 +2244,7 @@ void
 init_class_processing ()
 {
   registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterClass");
+  ggc_add_tree_root (&registered_class, 1);
+  ggc_add_rtx_root (&registerClass_libfunc, 1);
+  gcc_obstack_init (&temporary_obstack);
 }