70a3a1d
2007-10-03  Andrew Haley  <aph@redhat.com>
70a3a1d
70a3a1d
	PR java/33639
70a3a1d
	* class.c (mangled_classname): Detect and replace illegal
70a3a1d
	characters in assembly language symbols.
70a3a1d
	(gen_indirect_dispatch_tables): Call mangled_classname() on
70a3a1d
	the type.
70a3a1d
70a3a1d
--- gcc/java/class.c	(revision 128980)
70a3a1d
+++ gcc/java/class.c	(revision 128981)
70a3a1d
@@ -314,10 +314,63 @@ identifier_subst (const tree old_id,
70a3a1d
 tree
70a3a1d
 mangled_classname (const char *prefix, tree type)
70a3a1d
 {
70a3a1d
+  tree result;
70a3a1d
   tree ident = TYPE_NAME (type);
70a3a1d
   if (TREE_CODE (ident) != IDENTIFIER_NODE)
70a3a1d
     ident = DECL_NAME (ident);
70a3a1d
-  return identifier_subst (ident, prefix, '.', '_', "");
70a3a1d
+  result = identifier_subst (ident, prefix, '.', '_', "");
70a3a1d
+
70a3a1d
+  /* Replace any characters that aren't in the set [0-9a-zA-Z_$] with
70a3a1d
+     "_0xXX".  Class names containing such chracters are uncommon, but
70a3a1d
+     they do sometimes occur in class files.  Without this check,
70a3a1d
+     these names cause assembly errors.
70a3a1d
+
70a3a1d
+     There is a possibility that a real class name could conflict with
70a3a1d
+     the identifier we generate, but it is unlikely and will
70a3a1d
+     immediately be detected as an assembler error.  At some point we
70a3a1d
+     should do something more elaborate (perhaps using the full
70a3a1d
+     unicode mangling scheme) in order to prevent such a conflict.  */
70a3a1d
+  {
70a3a1d
+    int i;
70a3a1d
+    const int len = IDENTIFIER_LENGTH (result);
70a3a1d
+    const char *p = IDENTIFIER_POINTER (result);
70a3a1d
+    int illegal_chars = 0;
70a3a1d
+
70a3a1d
+    /* Make two passes over the identifier.  The first pass is merely
70a3a1d
+       to count illegal characters; we need to do this in order to
70a3a1d
+       allocate a buffer.  */
70a3a1d
+    for (i = 0; i < len; i++)
70a3a1d
+      {
70a3a1d
+	char c = p[i];
70a3a1d
+	illegal_chars += (! ISALNUM (c) && c != '_' && c != '$');
70a3a1d
+      }
70a3a1d
+
70a3a1d
+    /* And the second pass, which is rarely executed, does the
70a3a1d
+       rewriting.  */
70a3a1d
+    if (illegal_chars != 0)
70a3a1d
+      {
70a3a1d
+	char *buffer = alloca (illegal_chars * 4 + len + 1);
70a3a1d
+	int j;
70a3a1d
+
70a3a1d
+	for (i = 0, j = 0; i < len; i++)
70a3a1d
+	  {
70a3a1d
+	    char c = p[i];
70a3a1d
+	    if (! ISALNUM (c) && c != '_' && c != '$')
70a3a1d
+	      {
70a3a1d
+		buffer[j++] = '_';
70a3a1d
+		sprintf (&buffer[j], "0x%02x", c);
70a3a1d
+		j += 4;
70a3a1d
+	      }
70a3a1d
+	    else
70a3a1d
+	      buffer[j++] = c;
70a3a1d
+	  }
70a3a1d
+
70a3a1d
+	buffer[j] = 0;
70a3a1d
+	result = get_identifier (buffer);
70a3a1d
+      }
70a3a1d
+  }
70a3a1d
+
70a3a1d
+  return result;
70a3a1d
 }
70a3a1d
 
70a3a1d
 tree
70a3a1d
@@ -389,7 +442,7 @@ while (0)
70a3a1d
 void
70a3a1d
 gen_indirect_dispatch_tables (tree type)
70a3a1d
 {
70a3a1d
-  const char *typename = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
70a3a1d
+  const char *typename = IDENTIFIER_POINTER (mangled_classname ("", type));
70a3a1d
   {  
70a3a1d
     tree field = NULL;
70a3a1d
     char *buf = alloca (strlen (typename) + strlen ("_catch_classes_") + 1);