OSDN Git Service

In gcc/java:
[pf3gnuchains/gcc-fork.git] / gcc / java / class.c
index 21232e7..ae715f1 100644 (file)
@@ -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));
@@ -51,11 +52,14 @@ 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
@@ -268,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"),
@@ -286,7 +289,6 @@ make_class ()
   TYPE_BINFO (type) = make_tree_vec (6);
 #endif
   MAYBE_CREATE_TYPE_TYPE_LANG_SPECIFIC (type);
-  pop_obstacks ();
 
   return type;
 }
@@ -323,7 +325,6 @@ push_class (class_type, class_name)
   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;
@@ -349,7 +350,6 @@ push_class (class_type, class_name)
   }
 #endif
 
-  pop_obstacks ();
   return decl;
 }
 
@@ -380,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)
     {
@@ -392,7 +391,6 @@ 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;
@@ -400,6 +398,8 @@ set_super_info (access_flags, this_class, super_class, interfaces_count)
   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,
@@ -486,6 +486,30 @@ enclosing_context_p (type1, type2)
   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;
@@ -619,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);
@@ -628,8 +651,7 @@ 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),
@@ -638,7 +660,6 @@ add_method_1 (handle_class, access_flags, name, function_type)
 
   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;
@@ -673,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;
 }
 
@@ -692,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;
@@ -791,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'. */
@@ -843,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;
 }
 
@@ -869,7 +883,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);
              DECL_SIZE (decl) = TYPE_SIZE (class_type_node);
              DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (class_type_node);
@@ -882,7 +895,6 @@ build_class_ref (type)
              pushdecl_top_level (decl);
              if (is_compiled == 1)
                DECL_EXTERNAL (decl) = 1;
-             pop_obstacks ();
            }
        }
       else
@@ -928,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;
@@ -936,7 +947,6 @@ build_class_ref (type)
              pushdecl_top_level (decl);
              if (is_compiled == 1)
                DECL_EXTERNAL (decl) = 1;
-             pop_obstacks ();
            }
        }
 
@@ -947,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;
     }
 }
@@ -966,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;
        }
@@ -985,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));
 
@@ -1050,6 +1062,10 @@ get_access_flags_from_decl (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)
@@ -1188,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;
@@ -1196,17 +1213,26 @@ 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.  When
      using the Boehm GC we sometimes stash a GC type descriptor
-     there.  */
-  list = tree_cons (integer_zero_node, get_boehm_type_descriptor (type),
+     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,
@@ -1314,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);
@@ -1415,6 +1441,7 @@ make_class_data (type)
   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);
 
@@ -1453,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;
@@ -1580,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, '_');
@@ -1637,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
@@ -1669,9 +1725,7 @@ push_super_field (this_class, super_class)
   /* 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;
-  push_obstacks (&permanent_obstack, &permanent_obstack);
   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;
@@ -1688,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);
@@ -1720,13 +1773,22 @@ 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'",
@@ -1744,7 +1806,9 @@ layout_class (this_class)
          obstack_grow (&temporary_obstack, buffer, strlen (buffer));
        }
       obstack_1grow (&temporary_obstack, '\0');
-      cyclic_inheritance_report = obstack_finish (&temporary_obstack);
+      report = obstack_finish (&temporary_obstack);
+      cyclic_inheritance_report = ggc_strdup (report);
+      obstack_free (&temporary_obstack, report);
       TYPE_SIZE (this_class) = error_mark_node;
       return;
     }
@@ -1752,8 +1816,10 @@ layout_class (this_class)
 
   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;
@@ -1776,6 +1842,35 @@ 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)));
@@ -1794,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);
 
@@ -1807,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);
@@ -1820,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
@@ -1858,8 +2050,14 @@ 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 (ID_FINIT_P (method_name))
     obstack_grow (&temporary_obstack, "finit", 5);
@@ -1985,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);
@@ -2043,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);
 }