# HG changeset patch # User jjg # Date 1286914787 25200 # Node ID b6fea484cbb2186e420d0a3fef9a6243238e92c8 # Parent 81a6a7c1bef1737076d28333f5c46c93e10ac6e5 4942232: missing param class processes without error Reviewed-by: darcy diff -r 81a6a7c1bef1 -r b6fea484cbb2 langtools/src/share/classes/com/sun/tools/javah/JNI.java --- a/langtools/src/share/classes/com/sun/tools/javah/JNI.java Tue Oct 12 13:15:46 2010 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javah/JNI.java Tue Oct 12 13:19:47 2010 -0700 @@ -59,72 +59,76 @@ } public void write(OutputStream o, TypeElement clazz) throws Util.Exit { - String cname = mangler.mangle(clazz.getQualifiedName(), Mangle.Type.CLASS); - PrintWriter pw = wrapWriter(o); - pw.println(guardBegin(cname)); - pw.println(cppGuardBegin()); + try { + String cname = mangler.mangle(clazz.getQualifiedName(), Mangle.Type.CLASS); + PrintWriter pw = wrapWriter(o); + pw.println(guardBegin(cname)); + pw.println(cppGuardBegin()); - /* Write statics. */ - List classfields = getAllFields(clazz); + /* Write statics. */ + List classfields = getAllFields(clazz); - for (VariableElement v: classfields) { - if (!v.getModifiers().contains(Modifier.STATIC)) - continue; - String s = null; - s = defineForStatic(clazz, v); - if (s != null) { - pw.println(s); + for (VariableElement v: classfields) { + if (!v.getModifiers().contains(Modifier.STATIC)) + continue; + String s = null; + s = defineForStatic(clazz, v); + if (s != null) { + pw.println(s); + } } - } - /* Write methods. */ - List classmethods = ElementFilter.methodsIn(clazz.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(elems); - 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; + /* Write methods. */ + List classmethods = ElementFilter.methodsIn(clazz.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(elems); + 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; + } + pw.println("/*"); + pw.println(" * Class: " + cname); + pw.println(" * Method: " + + mangler.mangle(methodName, Mangle.Type.FIELDSTUB)); + pw.println(" * Signature: " + newtypesig.getTypeSignature(sig, mtr)); + pw.println(" */"); + pw.println("JNIEXPORT " + jniType(mtr) + + " JNICALL " + + mangler.mangleMethod(md, clazz, + (longName) ? + Mangle.Type.METHOD_JNI_LONG : + Mangle.Type.METHOD_JNI_SHORT)); + pw.print(" (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)) + pw.print("jclass"); + else + pw.print("jobject"); + + for (TypeMirror arg: args) { + pw.print(", "); + pw.print(jniType(arg)); + } + pw.println(");" + lineSep); } - pw.println("/*"); - pw.println(" * Class: " + cname); - pw.println(" * Method: " + - mangler.mangle(methodName, Mangle.Type.FIELDSTUB)); - pw.println(" * Signature: " + newtypesig.getTypeSignature(sig, mtr)); - pw.println(" */"); - pw.println("JNIEXPORT " + jniType(mtr) + - " JNICALL " + - mangler.mangleMethod(md, clazz, - (longName) ? - Mangle.Type.METHOD_JNI_LONG : - Mangle.Type.METHOD_JNI_SHORT)); - pw.print(" (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)) - pw.print("jclass"); - else - pw.print("jobject"); - - for (TypeMirror arg: args) { - pw.print(", "); - pw.print(jniType(arg)); - } - pw.println(");" + lineSep); } + pw.println(cppGuardEnd()); + pw.println(guardEnd(cname)); + } catch (TypeSignature.SignatureException e) { + util.error("jni.sigerror", e.getMessage()); } - pw.println(cppGuardEnd()); - pw.println(guardEnd(cname)); } diff -r 81a6a7c1bef1 -r b6fea484cbb2 langtools/src/share/classes/com/sun/tools/javah/JavahTask.java --- a/langtools/src/share/classes/com/sun/tools/javah/JavahTask.java Tue Oct 12 13:15:46 2010 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javah/JavahTask.java Tue Oct 12 13:19:47 2010 -0700 @@ -46,9 +46,9 @@ import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Messager; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.ExecutableElement; @@ -71,6 +71,9 @@ import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import javax.tools.ToolProvider; +import static javax.tools.Diagnostic.Kind.*; + +import com.sun.tools.javac.code.Symbol.CompletionFailure; /** * Javah generates support files for native methods. @@ -233,6 +236,15 @@ task.doubleAlign = true; } }, + + new HiddenOption(false) { + boolean matches(String opt) { + return opt.startsWith("-XD"); + } + void process(JavahTask task, String opt, String arg) { + task.javac_extras.add(opt); + } + }, }; JavahTask() { @@ -326,6 +338,8 @@ } catch (InternalError e) { diagnosticListener.report(createDiagnostic("err.internal.error", e.getMessage())); return 1; + } catch (Util.Exit e) { + return e.exitValue; } finally { log.flush(); } @@ -475,7 +489,9 @@ ((JavahFileManager) fileManager).setIgnoreSymbolFile(true); JavaCompiler c = ToolProvider.getSystemJavaCompiler(); - List opts = Arrays.asList("-proc:only"); + List opts = new ArrayList(); + opts.add("-proc:only"); + opts.addAll(javac_extras); CompilationTask t = c.getTask(log, fileManager, diagnosticListener, opts, internalize(classes), null); JavahProcessor p = new JavahProcessor(g); t.setProcessors(Collections.singleton(p)); @@ -642,6 +658,7 @@ boolean doubleAlign; boolean force; boolean old; + Set javac_extras = new LinkedHashSet(); PrintWriter log; JavaFileManager fileManager; @@ -652,30 +669,45 @@ private static final String progname = "javah"; @SupportedAnnotationTypes("*") - @SupportedSourceVersion(SourceVersion.RELEASE_7) class JavahProcessor extends AbstractProcessor { + private Messager messager; + JavahProcessor(Gen g) { this.g = g; } - public boolean process(Set annotations, RoundEnvironment roundEnv) { - Messager messager = processingEnv.getMessager(); - Set classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements())); - if (classes.size() > 0) { - checkMethodParameters(classes); - g.setProcessingEnvironment(processingEnv); - g.setClasses(classes); + @Override + public SourceVersion getSupportedSourceVersion() { + // since this is co-bundled with javac, we can assume it supports + // the latest source version + return SourceVersion.latest(); + } + + @Override + public void init(ProcessingEnvironment pEnv) { + super.init(pEnv); + messager = processingEnv.getMessager(); + } - try { + public boolean process(Set annotations, RoundEnvironment roundEnv) { + try { + Set classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements())); + if (classes.size() > 0) { + checkMethodParameters(classes); + g.setProcessingEnvironment(processingEnv); + g.setClasses(classes); g.run(); - } catch (ClassNotFoundException cnfe) { - messager.printMessage(Diagnostic.Kind.ERROR, getMessage("class.not.found", cnfe.getMessage())); - } catch (IOException ioe) { - messager.printMessage(Diagnostic.Kind.ERROR, getMessage("io.exception", ioe.getMessage())); - } catch (Util.Exit e) { - exit = e; } + } catch (CompletionFailure cf) { + messager.printMessage(ERROR, getMessage("class.not.found", cf.sym.getQualifiedName().toString())); + } catch (ClassNotFoundException cnfe) { + messager.printMessage(ERROR, getMessage("class.not.found", cnfe.getMessage())); + } catch (IOException ioe) { + messager.printMessage(ERROR, getMessage("io.exception", ioe.getMessage())); + } catch (Util.Exit e) { + exit = e; } + return true; } diff -r 81a6a7c1bef1 -r b6fea484cbb2 langtools/src/share/classes/com/sun/tools/javah/LLNI.java --- a/langtools/src/share/classes/com/sun/tools/javah/LLNI.java Tue Oct 12 13:15:46 2010 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javah/LLNI.java Tue Oct 12 13:19:47 2010 -0700 @@ -74,16 +74,21 @@ } protected void write(OutputStream o, TypeElement clazz) throws Util.Exit { - String cname = mangleClassName(clazz.getQualifiedName().toString()); - PrintWriter pw = wrapWriter(o); - fields = ElementFilter.fieldsIn(clazz.getEnclosedElements()); - methods = ElementFilter.methodsIn(clazz.getEnclosedElements()); - generateDeclsForClass(pw, clazz, cname); - // FIXME check if errors occurred on the PrintWriter and throw exception if so + try { + String cname = mangleClassName(clazz.getQualifiedName().toString()); + PrintWriter pw = wrapWriter(o); + fields = ElementFilter.fieldsIn(clazz.getEnclosedElements()); + methods = ElementFilter.methodsIn(clazz.getEnclosedElements()); + generateDeclsForClass(pw, clazz, cname); + // FIXME check if errors occurred on the PrintWriter and throw exception if so + } catch (TypeSignature.SignatureException e) { + util.error("llni.sigerror", e.getMessage()); + } } protected void generateDeclsForClass(PrintWriter pw, - TypeElement clazz, String cname) throws Util.Exit { + TypeElement clazz, String cname) + throws TypeSignature.SignatureException, Util.Exit { doneHandleTypes = new HashSet(); /* The following handle types are predefined in "typedefs.h". Suppress inclusion in the output by generating them "into the blue" here. */ @@ -127,7 +132,8 @@ .replace(innerDelim, '_'); } - protected void forwardDecls(PrintWriter pw, TypeElement clazz) { + protected void forwardDecls(PrintWriter pw, TypeElement clazz) + throws TypeSignature.SignatureException { TypeElement object = elems.getTypeElement("java.lang.Object"); if (clazz.equals(object)) return; @@ -403,7 +409,7 @@ protected void methodSectionForClass(PrintWriter pw, TypeElement clazz, String cname) - throws Util.Exit { + throws TypeSignature.SignatureException, Util.Exit { String methods = methodDecls(clazz, cname); if (methods.length() != 0) { @@ -418,7 +424,8 @@ } } - protected String methodDecls(TypeElement clazz, String cname) throws Util.Exit { + protected String methodDecls(TypeElement clazz, String cname) + throws TypeSignature.SignatureException, Util.Exit { String res = ""; for (ExecutableElement method: methods) { @@ -430,7 +437,7 @@ protected String methodDecl(ExecutableElement method, TypeElement clazz, String cname) - throws Util.Exit { + throws TypeSignature.SignatureException, Util.Exit { String res = null; TypeMirror retType = types.erasure(method.getReturnType()); @@ -474,7 +481,8 @@ } protected final String jniMethodName(ExecutableElement method, String cname, - boolean longName) { + boolean longName) + throws TypeSignature.SignatureException { String res = "Java_" + cname + "_" + method.getSimpleName(); if (longName) { diff -r 81a6a7c1bef1 -r b6fea484cbb2 langtools/src/share/classes/com/sun/tools/javah/Mangle.java --- a/langtools/src/share/classes/com/sun/tools/javah/Mangle.java Tue Oct 12 13:15:46 2010 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javah/Mangle.java Tue Oct 12 13:19:47 2010 -0700 @@ -114,7 +114,7 @@ } public String mangleMethod(ExecutableElement method, TypeElement clazz, - int mtype) { + int mtype) throws TypeSignature.SignatureException { StringBuffer result = new StringBuffer(100); result.append("Java_"); diff -r 81a6a7c1bef1 -r b6fea484cbb2 langtools/src/share/classes/com/sun/tools/javah/TypeSignature.java --- a/langtools/src/share/classes/com/sun/tools/javah/TypeSignature.java Tue Oct 12 13:15:46 2010 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javah/TypeSignature.java Tue Oct 12 13:19:47 2010 -0700 @@ -51,7 +51,13 @@ * @author Sucheta Dambalkar */ -public class TypeSignature{ +public class TypeSignature { + static class SignatureException extends Exception { + private static final long serialVersionUID = 1L; + SignatureException(String reason) { + super(reason); + } + } Elements elems; @@ -78,14 +84,15 @@ /* * Returns the type signature of a field according to JVM specs */ - public String getTypeSignature(String javasignature){ + 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){ + 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. @@ -166,7 +173,7 @@ /* * Returns internal signature of a parameter. */ - private String getParamJVMSignature(String paramsig) { + private String getParamJVMSignature(String paramsig) throws SignatureException { String paramJVMSig = ""; String componentType =""; @@ -197,7 +204,7 @@ /* * Returns internal signature of a component. */ - private String getComponentType(String componentType){ + private String getComponentType(String componentType) throws SignatureException { String JVMSig = ""; @@ -216,8 +223,7 @@ TypeElement classNameDoc = elems.getTypeElement(componentType); if(classNameDoc == null){ - System.out.println("Invalid class type for " + componentType); - new Exception().printStackTrace(); + throw new SignatureException(componentType); }else { String classname = classNameDoc.getQualifiedName().toString(); String newclassname = classname.replace('.', '/'); diff -r 81a6a7c1bef1 -r b6fea484cbb2 langtools/src/share/classes/com/sun/tools/javah/resources/l10n.properties --- a/langtools/src/share/classes/com/sun/tools/javah/resources/l10n.properties Tue Oct 12 13:15:46 2010 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javah/resources/l10n.properties Tue Oct 12 13:19:47 2010 -0700 @@ -45,6 +45,8 @@ Can''t mix options -jni and -llni. Try -help. jni.no.stubs=\ JNI does not require stubs, please refer to the JNI documentation. +jni.sigerror=\ + Cannot determine signature for {0} dir.file.mixed=\ Can''t mix options -d and -o. Try -help. no.classes.specified=\ diff -r 81a6a7c1bef1 -r b6fea484cbb2 langtools/test/tools/javah/4942232/ParamClassTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javah/4942232/ParamClassTest.java Tue Oct 12 13:19:47 2010 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010, 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. + */ + +public class ParamClassTest { + static { + System.loadLibrary("Test"); + } + + public native void method(Param s); + + public static void main(String[] a) { + } +} + +class Param { +} diff -r 81a6a7c1bef1 -r b6fea484cbb2 langtools/test/tools/javah/4942232/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javah/4942232/Test.java Tue Oct 12 13:19:47 2010 -0700 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2010, 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 4942232 + * @summary missing param class processes without error + * @build ParamClassTest Test + * @run main Test + */ + +import java.io.*; +import java.util.*; + +public class Test { + public static void main(String... args) throws Exception { + new Test().run(); + } + + void run() throws Exception { + File testSrc = new File(System.getProperty("test.src")); + File testClasses = new File(System.getProperty("test.classes")); + + // standard use of javah on valid class file + String[] test1Args = { + "-d", mkdir("test1/out").getPath(), + "-classpath", testClasses.getPath(), + "ParamClassTest" + }; + test(test1Args, 0); + + // extended use of javah on valid source file + String[] test2Args = { + "-d", mkdir("test2/out").getPath(), + "-classpath", testSrc.getPath(), + "ParamClassTest" + }; + test(test2Args, 0); + + // javah on class file with missing referents + File test3Classes = mkdir("test3/classes"); + copy(new File(testClasses, "ParamClassTest.class"), test3Classes); + String[] test3Args = { + "-d", mkdir("test3/out").getPath(), + "-classpath", test3Classes.getPath(), + "ParamClassTest" + }; + test(test3Args, 1); + + // javah on source file with missing referents + File test4Src = mkdir("test4/src"); + String paramClassTestSrc = readFile(new File(testSrc, "ParamClassTest.java")); + writeFile(new File(test4Src, "ParamClassTest.java"), + paramClassTestSrc.replaceAll("class Param \\{\\s+\\}", "")); + String[] test4Args = { + "-d", mkdir("test4/out").getPath(), + "-classpath", test4Src.getPath(), + "ParamClassTest" + }; + test(test4Args, 15); + + if (errors > 0) + throw new Exception(errors + " errors occurred"); + } + + void test(String[] args, int expect) { + System.err.println("test: " + Arrays.asList(args)); + int rc = javah(args); + if (rc != expect) + error("Unexpected return code: " + rc + "; expected: " + expect); + } + + int javah(String... args) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + int rc = com.sun.tools.javah.Main.run(args, pw); + pw.close(); + String out = sw.toString(); + if (!out.isEmpty()) + System.err.println(out); + return rc; + } + + File mkdir(String path) { + File f = new File(path); + f.mkdirs(); + return f; + } + + void copy(File from, File to) throws IOException { + if (to.isDirectory()) + to = new File(to, from.getName()); + try (DataInputStream in = new DataInputStream(new FileInputStream(from)); + FileOutputStream out = new FileOutputStream(to)) { + byte[] buf = new byte[(int) from.length()]; + in.readFully(buf); + out.write(buf); + } + } + + String readFile(File f) throws IOException { + try (DataInputStream in = new DataInputStream(new FileInputStream(f))) { + byte[] buf = new byte[(int) f.length()]; + in.readFully(buf); + return new String(buf); + } + } + + void writeFile(File f, String body) throws IOException { + try (FileWriter out = new FileWriter(f)) { + out.write(body); + } + } + + void error(String msg) { + System.err.println(msg); + errors++; + } + + int errors; +}