namespace namespace

Andrew Haley aph@redhat.com
Mon Jun 29 17:39:00 GMT 2009


It turns out that the mangling of C++ keywords used by gcj is completely
broken:

In particular, when a member name is a C++ keyword, "$" is appended to the
name.  However, this is results in an illegal mangled name so it is not
possible to refer to the member from CNI code.

Also, the set of C++ keywords in gjavah is different from the set in gcj.

Also, types are not checked for C++ keywords, so javax.xml.namespace.* cannot
be referenced from CNI code.

This patch fixes the problem.

This is an ABI change.  However, the ABI was almost completely broken
anyway.

Andrew.


2009-06-29  Andrew Haley  <aph@redhat.com>

	PR java/40590	
	* tools/gnu/classpath/tools/javah/FieldHelper.java (print):
	Use printName().
	* tools/gnu/classpath/tools/javah/MethodHelper.java (print):
	Use printName().
	* tools/gnu/classpath/tools/javah/CniStubPrinter.java (printDecl):
	Use printName().
	* tools/gnu/classpath/tools/javah/Keywords.java (words): Replace
	with keywords list from  gcc/java/mangle.c.
	* tools/gnu/classpath/tools/javah/ClassWrapper.java (printMethods):
	Don't pre-convert a C++ keyword.
	(print(CniPrintStream)): Call CniPrintStream.printName().
	(printContents): Likewise.
	* tools/gnu/classpath/tools/javah/CniPrintStream.java
	(getClassName): Don't call replaceAll("/", "::").
	(print(Type)): Add ""::" befor name, " *" after.  Use printName(), not
	print.
	(printName(PrintStream, String), printName(String), printlnName):
	New methods.
	(moveToPackage): Use printName().

2009-06-29  Andrew Haley  <aph@redhat.com>

	PR java/40590
	* java-tree.h (cxx_keyword_p): New declaration.
	* mangle_name.c (utf8_cmp): Move here from mangle.c.
	(cxx_keywords): Likewise.
	(cxx_keyword_p): Likewise.
	(MANGLE_CXX_KEYWORDS): New macro.
	(append_gpp_mangled_name): Use MANGLE_CXX_KEYWORDS.
	(append_gpp_mangled_name): Likewise.
	* mangle.c: Move code to mangle_name.c.
	(mangle_member_name): Don't call cxx_keyword_p.

Index: gcc/java/mangle_name.c
===================================================================
--- gcc/java/mangle_name.c	(revision 149053)
+++ gcc/java/mangle_name.c	(working copy)
@@ -41,6 +41,183 @@

 extern struct obstack *mangle_obstack;

