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 <a...@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 <a...@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))