# HG changeset patch # User lana # Date 1332808337 25200 # Node ID be069d72dde2bfe6f996c46325a320961ca854c2 # Parent ebfe9b8ce039413659da54adbfd6e52e9739c4dd# Parent 6b473c9ebf1e4ee3ac174411081aa992eab75ac1 Merge diff -r ebfe9b8ce039 -r be069d72dde2 src/share/classes/com/sun/tools/javac/code/Symtab.java --- a/src/share/classes/com/sun/tools/javac/code/Symtab.java Thu Mar 22 12:41:36 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java Mon Mar 26 17:32:17 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,6 +126,7 @@ public final Type cloneableType; public final Type serializableType; public final Type methodHandleType; + public final Type nativeHeaderType; public final Type polymorphicSignatureType; public final Type throwableType; public final Type errorType; @@ -477,6 +478,7 @@ List.of(exceptionType), methodClass), autoCloseableType.tsym); trustMeType = enterClass("java.lang.SafeVarargs"); + nativeHeaderType = enterClass("javax.tools.annotation.GenerateNativeHeader"); synthesizeEmptyInterfaceIfMissing(autoCloseableType); synthesizeEmptyInterfaceIfMissing(cloneableType); diff -r ebfe9b8ce039 -r be069d72dde2 src/share/classes/com/sun/tools/javac/file/Locations.java --- a/src/share/classes/com/sun/tools/javac/file/Locations.java Thu Mar 22 12:41:36 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/file/Locations.java Mon Mar 26 17:32:17 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -648,7 +648,8 @@ new SimpleLocationHandler(StandardLocation.SOURCE_PATH, Option.SOURCEPATH), new SimpleLocationHandler(StandardLocation.ANNOTATION_PROCESSOR_PATH, Option.PROCESSORPATH), new OutputLocationHandler((StandardLocation.CLASS_OUTPUT), Option.D), - new OutputLocationHandler((StandardLocation.SOURCE_OUTPUT), Option.S) + new OutputLocationHandler((StandardLocation.SOURCE_OUTPUT), Option.S), + new OutputLocationHandler((StandardLocation.NATIVE_HEADER_OUTPUT), Option.H) }; for (LocationHandler h: handlers) { diff -r ebfe9b8ce039 -r be069d72dde2 src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java --- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Thu Mar 22 12:41:36 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Mon Mar 26 17:32:17 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,11 +69,11 @@ */ private boolean verbose; - /** Switch: scrable private names. + /** Switch: scramble private names. */ private boolean scramble; - /** Switch: scrable private names. + /** Switch: scramble private names. */ private boolean scrambleAll; diff -r ebfe9b8ce039 -r be069d72dde2 src/share/classes/com/sun/tools/javac/jvm/JNIWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/jvm/JNIWriter.java Mon Mar 26 17:32:17 2012 -0700 @@ -0,0 +1,856 @@ +/* + * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.jvm; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; +import java.util.StringTokenizer; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.NoType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.type.TypeVisitor; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.lang.model.util.SimpleTypeVisitor8; +import javax.lang.model.util.Types; + +import javax.tools.FileObject; +import javax.tools.JavaFileManager; +import javax.tools.StandardLocation; + +import com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Kinds; +import com.sun.tools.javac.code.Scope; +import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.model.JavacElements; +import com.sun.tools.javac.model.JavacTypes; +import com.sun.tools.javac.util.Assert; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Options; + +import static com.sun.tools.javac.main.Option.*; + +/** This class provides operations to write native header files for classes. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class JNIWriter { + protected static final Context.Key jniWriterKey = + new Context.Key(); + + /** Access to files. */ + private final JavaFileManager fileManager; + + JavacElements elements; + JavacTypes types; + + /** The log to use for verbose output. + */ + private final Log log; + + /** Switch: verbose output. + */ + private boolean verbose; + + /** Switch: check all nested classes of top level class + */ + private boolean checkAll; + + private Mangle mangler; + + private Context context; + + private Symtab syms; + + private String lineSep; + + private final boolean isWindows = + System.getProperty("os.name").startsWith("Windows"); + + /** Get the ClassWriter instance for this context. */ + public static JNIWriter instance(Context context) { + JNIWriter instance = context.get(jniWriterKey); + if (instance == null) + instance = new JNIWriter(context); + return instance; + } + + /** Construct a class writer, given an options table. + */ + private JNIWriter(Context context) { + context.put(jniWriterKey, this); + fileManager = context.get(JavaFileManager.class); + log = Log.instance(context); + + Options options = Options.instance(context); + verbose = options.isSet(VERBOSE); + checkAll = options.isSet("javah:full"); + + this.context = context; // for lazyInit() + syms = Symtab.instance(context); + + lineSep = System.getProperty("line.separator"); + } + + private void lazyInit() { + if (mangler == null) { + elements = JavacElements.instance(context); + types = JavacTypes.instance(context); + mangler = new Mangle(elements, types); + } + } + + public boolean needsHeader(ClassSymbol c) { + if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0) + return false; + + if (checkAll) + return needsHeader(c.outermostClass(), true); + else + return needsHeader(c, false); + } + + private boolean needsHeader(ClassSymbol c, boolean checkNestedClasses) { + if (c.isLocal() || (c.flags() & Flags.SYNTHETIC) != 0) + return false; + + for (Attribute.Compound a: c.attributes_field) { + if (a.type.tsym == syms.nativeHeaderType.tsym) + return true; + } + for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) { + if (i.sym.kind == Kinds.MTH && (i.sym.flags() & Flags.NATIVE) != 0) + return true; + } + if (checkNestedClasses) { + for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) { + if ((i.sym.kind == Kinds.TYP) && needsHeader(((ClassSymbol) i.sym), true)) + return true; + } + } + return false; + } + + /** Emit a class file for a given class. + * @param c The class from which a class file is generated. + */ + public FileObject write(ClassSymbol c) + throws IOException + { + String className = c.flatName().toString(); + FileObject outFile + = fileManager.getFileForOutput(StandardLocation.NATIVE_HEADER_OUTPUT, + "", className.replaceAll("[.$]", "_") + ".h", null); + Writer out = outFile.openWriter(); + try { + write(out, c); + if (verbose) + log.printVerbose("wrote.file", outFile); + out.close(); + out = null; + } finally { + if (out != null) { + // if we are propogating an exception, delete the file + out.close(); + outFile.delete(); + outFile = null; + } + } + return outFile; // may be null if write failed + } + + public void write(Writer out, ClassSymbol sym) + throws IOException { + lazyInit(); + try { + String cname = mangler.mangle(sym.fullname, Mangle.Type.CLASS); + println(out, fileTop()); + println(out, includes()); + println(out, guardBegin(cname)); + println(out, cppGuardBegin()); + + writeStatics(out, sym); + writeMethods(out, sym, cname); + + println(out, cppGuardEnd()); + println(out, guardEnd(cname)); + } catch (TypeSignature.SignatureException e) { + throw new IOException(e); + } + } + + protected void writeStatics(Writer out, ClassSymbol sym) throws IOException { + List classfields = getAllFields(sym); + + for (VariableElement v: classfields) { + if (!v.getModifiers().contains(Modifier.STATIC)) + continue; + String s = null; + s = defineForStatic(sym, v); + if (s != null) { + println(out, s); + } + } + } + + /** + * Including super class fields. + */ + List getAllFields(TypeElement subclazz) { + List fields = new ArrayList(); + TypeElement cd = null; + Stack s = new Stack(); + + cd = subclazz; + while (true) { + s.push(cd); + TypeElement c = (TypeElement) (types.asElement(cd.getSuperclass())); + if (c == null) + break; + cd = c; + } + + while (!s.empty()) { + cd = s.pop(); + fields.addAll(ElementFilter.fieldsIn(cd.getEnclosedElements())); + } + + return fields; + } + + protected String defineForStatic(TypeElement c, VariableElement f) { + CharSequence cnamedoc = c.getQualifiedName(); + CharSequence fnamedoc = f.getSimpleName(); + + String cname = mangler.mangle(cnamedoc, Mangle.Type.CLASS); + String fname = mangler.mangle(fnamedoc, Mangle.Type.FIELDSTUB); + + Assert.check(f.getModifiers().contains(Modifier.STATIC)); + + if (f.getModifiers().contains(Modifier.FINAL)) { + Object value = null; + + value = f.getConstantValue(); + + if (value != null) { /* so it is a ConstantExpression */ + String constString = null; + if ((value instanceof Integer) + || (value instanceof Byte) + || (value instanceof Short)) { + /* covers byte, short, int */ + constString = value.toString() + "L"; + } else if (value instanceof Boolean) { + constString = ((Boolean) value) ? "1L" : "0L"; + } else if (value instanceof Character) { + Character ch = (Character) value; + constString = String.valueOf(((int) ch) & 0xffff) + "L"; + } else if (value instanceof Long) { + // Visual C++ supports the i64 suffix, not LL. + if (isWindows) + constString = value.toString() + "i64"; + else + constString = value.toString() + "LL"; + } else if (value instanceof Float) { + /* bug for bug */ + float fv = ((Float)value).floatValue(); + if (Float.isInfinite(fv)) + constString = ((fv < 0) ? "-" : "") + "Inff"; + else + constString = value.toString() + "f"; + } else if (value instanceof Double) { + /* bug for bug */ + double d = ((Double)value).doubleValue(); + if (Double.isInfinite(d)) + constString = ((d < 0) ? "-" : "") + "InfD"; + else + constString = value.toString(); + } + + if (constString != null) { + StringBuilder s = new StringBuilder("#undef "); + s.append(cname); s.append("_"); s.append(fname); s.append(lineSep); + s.append("#define "); s.append(cname); s.append("_"); + s.append(fname); s.append(" "); s.append(constString); + return s.toString(); + } + + } + } + + return null; + } + + + protected void writeMethods(Writer out, ClassSymbol sym, String cname) + throws IOException, TypeSignature.SignatureException { + List classmethods = ElementFilter.methodsIn(sym.getEnclosedElements()); + for (ExecutableElement md: classmethods) { + if(md.getModifiers().contains(Modifier.NATIVE)){ + TypeMirror mtr = types.erasure(md.getReturnType()); + String sig = signature(md); + TypeSignature newtypesig = new TypeSignature(elements); + CharSequence methodName = md.getSimpleName(); + boolean longName = false; + for (ExecutableElement md2: classmethods) { + if ((md2 != md) + && (methodName.equals(md2.getSimpleName())) + && (md2.getModifiers().contains(Modifier.NATIVE))) + longName = true; + + } + println(out, "/*"); + println(out, " * Class: " + cname); + println(out, " * Method: " + + mangler.mangle(methodName, Mangle.Type.FIELDSTUB)); + println(out, " * Signature: " + newtypesig.getTypeSignature(sig, mtr)); + println(out, " */"); + println(out, "JNIEXPORT " + jniType(mtr) + + " JNICALL " + + mangler.mangleMethod(md, sym, + (longName) ? + Mangle.Type.METHOD_JNI_LONG : + Mangle.Type.METHOD_JNI_SHORT)); + print(out, " (JNIEnv *, "); + List paramargs = md.getParameters(); + List args = new ArrayList(); + for (VariableElement p: paramargs) { + args.add(types.erasure(p.asType())); + } + if (md.getModifiers().contains(Modifier.STATIC)) + print(out, "jclass"); + else + print(out, "jobject"); + + for (TypeMirror arg: args) { + print(out, ", "); + print(out, jniType(arg)); + } + println(out, ");" + + lineSep); + } + } + } + + // c.f. MethodDoc.signature + String signature(ExecutableElement e) { + StringBuilder sb = new StringBuilder("("); + String sep = ""; + for (VariableElement p: e.getParameters()) { + sb.append(sep); + sb.append(types.erasure(p.asType()).toString()); + sep = ","; + } + sb.append(")"); + return sb.toString(); + } + + protected final String jniType(TypeMirror t) { + TypeElement throwable = elements.getTypeElement("java.lang.Throwable"); + TypeElement jClass = elements.getTypeElement("java.lang.Class"); + TypeElement jString = elements.getTypeElement("java.lang.String"); + Element tclassDoc = types.asElement(t); + + + switch (t.getKind()) { + case ARRAY: { + TypeMirror ct = ((ArrayType) t).getComponentType(); + switch (ct.getKind()) { + case BOOLEAN: return "jbooleanArray"; + case BYTE: return "jbyteArray"; + case CHAR: return "jcharArray"; + case SHORT: return "jshortArray"; + case INT: return "jintArray"; + case LONG: return "jlongArray"; + case FLOAT: return "jfloatArray"; + case DOUBLE: return "jdoubleArray"; + case ARRAY: + case DECLARED: return "jobjectArray"; + default: throw new Error(ct.toString()); + } + } + + case VOID: return "void"; + case BOOLEAN: return "jboolean"; + case BYTE: return "jbyte"; + case CHAR: return "jchar"; + case SHORT: return "jshort"; + case INT: return "jint"; + case LONG: return "jlong"; + case FLOAT: return "jfloat"; + case DOUBLE: return "jdouble"; + + case DECLARED: { + if (tclassDoc.equals(jString)) + return "jstring"; + else if (types.isAssignable(t, throwable.asType())) + return "jthrowable"; + else if (types.isAssignable(t, jClass.asType())) + return "jclass"; + else + return "jobject"; + } + } + + Assert.check(false, "jni unknown type"); + return null; /* dead code. */ + } + + protected String fileTop() { + return "/* DO NOT EDIT THIS FILE - it is machine generated */"; + } + + protected String includes() { + return "#include "; + } + + /* + * Deal with the C pre-processor. + */ + protected String cppGuardBegin() { + return "#ifdef __cplusplus" + lineSep + + "extern \"C\" {" + lineSep + + "#endif"; + } + + protected String cppGuardEnd() { + return "#ifdef __cplusplus" + lineSep + + "}" + lineSep + + "#endif"; + } + + protected String guardBegin(String cname) { + return "/* Header for class " + cname + " */" + lineSep + + lineSep + + "#ifndef _Included_" + cname + lineSep + + "#define _Included_" + cname; + } + + protected String guardEnd(String cname) { + return "#endif"; + } + + protected void print(Writer out, String text) throws IOException { + out.write(text); + } + + protected void println(Writer out, String text) throws IOException { + out.write(text); + out.write(lineSep); + } + + + private static class Mangle { + + public static class Type { + public static final int CLASS = 1; + public static final int FIELDSTUB = 2; + public static final int FIELD = 3; + public static final int JNI = 4; + public static final int SIGNATURE = 5; + public static final int METHOD_JDK_1 = 6; + public static final int METHOD_JNI_SHORT = 7; + public static final int METHOD_JNI_LONG = 8; + }; + + private Elements elems; + private Types types; + + Mangle(Elements elems, Types types) { + this.elems = elems; + this.types = types; + } + + public final String mangle(CharSequence name, int mtype) { + StringBuilder result = new StringBuilder(100); + int length = name.length(); + + for (int i = 0; i < length; i++) { + char ch = name.charAt(i); + if (isalnum(ch)) { + result.append(ch); + } else if ((ch == '.') && + mtype == Mangle.Type.CLASS) { + result.append('_'); + } else if (( ch == '$') && + mtype == Mangle.Type.CLASS) { + result.append('_'); + result.append('_'); + } else if (ch == '_' && mtype == Mangle.Type.FIELDSTUB) { + result.append('_'); + } else if (ch == '_' && mtype == Mangle.Type.CLASS) { + result.append('_'); + } else if (mtype == Mangle.Type.JNI) { + String esc = null; + if (ch == '_') + esc = "_1"; + else if (ch == '.') + esc = "_"; + else if (ch == ';') + esc = "_2"; + else if (ch == '[') + esc = "_3"; + if (esc != null) { + result.append(esc); + } else { + result.append(mangleChar(ch)); + } + } else if (mtype == Mangle.Type.SIGNATURE) { + if (isprint(ch)) { + result.append(ch); + } else { + result.append(mangleChar(ch)); + } + } else { + result.append(mangleChar(ch)); + } + } + + return result.toString(); + } + + public String mangleMethod(ExecutableElement method, TypeElement clazz, + int mtype) throws TypeSignature.SignatureException { + StringBuilder result = new StringBuilder(100); + result.append("Java_"); + + if (mtype == Mangle.Type.METHOD_JDK_1) { + result.append(mangle(clazz.getQualifiedName(), Mangle.Type.CLASS)); + result.append('_'); + result.append(mangle(method.getSimpleName(), + Mangle.Type.FIELD)); + result.append("_stub"); + return result.toString(); + } + + /* JNI */ + result.append(mangle(getInnerQualifiedName(clazz), Mangle.Type.JNI)); + result.append('_'); + result.append(mangle(method.getSimpleName(), + Mangle.Type.JNI)); + if (mtype == Mangle.Type.METHOD_JNI_LONG) { + result.append("__"); + String typesig = signature(method); + TypeSignature newTypeSig = new TypeSignature(elems); + String sig = newTypeSig.getTypeSignature(typesig, method.getReturnType()); + sig = sig.substring(1); + sig = sig.substring(0, sig.lastIndexOf(')')); + sig = sig.replace('/', '.'); + result.append(mangle(sig, Mangle.Type.JNI)); + } + + return result.toString(); + } + //where + private String getInnerQualifiedName(TypeElement clazz) { + return elems.getBinaryName(clazz).toString(); + } + + public final String mangleChar(char ch) { + String s = Integer.toHexString(ch); + int nzeros = 5 - s.length(); + char[] result = new char[6]; + result[0] = '_'; + for (int i = 1; i <= nzeros; i++) + result[i] = '0'; + for (int i = nzeros+1, j = 0; i < 6; i++, j++) + result[i] = s.charAt(j); + return new String(result); + } + + // Warning: duplicated in Gen + private String signature(ExecutableElement e) { + StringBuilder sb = new StringBuilder(); + String sep = "("; + for (VariableElement p: e.getParameters()) { + sb.append(sep); + sb.append(types.erasure(p.asType()).toString()); + sep = ","; + } + sb.append(")"); + return sb.toString(); + } + + /* Warning: Intentional ASCII operation. */ + private static boolean isalnum(char ch) { + return ch <= 0x7f && /* quick test */ + ((ch >= 'A' && ch <= 'Z') || + (ch >= 'a' && ch <= 'z') || + (ch >= '0' && ch <= '9')); + } + + /* Warning: Intentional ASCII operation. */ + private static boolean isprint(char ch) { + return ch >= 32 && ch <= 126; + } + } + + private static class TypeSignature { + static class SignatureException extends Exception { + private static final long serialVersionUID = 1L; + SignatureException(String reason) { + super(reason); + } + } + + Elements elems; + + /* Signature Characters */ + + private static final String SIG_VOID = "V"; + private static final String SIG_BOOLEAN = "Z"; + private static final String SIG_BYTE = "B"; + private static final String SIG_CHAR = "C"; + private static final String SIG_SHORT = "S"; + private static final String SIG_INT = "I"; + private static final String SIG_LONG = "J"; + private static final String SIG_FLOAT = "F"; + private static final String SIG_DOUBLE = "D"; + private static final String SIG_ARRAY = "["; + private static final String SIG_CLASS = "L"; + + + + public TypeSignature(Elements elems){ + this.elems = elems; + } + + /* + * Returns the type signature of a field according to JVM specs + */ + public String getTypeSignature(String javasignature) throws SignatureException { + return getParamJVMSignature(javasignature); + } + + /* + * Returns the type signature of a method according to JVM specs + */ + public String getTypeSignature(String javasignature, TypeMirror returnType) + throws SignatureException { + String signature = null; //Java type signature. + String typeSignature = null; //Internal type signature. + List params = new ArrayList(); //List of parameters. + String paramsig = null; //Java parameter signature. + String paramJVMSig = null; //Internal parameter signature. + String returnSig = null; //Java return type signature. + String returnJVMType = null; //Internal return type signature. + int dimensions = 0; //Array dimension. + + int startIndex = -1; + int endIndex = -1; + StringTokenizer st = null; + int i = 0; + + // Gets the actual java signature without parentheses. + if (javasignature != null) { + startIndex = javasignature.indexOf("("); + endIndex = javasignature.indexOf(")"); + } + + if (((startIndex != -1) && (endIndex != -1)) + &&(startIndex+1 < javasignature.length()) + &&(endIndex < javasignature.length())) { + signature = javasignature.substring(startIndex+1, endIndex); + } + + // Separates parameters. + if (signature != null) { + if (signature.indexOf(",") != -1) { + st = new StringTokenizer(signature, ","); + if (st != null) { + while (st.hasMoreTokens()) { + params.add(st.nextToken()); + } + } + } else { + params.add(signature); + } + } + + /* JVM type signature. */ + typeSignature = "("; + + // Gets indivisual internal parameter signature. + while (params.isEmpty() != true) { + paramsig = params.remove(i).trim(); + paramJVMSig = getParamJVMSignature(paramsig); + if (paramJVMSig != null) { + typeSignature += paramJVMSig; + } + } + + typeSignature += ")"; + + // Get internal return type signature. + + returnJVMType = ""; + if (returnType != null) { + dimensions = dimensions(returnType); + } + + //Gets array dimension of return type. + while (dimensions-- > 0) { + returnJVMType += "["; + } + if (returnType != null) { + returnSig = qualifiedTypeName(returnType); + returnJVMType += getComponentType(returnSig); + } else { + System.out.println("Invalid return type."); + } + + typeSignature += returnJVMType; + + return typeSignature; + } + + /* + * Returns internal signature of a parameter. + */ + private String getParamJVMSignature(String paramsig) throws SignatureException { + String paramJVMSig = ""; + String componentType =""; + + if(paramsig != null){ + + if(paramsig.indexOf("[]") != -1) { + // Gets array dimension. + int endindex = paramsig.indexOf("[]"); + componentType = paramsig.substring(0, endindex); + String dimensionString = paramsig.substring(endindex); + if(dimensionString != null){ + while(dimensionString.indexOf("[]") != -1){ + paramJVMSig += "["; + int beginindex = dimensionString.indexOf("]") + 1; + if(beginindex < dimensionString.length()){ + dimensionString = dimensionString.substring(beginindex); + }else + dimensionString = ""; + } + } + } else componentType = paramsig; + + paramJVMSig += getComponentType(componentType); + } + return paramJVMSig; + } + + /* + * Returns internal signature of a component. + */ + private String getComponentType(String componentType) throws SignatureException { + + String JVMSig = ""; + + if(componentType != null){ + if(componentType.equals("void")) JVMSig += SIG_VOID ; + else if(componentType.equals("boolean")) JVMSig += SIG_BOOLEAN ; + else if(componentType.equals("byte")) JVMSig += SIG_BYTE ; + else if(componentType.equals("char")) JVMSig += SIG_CHAR ; + else if(componentType.equals("short")) JVMSig += SIG_SHORT ; + else if(componentType.equals("int")) JVMSig += SIG_INT ; + else if(componentType.equals("long")) JVMSig += SIG_LONG ; + else if(componentType.equals("float")) JVMSig += SIG_FLOAT ; + else if(componentType.equals("double")) JVMSig += SIG_DOUBLE ; + else { + if(!componentType.equals("")){ + TypeElement classNameDoc = elems.getTypeElement(componentType); + + if(classNameDoc == null){ + throw new SignatureException(componentType); + }else { + String classname = classNameDoc.getQualifiedName().toString(); + String newclassname = classname.replace('.', '/'); + JVMSig += "L"; + JVMSig += newclassname; + JVMSig += ";"; + } + } + } + } + return JVMSig; + } + + int dimensions(TypeMirror t) { + if (t.getKind() != TypeKind.ARRAY) + return 0; + return 1 + dimensions(((ArrayType) t).getComponentType()); + } + + + String qualifiedTypeName(TypeMirror type) { + TypeVisitor v = new SimpleTypeVisitor8() { + @Override + public Name visitArray(ArrayType t, Void p) { + return t.getComponentType().accept(this, p); + } + + @Override + public Name visitDeclared(DeclaredType t, Void p) { + return ((TypeElement) t.asElement()).getQualifiedName(); + } + + @Override + public Name visitPrimitive(PrimitiveType t, Void p) { + return elems.getName(t.toString()); + } + + @Override + public Name visitNoType(NoType t, Void p) { + if (t.getKind() == TypeKind.VOID) + return elems.getName("void"); + return defaultAction(t, p); + } + + @Override + public Name visitTypeVariable(TypeVariable t, Void p) { + return t.getUpperBound().accept(this, p); + } + }; + return v.visit(type).toString(); + } + } + +} diff -r ebfe9b8ce039 -r be069d72dde2 src/share/classes/com/sun/tools/javac/main/JavaCompiler.java --- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Thu Mar 22 12:41:36 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Mar 26 17:32:17 2012 -0700 @@ -44,6 +44,8 @@ import javax.tools.DiagnosticListener; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; + import static javax.tools.StandardLocation.CLASS_OUTPUT; import com.sun.source.util.TaskEvent; @@ -60,6 +62,7 @@ import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.Log.WriterKind; + import static com.sun.tools.javac.main.Option.*; import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*; import static com.sun.tools.javac.util.ListBuffer.lb; @@ -227,6 +230,10 @@ */ protected ClassWriter writer; + /** The native header writer. + */ + protected JNIWriter jniWriter; + /** The module for the symbol table entry phases. */ protected Enter enter; @@ -330,6 +337,7 @@ reader = ClassReader.instance(context); make = TreeMaker.instance(context); writer = ClassWriter.instance(context); + jniWriter = JNIWriter.instance(context); enter = Enter.instance(context); todo = Todo.instance(context); @@ -1450,8 +1458,13 @@ JavaFileObject file; if (usePrintSource) file = printSource(env, cdef); - else + else { + if (fileManager.hasLocation(StandardLocation.NATIVE_HEADER_OUTPUT) + && jniWriter.needsHeader(cdef.sym)) { + jniWriter.write(cdef.sym); + } file = genCode(env, cdef); + } if (results != null && file != null) results.add(file); } catch (IOException ex) { diff -r ebfe9b8ce039 -r be069d72dde2 src/share/classes/com/sun/tools/javac/main/Option.java --- a/src/share/classes/com/sun/tools/javac/main/Option.java Thu Mar 22 12:41:36 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/main/Option.java Mon Mar 26 17:32:17 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -160,6 +160,8 @@ S("-s", "opt.arg.directory", "opt.sourceDest", STANDARD, FILEMANAGER), + H("-h", "opt.arg.directory", "opt.headerDest", STANDARD, FILEMANAGER), + IMPLICIT("-implicit:", "opt.implicit", STANDARD, BASIC, ONEOF, "none", "class"), ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER) { diff -r ebfe9b8ce039 -r be069d72dde2 src/share/classes/com/sun/tools/javac/resources/javac.properties --- a/src/share/classes/com/sun/tools/javac/resources/javac.properties Thu Mar 22 12:41:36 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/resources/javac.properties Mon Mar 26 17:32:17 2012 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -61,6 +61,8 @@ Specify where to place generated class files javac.opt.sourceDest=\ Specify where to place generated source files +javac.opt.headerDest=\ + Specify where to place generated native header files javac.opt.J=\ Pass directly to the runtime system javac.opt.encoding=\ diff -r ebfe9b8ce039 -r be069d72dde2 src/share/classes/javax/tools/StandardLocation.java --- a/src/share/classes/javax/tools/StandardLocation.java Thu Mar 22 12:41:36 2012 -0700 +++ b/src/share/classes/javax/tools/StandardLocation.java Mon Mar 26 17:32:17 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,13 @@ * Location to search for platform classes. Sometimes called * the boot class path. */ - PLATFORM_CLASS_PATH; + PLATFORM_CLASS_PATH, + + /** + * Location of new native header files. + * @since 1.8 + */ + NATIVE_HEADER_OUTPUT; /** * Gets a location object with the given name. The following @@ -97,6 +103,13 @@ public String getName() { return name(); } public boolean isOutputLocation() { - return this == CLASS_OUTPUT || this == SOURCE_OUTPUT; + switch (this) { + case CLASS_OUTPUT: + case SOURCE_OUTPUT: + case NATIVE_HEADER_OUTPUT: + return true; + default: + return false; + } } } diff -r ebfe9b8ce039 -r be069d72dde2 src/share/classes/javax/tools/annotation/GenerateNativeHeader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/javax/tools/annotation/GenerateNativeHeader.java Mon Mar 26 17:32:17 2012 -0700 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.tools.annotation; + +import java.lang.annotation.*; +import static java.lang.annotation.RetentionPolicy.*; +import static java.lang.annotation.ElementType.*; + +/** + * An annotation used to indicate that a native header file + * should be generated for this class. + * + * Normally, the presence of native methods is a sufficient + * indication of the need for a native header file. However, + * in some cases, a class may contain constants of interest to + * native code, without containing any native methods. + * + * @since 1.8 + */ +@Documented +@Target(TYPE) +@Retention(SOURCE) +public @interface GenerateNativeHeader { +} diff -r ebfe9b8ce039 -r be069d72dde2 test/tools/javac/api/7086261/T7086261.java --- a/test/tools/javac/api/7086261/T7086261.java Thu Mar 22 12:41:36 2012 -0700 +++ b/test/tools/javac/api/7086261/T7086261.java Mon Mar 26 17:32:17 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 20011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff -r ebfe9b8ce039 -r be069d72dde2 test/tools/javac/diags/CheckResourceKeys.java --- a/test/tools/javac/diags/CheckResourceKeys.java Thu Mar 22 12:41:36 2012 -0700 +++ b/test/tools/javac/diags/CheckResourceKeys.java Mon Mar 26 17:32:17 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,6 +259,7 @@ "application.home", // in Paths.java "env.class.path", "line.separator", + "os.name", "user.dir", // file names "ct.sym", diff -r ebfe9b8ce039 -r be069d72dde2 test/tools/javac/nativeHeaders/NativeHeaderTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/nativeHeaders/NativeHeaderTest.java Mon Mar 26 17:32:17 2012 -0700 @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7150368 + * @summary javac should include basic ability to generate native headers + */ + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; + +public class NativeHeaderTest { + public static void main(String... args) throws Exception { + new NativeHeaderTest().run(); + } + + /** How to invoke javac. */ + enum RunKind { + /** Use the command line entry point. */ + CMD, + /** Use the JavaCompiler API. */ + API + }; + + /** Which classes for which to generate headers. */ + enum GenKind { + /** Just classes with native methods or the marker annotation. */ + SIMPLE, + /** All appropriate classes within the top level class. */ + FULL + }; + + // ---------- Test cases, invoked reflectively via run. ---------- + + @Test + void simpleTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C { native void m(); }")); + + Set expect = createSet("C.h"); + + test(rk, gk, files, expect); + } + + @Test + void nestedClassTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C { static class Inner { native void m(); } }")); + + Set expect = createSet("C_Inner.h"); + if (gk == GenKind.FULL) expect.add("C.h"); + + test(rk, gk, files, expect); + } + + @Test + void localClassTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C { native void m(); void m2() { class Local { } } }")); + + Set expect = createSet("C.h"); + + test(rk, gk, files, expect); + } + + @Test + void syntheticClassTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C {\n" + + " private C() { }\n" + + " class Inner extends C { native void m(); }\n" + + "}")); + + Set expect = createSet("C_Inner.h"); + if (gk == GenKind.FULL) expect.add("C.h"); + + test(rk, gk, files, expect); + + // double check the synthetic class was generated + checkEqual("generatedClasses", + createSet("C.class", "C$1.class", "C$Inner.class"), + createSet(classesDir.list())); + } + + @Test + void annoTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "@javax.tools.annotation.GenerateNativeHeader class C { }")); + + Set expect = createSet("C.h"); + + test(rk, gk, files, expect); + } + + @Test + void annoNestedClassTest(RunKind rk, GenKind gk) throws Exception { + List files = new ArrayList(); + files.add(createFile("p/C.java", + "class C { @javax.tools.annotation.GenerateNativeHeader class Inner { } }")); + + Set expect = createSet("C_Inner.h"); + if (gk == GenKind.FULL) expect.add("C.h"); + + test(rk, gk, files, expect); + } + + /** + * The worker method for each test case. + * Compile the files and verify that exactly the expected set of header files + * is generated. + */ + void test(RunKind rk, GenKind gk, List files, Set expect) throws Exception { + List args = new ArrayList(); + if (gk == GenKind.FULL) + args.add("-XDjavah:full"); + + switch (rk) { + case CMD: + args.add("-d"); + args.add(classesDir.getPath()); + args.add("-h"); + args.add(headersDir.getPath()); + for (File f: files) + args.add(f.getPath()); + int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()])); + if (rc != 0) + throw new Exception("compilation failed, rc=" + rc); + break; + + case API: + fm.setLocation(StandardLocation.SOURCE_PATH, Arrays.asList(srcDir)); + fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(classesDir)); + fm.setLocation(StandardLocation.NATIVE_HEADER_OUTPUT, Arrays.asList(headersDir)); + JavacTask task = javac.getTask(null, fm, null, args, null, + fm.getJavaFileObjectsFromFiles(files)); + if (!task.call()) + throw new Exception("compilation failed"); + break; + } + + Set found = createSet(headersDir.list()); + checkEqual("header files", expect, found); + } + + /** Marker annotation for test cases. */ + @Retention(RetentionPolicy.RUNTIME) + @interface Test { } + + /** Combo test to run all test cases in all modes. */ + void run() throws Exception { + javac = JavacTool.create(); + fm = javac.getStandardFileManager(null, null, null); + + for (RunKind rk: RunKind.values()) { + for (GenKind gk: GenKind.values()) { + for (Method m: getClass().getDeclaredMethods()) { + Annotation a = m.getAnnotation(Test.class); + if (a != null) { + init(rk, gk, m.getName()); + try { + m.invoke(this, new Object[] { rk, gk }); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + throw (cause instanceof Exception) ? ((Exception) cause) : e; + } + System.err.println(); + } + } + } + } + System.err.println(testCount + " tests" + ((errorCount == 0) ? "" : ", " + errorCount + " errors")); + if (errorCount > 0) + throw new Exception(errorCount + " errors found"); + } + + /** + * Init directories for a test case. + */ + void init(RunKind rk, GenKind gk, String name) throws IOException { + System.err.println("Test " + rk + " " + gk + " " + name); + testCount++; + + testDir = new File(rk.toString().toLowerCase() + "_" + gk.toString().toLowerCase() + "-" + name); + srcDir = new File(testDir, "src"); + srcDir.mkdirs(); + classesDir = new File(testDir, "classes"); + classesDir.mkdirs(); + headersDir = new File(testDir, "headers"); + headersDir.mkdirs(); + } + + /** Create a source file with given body text. */ + File createFile(String path, final String body) throws IOException { + File f = new File(srcDir, path); + f.getParentFile().mkdirs(); + try (FileWriter out = new FileWriter(f)) { + out.write(body); + } + return f; + } + + /** Convenience method to create a set of items. */ + Set createSet(T... items) { + return new HashSet(Arrays.asList(items)); + } + + /** Convenience method to check two values are equal, and report an error if not. */ + void checkEqual(String label, T expect, T found) { + if ((found == null) ? (expect == null) : found.equals(expect)) + return; + System.err.println("Error: mismatch"); + System.err.println(" expected: " + expect); + System.err.println(" found: " + found); + errorCount++; + } + + // Shared across API test cases + JavacTool javac; + StandardJavaFileManager fm; + + // Directories set up by init + File testDir; + File srcDir; + File classesDir; + File headersDir; + + // Statistics + int testCount; + int errorCount; +} + diff -r ebfe9b8ce039 -r be069d72dde2 test/tools/javac/nativeHeaders/javahComparison/CompareTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/nativeHeaders/javahComparison/CompareTest.java Mon Mar 26 17:32:17 2012 -0700 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2007,2012 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7150368 + * @summary javac should include basic ability to generate native headers + */ + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class CompareTest { + public static void main(String... args) throws Exception { + new CompareTest().run(); + } + + void run() throws Exception { + File srcDir = new File(System.getProperty("test.src")); + File classesDir = new File("classes"); + classesDir.mkdirs(); + File javacHeaders = new File("headers.javac"); + javacHeaders.mkdirs(); + File javahHeaders = new File("headers.javah"); + javahHeaders.mkdirs(); + + List javacArgs = new ArrayList(); + javacArgs.add("-d"); + javacArgs.add(classesDir.getPath()); + javacArgs.add("-h"); + javacArgs.add(javacHeaders.getPath()); + javacArgs.add("-XDjavah:full"); + + for (File f: srcDir.listFiles()) { + if (f.getName().matches("TestClass[0-9]+\\.java")) { + sourceFileCount++; + javacArgs.add(f.getPath()); + } + } + + int rc = com.sun.tools.javac.Main.compile(javacArgs.toArray(new String[javacArgs.size()])); + if (rc != 0) + throw new Exception("javac failed; rc=" + rc); + + List javahArgs = new ArrayList(); + javahArgs.add("-d"); + javahArgs.add(javahHeaders.getPath()); + + for (File f: classesDir.listFiles()) { + if (f.getName().endsWith(".class")) { + javahArgs.add(inferBinaryName(f)); + } + } + + PrintWriter pw = new PrintWriter(System.out, true); + rc = com.sun.tools.javah.Main.run(javahArgs.toArray(new String[javahArgs.size()]), pw); + if (rc != 0) + throw new Exception("javah failed; rc=" + rc); + + compare(javahHeaders, javacHeaders); + + int javahHeaderCount = javahHeaders.list().length; + int javacHeaderCount = javacHeaders.list().length; + + System.out.println(sourceFileCount + " .java files found"); + System.out.println(javacHeaderCount + " .h files generated by javac"); + System.out.println(javahHeaderCount + " .h files generated by javah"); + System.out.println(compareCount + " header files compared"); + + if (javacHeaderCount != javahHeaderCount || javacHeaderCount != compareCount) + error("inconsistent counts"); + + if (errors > 0) + throw new Exception(errors + " errors occurred"); + } + + String inferBinaryName(File file) { + String name = file.getName(); + return name.substring(0, name.length() - ".class".length()).replace("$", "."); + } + + /** Compare two directories. + * @param f1 The golden directory + * @param f2 The directory to be compared + */ + void compare(File f1, File f2) { + compare(f1, f2, null); + } + + /** Compare two files or directories + * @param f1 The golden directory + * @param f2 The directory to be compared + * @param p An optional path identifying a file within the two directories + */ + void compare(File f1, File f2, String p) { + File f1p = (p == null ? f1 : new File(f1, p)); + File f2p = (p == null ? f2 : new File(f2, p)); + if (f1p.isDirectory() && f2p.isDirectory()) { + Set children = new HashSet(); + children.addAll(Arrays.asList(f1p.list())); + children.addAll(Arrays.asList(f2p.list())); + for (String c: children) { + compare(f1, f2, new File(p, c).getPath()); // null-safe for p + } + } + else if (f1p.isFile() && f2p.isFile()) { + System.out.println("checking " + p); + compareCount++; + String s1 = read(f1p); + String s2 = read(f2p); + if (!s1.equals(s2)) { + System.out.println("File: " + f1p + "\n" + s1); + System.out.println("File: " + f2p + "\n" + s2); + error("Files differ: " + f1p + " " + f2p); + } + } + else if (f1p.exists() && !f2p.exists()) + error("Only in " + f1 + ": " + p); + else if (f2p.exists() && !f1p.exists()) + error("Only in " + f2 + ": " + p); + else + error("Files differ: " + f1p + " " + f2p); + } + + private String read(File f) { + try { + return new String(Files.readAllBytes(f.toPath())); + } catch (IOException e) { + error("error reading " + f + ": " + e); + return ""; + } + } + + private void error(String msg) { + System.out.println(msg); + errors++; + } + + private int errors; + private int compareCount; + private int sourceFileCount; +} diff -r ebfe9b8ce039 -r be069d72dde2 test/tools/javac/nativeHeaders/javahComparison/TestClass1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/nativeHeaders/javahComparison/TestClass1.java Mon Mar 26 17:32:17 2012 -0700 @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.List; + +public class TestClass1 { + // simple types + byte b; + short s; + int i; + long l; + float f; + double d; + Object o; + String t; + List g; + + // constants + static final byte bc = 0; + static final short sc = 0; + static final int ic = 0; + static final long lc = 0; + static final float fc = 0; + static final double dc = 0; + static final Object oc = null; + static final String tc = ""; + static final List gc = null; + + // simple arrays + byte[] ba; + short[] sa; // not handled corrected by javah v6 + int[] ia; + long[] la; + float[] fa; + double[] da; + Object[] oa; + String[] ta; + List[] ga; + + // multidimensional arrays + byte[][] baa; + short[][] saa; + int[][] iaa; + long[][] laa; + float[][] faa; + double[][] daa; + Object[][] oaa; + String[][] taa; + List[] gaa; + + // simple Java methods + byte bm() { return 0; } + short sm() { return 0; } + int im() { return 0; } + long lm() { return 0; } + float fm() { return 0; } + double dm() { return 0; } + Object om() { return null; } + String tm() { return ""; } + List gm() { return null; } + void vm() { } + byte[] bam() { return null; } + short[] sam() { return null; } + int[] iam() { return null; } + long[] lam() { return null; } + float[] fam() { return null; } + double[] dam() { return null; } + Object[] oam() { return null; } + String[] tam() { return null; } + List[] gam() { return null; } + byte[][] baam() { return null; } + short[][] saam() { return null; } + int[][] iaam() { return null; } + long[][] laam() { return null; } + float[][] faam() { return null; } + double[][] daam() { return null; } + Object[][] oaam() { return null; } + String[][] taam() { return null; } + List[] gaam() { return null; } + + // simple native methods + native byte bmn(); + native short smn(); + native int imn(); + native long lmn(); + native float fmn(); + native double dmn(); + native Object omn(); + native String tmn(); + native List gmn(); + native void vmn(); + native byte[] bamn(); + native short[] samn(); + native int[] iamn(); + native long[] lamn(); + native float[] famn(); + native double[] damn(); + native Object[] oamn(); + native String[] tamn(); + native List[] gamn(); + native byte[][] baamn(); + native short[][] saamn(); + native int[][] iaamn(); + native long[][] laamn(); + native float[][] faamn(); + native double[][] daamn(); + native Object[][] oaamn(); + native String[][] taamn(); + native List[] gaamn(); + + // overloaded Java methods + byte bm1() { return 0; } + short sm1() { return 0; } + int im1() { return 0; } + long lm1() { return 0; } + float fm1() { return 0; } + double dm1() { return 0; } + Object om1() { return null; } + String tm1() { return ""; } + List gm1() { return null; } + void vm1() { } + + byte bm2(int i) { return 0; } + short sm2(int i) { return 0; } + int im2(int i) { return 0; } + long lm2(int i) { return 0; } + float fm2(int i) { return 0; } + double dm2(int i) { return 0; } + Object om2(int i) { return null; } + String tm2(int i) { return ""; } + List gm2(int i) { return null; } + void vm2(int i) { } + + // overloaded native methods + native byte bmn1(); + native short smn1(); + native int imn1(); + native long lmn1(); + native float fmn1(); + native double dmn1(); + native Object omn1(); + native String tmn1(); + native List gmn1(); + native void vmn1(); + + native byte bmn2(int i); + native short smn2(int i); + native int imn2(int i); + native long lmn2(int i); + native float fmn2(int i); + native double dmn2(int i); + native Object omn2(int i); + native String tmn2(int i); + native List gmn2(int i); + native void vmn2(int i); + + // arg types for Java methods + void mb(byte b) { } + void ms(short s) { } + void mi(int i) { } + void ml(long l) { } + void mf(float f) { } + void md(double d) { } + void mo(Object o) { } + void mt(String t) { } + void mg(List g) { } + + // arg types for native methods + native void mbn(byte b); + native void msn(short s); + native void min(int i); + native void mln(long l); + native void mfn(float f); + native void mdn(double d); + native void mon(Object o); + native void mtn(String t); + native void mgn(List g); + + static class Inner1 { + // simple types + byte b; + short s; + int i; + long l; + float f; + double d; + Object o; + String t; + List g; + + // constants + static final byte bc = 0; + static final short sc = 0; + static final int ic = 0; + static final long lc = 0; + static final float fc = 0; + static final double dc = 0; + static final Object oc = null; + static final String tc = ""; + static final List gc = null; + + // simple arrays + byte[] ba; + // short[] sa; // not handled corrected by javah v6 + int[] ia; + long[] la; + float[] fa; + double[] da; + Object[] oa; + String[] ta; + List[] ga; + + // multidimensional arrays + byte[][] baa; + short[][] saa; + int[][] iaa; + long[][] laa; + float[][] faa; + double[][] daa; + Object[][] oaa; + String[][] taa; + List[] gaa; + + // simple Java methods + byte bm() { return 0; } + short sm() { return 0; } + int im() { return 0; } + long lm() { return 0; } + float fm() { return 0; } + double dm() { return 0; } + Object om() { return null; } + String tm() { return ""; } + List gm() { return null; } + void vm() { } + + // simple native methods + native byte bmn(); + native short smn(); + native int imn(); + native long lmn(); + native float fmn(); + native double dmn(); + native Object omn(); + native String tmn(); + native List gmn(); + native void vmn(); + + // overloaded Java methods + byte bm1() { return 0; } + short sm1() { return 0; } + int im1() { return 0; } + long lm1() { return 0; } + float fm1() { return 0; } + double dm1() { return 0; } + Object om1() { return null; } + String tm1() { return ""; } + List gm1() { return null; } + void vm1() { } + + byte bm2(int i) { return 0; } + short sm2(int i) { return 0; } + int im2(int i) { return 0; } + long lm2(int i) { return 0; } + float fm2(int i) { return 0; } + double dm2(int i) { return 0; } + Object om2(int i) { return null; } + String tm2(int i) { return ""; } + List gm2(int i) { return null; } + void vm2(int i) { } + + // overloaded native methods + native byte bmn1(); + native short smn1(); + native int imn1(); + native long lmn1(); + native float fmn1(); + native double dmn1(); + native Object omn1(); + native String tmn1(); + native List gmn1(); + native void vmn1(); + + native byte bmn2(int i); + native short smn2(int i); + native int imn2(int i); + native long lmn2(int i); + native float fmn2(int i); + native double dmn2(int i); + native Object omn2(int i); + native String tmn2(int i); + native List gmn2(int i); + native void vmn2(int i); + + // arg types for Java methods + void mb(byte b) { } + void ms(short s) { } + void mi(int i) { } + void ml(long l) { } + void mf(float f) { } + void md(double d) { } + void mo(Object o) { } + void mt(String t) { } + void mg(List g) { } + + // arg types for native methods + native void mbn(byte b); + native void msn(short s); + native void min(int i); + native void mln(long l); + native void mfn(float f); + native void mdn(double d); + native void mon(Object o); + native void mtn(String t); + native void mgn(List g); + } + + class Inner2 { + // simple types + byte b; + short s; + int i; + long l; + float f; + double d; + Object o; + String t; + List g; + + // constants + static final byte bc = 0; + static final short sc = 0; + static final int ic = 0; + static final long lc = 0; + static final float fc = 0; + static final double dc = 0; + //static final Object oc = null; + static final String tc = ""; + //static final List gc = null; + + // simple arrays + byte[] ba; + // short[] sa; // not handled corrected by javah v6 + int[] ia; + long[] la; + float[] fa; + double[] da; + Object[] oa; + String[] ta; + List[] ga; + + // multidimensional arrays + byte[][] baa; + short[][] saa; + int[][] iaa; + long[][] laa; + float[][] faa; + double[][] daa; + Object[][] oaa; + String[][] taa; + List[] gaa; + + // simple Java methods + byte bm() { return 0; } + short sm() { return 0; } + int im() { return 0; } + long lm() { return 0; } + float fm() { return 0; } + double dm() { return 0; } + Object om() { return null; } + String tm() { return ""; } + List gm() { return null; } + void vm() { } + + // simple native methods + native byte bmn(); + native short smn(); + native int imn(); + native long lmn(); + native float fmn(); + native double dmn(); + native Object omn(); + native String tmn(); + native List gmn(); + native void vmn(); + + // overloaded Java methods + byte bm1() { return 0; } + short sm1() { return 0; } + int im1() { return 0; } + long lm1() { return 0; } + float fm1() { return 0; } + double dm1() { return 0; } + Object om1() { return null; } + String tm1() { return ""; } + List gm1() { return null; } + void vm1() { } + + byte bm2(int i) { return 0; } + short sm2(int i) { return 0; } + int im2(int i) { return 0; } + long lm2(int i) { return 0; } + float fm2(int i) { return 0; } + double dm2(int i) { return 0; } + Object om2(int i) { return null; } + String tm2(int i) { return ""; } + List gm2(int i) { return null; } + void vm2(int i) { } + + // overloaded native methods + native byte bmn1(); + native short smn1(); + native int imn1(); + native long lmn1(); + native float fmn1(); + native double dmn1(); + native Object omn1(); + native String tmn1(); + native List gmn1(); + native void vmn1(); + + native byte bmn2(int i); + native short smn2(int i); + native int imn2(int i); + native long lmn2(int i); + native float fmn2(int i); + native double dmn2(int i); + native Object omn2(int i); + native String tmn2(int i); + native List gmn2(int i); + native void vmn2(int i); + + // arg types for Java methods + void mb(byte b) { } + void ms(short s) { } + void mi(int i) { } + void ml(long l) { } + void mf(float f) { } + void md(double d) { } + void mo(Object o) { } + void mt(String t) { } + void mg(List g) { } + + // arg types for native methods + native void mbn(byte b); + native void msn(short s); + native void min(int i); + native void mln(long l); + native void mfn(float f); + native void mdn(double d); + native void mon(Object o); + native void mtn(String t); + native void mgn(List g); + } + +} diff -r ebfe9b8ce039 -r be069d72dde2 test/tools/javac/nativeHeaders/javahComparison/TestClass2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/nativeHeaders/javahComparison/TestClass2.java Mon Mar 26 17:32:17 2012 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.tools.annotation.GenerateNativeHeader; + +@GenerateNativeHeader +public class TestClass2 { + byte b; + short s; + int i; + long l; + float f; + double d; + Object o; + String t; +} diff -r ebfe9b8ce039 -r be069d72dde2 test/tools/javac/nativeHeaders/javahComparison/TestClass3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/nativeHeaders/javahComparison/TestClass3.java Mon Mar 26 17:32:17 2012 -0700 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.tools.annotation.GenerateNativeHeader; + +@GenerateNativeHeader +public class TestClass3 { + public int tc3; + + public class Inner1 { + public int tc3i1; + + public class Inner1A { + public int tc3i1i1a; + } + + public class Inner1B { + public int tc3i1i1b; + } + } + + public class Inner2 { + public int tc321; + + public class Inner2A { + public int tc3i2i2a; + } + + public class Inner2B { + public int tc3i2i2b; + } + } +} +