+static int
+utf8_cmp (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;
+}
+
+/* A sorted list of all C++ keywords.  */
+static const char *const cxx_keywords[] =
+{
+  "_Complex",
+  "__alignof",
+  "__alignof__",
+  "__asm",
+  "__asm__",
+  "__attribute",
+  "__attribute__",
+  "__builtin_va_arg",
+  "__complex",
+  "__complex__",
+  "__const",
+  "__const__",
+  "__extension__",
+  "__imag",
+  "__imag__",
+  "__inline",
+  "__inline__",
+  "__label__",
+  "__null",
+  "__real",
+  "__real__",
+  "__restrict",
+  "__restrict__",
+  "__signed",
+  "__signed__",
+  "__typeof",
+  "__typeof__",
+  "__volatile",
+  "__volatile__",
+  "and",
+  "and_eq",
+  "asm",
+  "auto",
+  "bitand",
+  "bitor",
+  "bool",
+  "break",
+  "case",
+  "catch",
+  "char",
+  "class",
+  "compl",
+  "const",
+  "const_cast",
+  "continue",
+  "default",
+  "delete",
+  "do",
+  "double",
+  "dynamic_cast",
+  "else",
+  "enum",
+  "explicit",
+  "export",
+  "extern",
+  "false",
+  "float",
+  "for",
+  "friend",
+  "goto",
+  "if",
+  "inline",
+  "int",
+  "long",
+  "mutable",
+  "namespace",
+  "new",
+  "not",
+  "not_eq",
+  "operator",
+  "or",
+  "or_eq",
+  "private",
+  "protected",
+  "public",
+  "register",
+  "reinterpret_cast",
+  "return",
+  "short",
+  "signed",
+  "sizeof",
+  "static",
+  "static_cast",
+  "struct",
+  "switch",
+  "template",
+  "this",
+  "throw",
+  "true",
+  "try",
+  "typedef",
+  "typeid",
+  "typename",
+  "typeof",
+  "union",
+  "unsigned",
+  "using",
+  "virtual",
+  "void",
+  "volatile",
+  "wchar_t",
+  "while",
+  "xor",
+  "xor_eq"
+};
+
+/* Return true if NAME is a C++ keyword.  */
+int
+cxx_keyword_p (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 ((const unsigned char *) 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;
+}
+
+/* If NAME happens to be a C++ keyword, add `$'.  */
+#define MANGLE_CXX_KEYWORDS(NAME, LEN)			\
+do							\
+  {							\
+    if (cxx_keyword_p ((NAME), (LEN)))			\
+      {							\
+	char *tmp_buf = (char *)alloca ((LEN)+1);	\
+	memcpy (tmp_buf, (NAME), (LEN));		\
+	tmp_buf[LEN]= '$';				\
+	(NAME) = tmp_buf;				\
+	(LEN)++;					\
+      }							\
+  }							\
+while (0)
+
+
 /* If the assembler doesn't support UTF8 in symbol names, some
    characters might need to be escaped.  */

@@ -54,10 +231,14 @@
 void
 append_gpp_mangled_name (const char *name, int len)
 {
-  int encoded_len = unicode_mangling_length (name, len);
-  int needs_escapes = encoded_len > 0;
+  int encoded_len, needs_escapes;
   char buf[6];

+  MANGLE_CXX_KEYWORDS (name, len);
+
+  encoded_len = unicode_mangling_length (name, len);
+  needs_escapes = encoded_len > 0;
+
   sprintf (buf, "%d", (needs_escapes ? encoded_len : len));
   obstack_grow (mangle_obstack, buf, strlen (buf));

@@ -195,10 +376,14 @@
 append_gpp_mangled_name (const char *name, int len)
 {
   const unsigned char *ptr;
-  const unsigned char *limit = (const unsigned char *)name + len;
+  const unsigned char *limit;
   int encoded_len;
   char buf [6];

+  MANGLE_CXX_KEYWORDS (name, len);
+
+  limit = (const unsigned char *)name + len;
+
   /* Compute the length of the string we wish to mangle. */
   for (encoded_len =  0, ptr = (const unsigned char *) name;
        ptr < limit; encoded_len++)
Index: gcc/java/mangle.c
===================================================================
--- gcc/java/mangle.c	(revision 149053)
+++ gcc/java/mangle.c	(working copy)
@@ -72,167 +72,6 @@
 /* atms: array template mangled string. */
 static GTY(()) tree atms;

-static int
-utf8_cmp (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;
-}
-
-/* A sorted list of all C++ keywords.  */
-static const char *const cxx_keywords[] =
-{
-  "_Complex",
-  "__alignof",
-  "__alignof__",
-  "__asm",
-  "__asm__",
-  "__attribute",
-  "__attribute__",
-  "__builtin_va_arg",
-  "__complex",
-  "__complex__",
-  "__const",
-  "__const__",
-  "__extension__",
-  "__imag",
-  "__imag__",
-  "__inline",
-  "__inline__",
-  "__label__",
-  "__null",
-  "__real",
-  "__real__",
-  "__restrict",
-  "__restrict__",
-  "__signed",
-  "__signed__",
-  "__typeof",
-  "__typeof__",
-  "__volatile",
-  "__volatile__",
-  "and",
-  "and_eq",
-  "asm",
-  "auto",
-  "bitand",
-  "bitor",
-  "bool",
-  "break",
-  "case",
-  "catch",
-  "char",
-  "class",
-  "compl",
-  "const",
-  "const_cast",
-  "continue",
-  "default",
-  "delete",
-  "do",
-  "double",
-  "dynamic_cast",
-  "else",
-  "enum",
-  "explicit",
-  "export",
-  "extern",
-  "false",
-  "float",
-  "for",
-  "friend",
-  "goto",
-  "if",
-  "inline",
-  "int",
-  "long",
-  "mutable",
-  "namespace",
-  "new",
-  "not",
-  "not_eq",
-  "operator",
-  "or",
-  "or_eq",
-  "private",
-  "protected",
-  "public",
-  "register",
-  "reinterpret_cast",
-  "return",
-  "short",
-  "signed",
-  "sizeof",
-  "static",
-  "static_cast",
-  "struct",
-  "switch",
-  "template",
-  "this",
-  "throw",
-  "true",
-  "try",
-  "typedef",
-  "typeid",
-  "typename",
-  "typeof",
-  "union",
-  "unsigned",
-  "using",
-  "virtual",
-  "void",
-  "volatile",
-  "wchar_t",
-  "while",
-  "xor",
-  "xor_eq"
-};
-
-/* Return true if NAME is a C++ keyword.  */
-static int
-cxx_keyword_p (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 ((const unsigned char *) 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;
-}
-
 /* This is the mangling interface: a decl, a class field (.class) and
    the vtable. */

@@ -392,10 +231,6 @@
 {
   append_gpp_mangled_name (IDENTIFIER_POINTER (name),
 			   IDENTIFIER_LENGTH (name));
-
-  /* If NAME happens to be a C++ keyword, add `$'.  */
-  if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
-    obstack_1grow (mangle_obstack, '$');
 }

 /* Append the mangled name of TYPE onto OBSTACK.  */
Index: gcc/java/java-tree.h
===================================================================
--- gcc/java/java-tree.h	(revision 149053)
+++ gcc/java/java-tree.h	(working copy)
@@ -1224,6 +1224,8 @@

 extern void rewrite_reflection_indexes (void *);

+int cxx_keyword_p (const char *name, int length);
+
 #define DECL_FINAL(DECL) DECL_LANG_FLAG_3 (DECL)

 /* Access flags etc for a method (a FUNCTION_DECL): */
Index: libjava/classpath/tools/gnu/classpath/tools/javah/CniPrintStream.java
===================================================================
--- libjava/classpath/tools/gnu/classpath/tools/javah/CniPrintStream.java	(revision 148903)
+++ libjava/classpath/tools/gnu/classpath/tools/javah/CniPrintStream.java	(working copy)
@@ -125,9 +125,10 @@
     // Add the plain class name; we'll handle it when
     // we process namespaces.
     allClasses.add(name);
-    return "::" + name.replaceAll("/", "::") + " *";
+    return name;
   }

+  // Print the C++ form of TYPE, mangling C++ keywords.
   public void print(Type type)
   {
     int arrayCount = 0;
@@ -141,7 +142,9 @@
       }
     if (type.getSort() == Type.OBJECT)
       {
-        print(getClassName(type));
+	print("::");
+        printName(getClassName(type));
+	print(" *");
       }
     else
       {
@@ -156,6 +159,34 @@
       }
   }

+  // Print NAME, converting into C++ syntax and mangling C++ keywords
+  // as we go.
+  public final static void printName(PrintStream out, String name)
+  {
+    String[] parts = name.split("::|/");
+    for (int i = 0; i < parts.length; i++)
+      {
+	if (i != 0)
+	  out.print("::");
+	out.print(Keywords.getCxxName(parts[i]));
+      }
+  }
+
+  // Println NAME, converting into C++ syntax and mangling C++
+  // keywords as we go.
+  public final static void printlnName(PrintStream out, String name)
+  {
+    printName(out, name);
+    out.println();
+  }
+
+  // Print NAME, converting into C++ syntax and mangling C++ keywords
+  // as we go.
+  final void printName(String name)
+  {
+    printName(this, name);
+  }
+
   private void indent(PrintStream out, int n)
   {
     for (int i = 0; i < n; ++i)
@@ -186,7 +217,7 @@
       {
         indent(out, j + 1);
         out.print("namespace ");
-        out.println(pkgParts[j]);
+        printlnName(out, pkgParts[j]);
         indent(out, j + 1);
         out.println("{");
       }
@@ -202,7 +233,7 @@
     moveToPackage(out, pkgParts);
     indent(out, pkgParts.length + 2);
     out.print("class ");
-    out.print(className);
+    printName(out, className);
     out.println(";");
   }

Index: libjava/classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java
===================================================================
--- libjava/classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java	(revision 148903)
+++ libjava/classpath/tools/gnu/classpath/tools/javah/ClassWrapper.java	(working copy)
@@ -260,7 +260,7 @@
 	if (bridgeTargets.contains(sum))
 	  nameToUse = (String) methodNameMap.get(sum);
 	else
-	  nameToUse = Keywords.getCxxName(m.name);
+	  nameToUse = m.name;
 	methodNameMap.put(sum, nameToUse);
         MethodHelper.print(out, m, this, nameToUse);
       }
@@ -291,7 +291,8 @@

   public void print(CniPrintStream out)
   {
-    out.print("::" + name.replaceAll("/", "::"));
+    out.print("::");
+    out.printName(name);
   }

   // This prints the body of a class to a CxxPrintStream.
@@ -303,7 +304,7 @@

     out.print("class ");
     // Don't use our print() -- we don't want the leading "::".
-    out.print(name.replaceAll("/", "::"));
+    out.printName(name);
     if (superClass != null)
       {
         out.print(" : public ");
Index: libjava/classpath/tools/gnu/classpath/tools/javah/Keywords.java
===================================================================
--- libjava/classpath/tools/gnu/classpath/tools/javah/Keywords.java	(revision 148903)
+++ libjava/classpath/tools/gnu/classpath/tools/javah/Keywords.java	(working copy)
@@ -42,28 +42,115 @@

 public class Keywords
 {
-  private static final String[] words = { "and", "and_eq", "asm", "auto",
-                                         "bitand", "bitor", "bool", "break",
-                                         "case", "catch", "char", "class",
-                                         "compl", "const", "const_cast",
-                                         "continue", "default", "delete", "do",
-                                         "double", "dynamic_cast", "else",
-                                         "enum", "explicit", "export",
-                                         "extern", "false", "float", "for",
-                                         "friend", "goto", "if", "inline",
-                                         "int", "long", "mutable", "namespace",
-                                         "new", "not", "not_eq", "operator",
-                                         "or", "or_eq", "private", "protected",
-                                         "public", "register",
-                                         "reinterpret_cast", "return", "short",
-                                         "signed", "sizeof", "static",
-                                         "static_cast", "struct", "switch",
-                                         "template", "this", "throw", "true",
-                                         "try", "typedef", "typeid",
-                                         "typename", "typeof", "union",
-                                         "unsigned", "using", "virtual",
-                                         "void", "volatile", "wchar_t",
-                                         "while", "xor", "xor_eq" };
+/* A sorted list of all C++ keywords.  This is identical to the list
+   in gcc/java/mangle.c.  */
+  private static final String[] words =
+    {
+      "_Complex",
+      "__alignof",
+      "__alignof__",
+      "__asm",
+      "__asm__",
+      "__attribute",
+      "__attribute__",
+      "__builtin_va_arg",
+      "__complex",
+      "__complex__",
+      "__const",
+      "__const__",
+      "__extension__",
+      "__imag",
+      "__imag__",
+      "__inline",
+      "__inline__",
+      "__label__",
+      "__null",
+      "__real",
+      "__real__",
+      "__restrict",
+      "__restrict__",
+      "__signed",
+      "__signed__",
+      "__typeof",
+      "__typeof__",
+      "__volatile",
+      "__volatile__",
+      "and",
+      "and_eq",
+      "asm",
+      "auto",
+      "bitand",
+      "bitor",
+      "bool",
+      "break",
+      "case",
+      "catch",
+      "char",
+      "class",
+      "compl",
+      "const",
+      "const_cast",
+      "continue",
+      "default",
+      "delete",
+      "do",
+      "double",
+      "dynamic_cast",
+      "else",
+      "enum",
+      "explicit",
+      "export",
+      "extern",
+      "false",
+      "float",
+      "for",
+      "friend",
+      "goto",
+      "if",
+      "inline",
+      "int",
+      "long",
+      "mutable",
+      "namespace",
+      "new",
+      "not",
+      "not_eq",
+      "operator",
+      "or",
+      "or_eq",
+      "private",
+      "protected",
+      "public",
+      "register",
+      "reinterpret_cast",
+      "return",
+      "short",
+      "signed",
+      "sizeof",
+      "static",
+      "static_cast",
+      "struct",
+      "switch",
+      "template",
+      "this",
+      "throw",
+      "true",
+      "try",
+      "typedef",
+      "typeid",
+      "typename",
+      "typeof",
+      "union",
+      "unsigned",
+      "using",
+      "virtual",
+      "void",
+      "volatile",
+      "wchar_t",
+      "while",
+      "xor",
+      "xor_eq"
+    };

   private static final HashSet keywords;
   static
Index: libjava/classpath/tools/gnu/classpath/tools/javah/CniStubPrinter.java
===================================================================
--- libjava/classpath/tools/gnu/classpath/tools/javah/CniStubPrinter.java	(revision 148903)
+++ libjava/classpath/tools/gnu/classpath/tools/javah/CniStubPrinter.java	(working copy)
@@ -59,9 +59,9 @@

   private void printDecl(CniPrintStream out, String className, MethodNode method)
   {
-    out.print(className);
+    out.printName(className);
     out.print("::");
-    out.print(method.name);
+    out.printName(method.name);
     out.print("(");
     Type[] argTypes = Type.getArgumentTypes(method.desc);
     for (int j = 0; j < argTypes.length; ++j)
Index: libjava/classpath/tools/gnu/classpath/tools/javah/MethodHelper.java
===================================================================
--- libjava/classpath/tools/gnu/classpath/tools/javah/MethodHelper.java	(revision 148903)
+++ libjava/classpath/tools/gnu/classpath/tools/javah/MethodHelper.java	(working copy)
@@ -97,14 +97,14 @@
       {
         out.print(Type.getReturnType(meth.desc));
         out.print(" ");
-	out.print(realMethodName);
+	out.printName(realMethodName);
       }
     else
       {
         String name = declarer.name;
         int index = name.lastIndexOf('/');
         name = name.substring(index + 1);
-        out.print(name);
+        out.printName(name);
       }
     out.print("(");
     Type[] argTypes = Type.getArgumentTypes(meth.desc);
Index: libjava/classpath/tools/gnu/classpath/tools/javah/FieldHelper.java
===================================================================
--- libjava/classpath/tools/gnu/classpath/tools/javah/FieldHelper.java	(revision 148903)
+++ libjava/classpath/tools/gnu/classpath/tools/javah/FieldHelper.java	(working copy)
@@ -66,7 +66,7 @@
         out.print(")))) ");
         result = true;
       }
-    out.print(Keywords.getCxxName(field.name));
+    out.printName(field.name);
     if (hasMethodName)
       out.print("__");
     if (Modifier.isStatic(field.access))



More information about the Java-patches mailing list