# HG changeset patch # User duke # Date 1499267066 -7200 # Node ID ade55a65b0f253ca594ca0fc1a4e402f31deedbd # Parent fcbbd4d495815eef3653c9d953436273eeea17a4# Parent 80dcc8ac5696a351335c69852f895d052c61073b Merge diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/.hgignore --- a/langtools/.hgignore Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/.hgignore Wed Jul 05 17:04:26 2017 +0200 @@ -1,3 +1,3 @@ ^build/ ^dist/ -^nbproject/private/ +/nbproject/private/ diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/.hgtags --- a/langtools/.hgtags Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/.hgtags Wed Jul 05 17:04:26 2017 +0200 @@ -51,3 +51,4 @@ 1a66b08deed0459054b5b1bea3dfbead30d258fa jdk7-b74 2485f5641ed0829205aaaeb31ad711c2c2ef0de3 jdk7-b75 8fb9b4be3cb1574302acde90549a4d333ef51e93 jdk7-b76 +0398ae15b90ac76d87ee21844453e95ff8613e43 jdk7-b77 diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/make/Makefile --- a/langtools/make/Makefile Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/make/Makefile Wed Jul 05 17:04:26 2017 +0200 @@ -133,6 +133,23 @@ ANT_JAVA_HOME = JAVA_HOME=$(ALT_BOOTDIR) endif +# To facilitate bootstrapping, much of langtools can be compiled with (just) +# a boot JDK. However, some source files need to be compiled against +# new JDK API. In a bootstrap build, an import JDK may not be available, +# so build.xml can also build against the source files in a jdk repo, +# in which case it will automatically generate stub files for the new JDK API. +ifdef JDK_TOPDIR + ANT_OPTIONS += -Dimport.jdk=$(JDK_TOPDIR) +else + ifdef ALT_JDK_TOPDIR + ANT_OPTIONS += -Dimport.jdk=$(ALT_JDK_TOPDIR) + else + ifdef ALT_JDK_IMPORT_DIR + ANT_OPTIONS += -Dimport.jdk=$(ALT_JDK_IMPORT_DIR) + endif + endif +endif + ifdef ALT_OUTPUTDIR OUTPUTDIR = $(ALT_OUTPUTDIR) ANT_OPTIONS += -Dbuild.dir=$(ALT_OUTPUTDIR)/build diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/make/build.properties --- a/langtools/make/build.properties Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/make/build.properties Wed Jul 05 17:04:26 2017 +0200 @@ -148,6 +148,13 @@ # +# The following files require the import JDK to be available +require.import.jdk.files = + +# The following files in the import jdk source directory are required +# in order to compile the files defined in ${require.import.jdk.files} +import.jdk.stub.files = + # The following value is used by the main jtreg target. # An empty value means all tests # Override as desired to run a specific set of tests diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/make/build.xml --- a/langtools/make/build.xml Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/make/build.xml Wed Jul 05 17:04:26 2017 +0200 @@ -56,6 +56,7 @@ + @@ -93,6 +94,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -108,11 +144,17 @@ - + - + - + + + @@ -188,23 +230,27 @@ - - + + + + - - + + - - + + + - + @@ -217,19 +263,20 @@ - + + + - + - - + + @@ -249,21 +296,19 @@ - + + - + - + - + @@ -281,19 +326,19 @@ - + + + - - + + + - + @@ -310,21 +355,23 @@ - - + + + + - + - - + + @@ -342,19 +389,19 @@ - + + + - - + + + - + @@ -372,6 +419,17 @@ + + + + + + + @@ -396,40 +454,12 @@ - + - - - - - - - - - - - - - - @@ -442,35 +472,15 @@ - + - - - - - - - - - - - + - - - + + + + + + + + + + - - - - - + + - + - - + @@ -562,30 +567,32 @@ + java="${boot.java}"/> + + + + + + + full.version="${bootstrap.full.version}" + excludes="${require.import.jdk.files} **/package-info.java"/> @@ -603,6 +610,20 @@ classpath="${build.toolclasses.dir}/"/> + + + + + + @@ -764,7 +785,7 @@ + description="display settings of configuration values"> ant.home = ${ant.home} boot.java.home = ${boot.java.home} target.java.home = ${target.java.home} diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/make/tools/GenStubs/GenStubs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/make/tools/GenStubs/GenStubs.java Wed Jul 05 17:04:26 2017 +0200 @@ -0,0 +1,392 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +import java.io.*; +import java.util.*; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.taskdefs.MatchingTask; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Reference; + + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.TypeTags; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCLiteral; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.Pretty; +import com.sun.tools.javac.tree.TreeTranslator; + +/** + * Generate stub source files by removing implementation details from input files. + * + * This is a special purpose stub generator, specific to the needs of generating + * stub files for JDK 7 API that are needed to compile langtools files that depend + * on that API. The stub generator works by removing as much of the API source code + * as possible without affecting the public signature, in order to reduce the + * transitive closure of the API being referenced. The resulting stubs can be + * put on the langtools sourcepath with -implicit:none to compile the langtools + * files that depend on the JDK 7 API. + * + * Usage: + * genstubs -s -sourcepath + * + * The specified class names are looked up on the sourcepath, and corresponding + * stubs are written to the source output directory. + * + * Classes are parsed into javac ASTs, then processed with a javac TreeTranslator + * to remove implementation details, and written out in the source output directory. + * Documentation comments and annotations are removed. Method bodies are removed + * and methods are marked native. Private and package-private field definitions + * have their initializers replace with 0, 0.0, false, null as appropriate. + * + * An Ant task, Main$Ant is also provided. Files are specified with an implicit + * fileset, using srcdir as a base directory. The set of files to be included + * is specified with an includes attribute or nested set. However, + * unlike a normal fileset, an empty includes attribute means "no files" instead + * of "all files". The Ant task also accepts "fork=true" and classpath attribute + * or nested element to run GenStubs in a separate VM with the specified + * path. This is likely necessary if a JDK 7 parser is required to read the + * JDK 7 input files. + */ + +public class GenStubs { + static class Fault extends Exception { + private static final long serialVersionUID = 0; + Fault(String message) { + super(message); + } + Fault(String message, Throwable cause) { + super(message); + initCause(cause); + } + } + + public static void main(String[] args) { + boolean ok = new GenStubs().run(args); + if (!ok) + System.exit(1); + } + + boolean run(String... args) { + File outdir = null; + String sourcepath = null; + List classes = new ArrayList(); + for (ListIterator iter = Arrays.asList(args).listIterator(); iter.hasNext(); ) { + String arg = iter.next(); + if (arg.equals("-s") && iter.hasNext()) + outdir = new File(iter.next()); + else if (arg.equals("-sourcepath") && iter.hasNext()) + sourcepath = iter.next(); + else if (arg.startsWith("-")) + throw new IllegalArgumentException(arg); + else { + classes.add(arg); + while (iter.hasNext()) + classes.add(iter.next()); + } + } + + return run(sourcepath, outdir, classes); + } + + boolean run(String sourcepath, File outdir, List classes) { + //System.err.println("run: sourcepath:" + sourcepath + " outdir:" + outdir + " classes:" + classes); + if (sourcepath == null) + throw new IllegalArgumentException("sourcepath not set"); + if (outdir == null) + throw new IllegalArgumentException("source output dir not set"); + + JavacTool tool = JavacTool.create(); + StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null); + + try { + fm.setLocation(StandardLocation.SOURCE_OUTPUT, Collections.singleton(outdir)); + fm.setLocation(StandardLocation.SOURCE_PATH, splitPath(sourcepath)); + List files = new ArrayList(); + for (String c: classes) { + JavaFileObject fo = fm.getJavaFileForInput( + StandardLocation.SOURCE_PATH, c, JavaFileObject.Kind.SOURCE); + if (fo == null) + error("class not found: " + c); + else + files.add(fo); + } + + JavacTask t = tool.getTask(null, fm, null, null, null, files); + Iterable trees = t.parse(); + for (CompilationUnitTree tree: trees) { + makeStub(fm, tree); + } + } catch (IOException e) { + error("IO error " + e, e); + } + + return (errors == 0); + } + + void makeStub(StandardJavaFileManager fm, CompilationUnitTree tree) throws IOException { + CompilationUnitTree tree2 = new StubMaker().translate(tree); + + String className = fm.inferBinaryName(StandardLocation.SOURCE_PATH, tree.getSourceFile()); + JavaFileObject fo = fm.getJavaFileForOutput(StandardLocation.SOURCE_OUTPUT, + className, JavaFileObject.Kind.SOURCE, null); + // System.err.println("Writing " + className + " to " + fo.getName()); + Writer out = fo.openWriter(); + try { + new Pretty(out, true).printExpr((JCTree) tree2); + } finally { + out.close(); + } + } + + List splitPath(String path) { + List list = new ArrayList(); + for (String p: path.split(File.pathSeparator)) { + if (p.length() > 0) + list.add(new File(p)); + } + return list; + } + + void error(String message) { + System.err.println(message); + errors++; + } + + void error(String message, Throwable cause) { + error(message); + } + + int errors; + + class StubMaker extends TreeTranslator { + CompilationUnitTree translate(CompilationUnitTree tree) { + return super.translate((JCCompilationUnit) tree); + } + + /** + * compilation units: remove javadoc comments + * -- required, in order to remove @deprecated tags, since we + * (separately) remove all annotations, including @Deprecated + */ + public void visitTopLevel(JCCompilationUnit tree) { + super.visitTopLevel(tree); + tree.docComments = Collections.emptyMap(); + } + + /** + * methods: remove method bodies, make methods native + */ + @Override + public void visitMethodDef(JCMethodDecl tree) { + tree.mods = translate(tree.mods); + tree.restype = translate(tree.restype); + tree.typarams = translateTypeParams(tree.typarams); + tree.params = translateVarDefs(tree.params); + tree.thrown = translate(tree.thrown); + if (tree.restype != null && tree.body != null) { + tree.mods.flags |= Flags.NATIVE; + tree.body = null; + } + result = tree; + } + + /** + * modifiers: remove annotations + */ + @Override + public void visitModifiers(JCModifiers tree) { + tree.annotations = com.sun.tools.javac.util.List.nil(); + result = tree; + } + + /** + * field definitions: replace initializers with 0, 0.0, false etc + * when possible -- i.e. leave public, protected initializers alone + */ + @Override + public void visitVarDef(JCVariableDecl tree) { + tree.mods = translate(tree.mods); + tree.vartype = translate(tree.vartype); + if (tree.init != null) { + if ((tree.mods.flags & (Flags.PUBLIC | Flags.PROTECTED)) != 0) + tree.init = translate(tree.init); + else { + String t = tree.vartype.toString(); + if (t.equals("boolean")) + tree.init = new JCLiteral(TypeTags.BOOLEAN, 0) { }; + else if (t.equals("byte")) + tree.init = new JCLiteral(TypeTags.BYTE, 0) { }; + else if (t.equals("char")) + tree.init = new JCLiteral(TypeTags.CHAR, 0) { }; + else if (t.equals("double")) + tree.init = new JCLiteral(TypeTags.DOUBLE, 0.d) { }; + else if (t.equals("float")) + tree.init = new JCLiteral(TypeTags.FLOAT, 0.f) { }; + else if (t.equals("int")) + tree.init = new JCLiteral(TypeTags.INT, 0) { }; + else if (t.equals("long")) + tree.init = new JCLiteral(TypeTags.LONG, 0) { }; + else if (t.equals("short")) + tree.init = new JCLiteral(TypeTags.SHORT, 0) { }; + else + tree.init = new JCLiteral(TypeTags.BOT, null) { }; + } + } + result = tree; + } + } + + //---------- Ant Invocation ------------------------------------------------ + + public static class Ant extends MatchingTask { + private File srcDir; + private File destDir; + private boolean fork; + private Path classpath; + private String includes; + + public void setSrcDir(File dir) { + this.srcDir = dir; + } + + public void setDestDir(File dir) { + this.destDir = dir; + } + + public void setFork(boolean v) { + this.fork = v; + } + + public void setClasspath(Path cp) { + if (classpath == null) + classpath = cp; + else + classpath.append(cp); + } + + public Path createClasspath() { + if (classpath == null) { + classpath = new Path(getProject()); + } + return classpath.createPath(); + } + + public void setClasspathRef(Reference r) { + createClasspath().setRefid(r); + } + + public void setIncludes(String includes) { + super.setIncludes(includes); + this.includes = includes; + } + + @Override + public void execute() { + if (includes != null && includes.trim().isEmpty()) + return; + + DirectoryScanner s = getDirectoryScanner(srcDir); + String[] files = s.getIncludedFiles(); +// System.err.println("Ant.execute: srcDir " + srcDir); +// System.err.println("Ant.execute: destDir " + destDir); +// System.err.println("Ant.execute: files " + Arrays.asList(files)); + + files = filter(srcDir, destDir, files); + if (files.length == 0) + return; + System.out.println("Generating " + files.length + " stub files to " + destDir); + + List classNames = new ArrayList(); + for (String file: files) { + classNames.add(file.replaceAll(".java$", "").replace('/', '.')); + } + + if (!fork) { + GenStubs m = new GenStubs(); + boolean ok = m.run(srcDir.getPath(), destDir, classNames); + if (!ok) + throw new BuildException("genstubs failed"); + } else { + List cmd = new ArrayList(); + String java_home = System.getProperty("java.home"); + cmd.add(new File(new File(java_home, "bin"), "java").getPath()); + if (classpath != null) + cmd.add("-Xbootclasspath/p:" + classpath); + cmd.add(GenStubs.class.getName()); + cmd.add("-sourcepath"); + cmd.add(srcDir.getPath()); + cmd.add("-s"); + cmd.add(destDir.getPath()); + cmd.addAll(classNames); + //System.err.println("GenStubs exec " + cmd); + ProcessBuilder pb = new ProcessBuilder(cmd); + pb.redirectErrorStream(true); + try { + Process p = pb.start(); + BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); + try { + String line; + while ((line = in.readLine()) != null) + System.out.println(line); + } finally { + in.close(); + } + int rc = p.waitFor(); + if (rc != 0) + throw new BuildException("genstubs failed"); + } catch (IOException e) { + throw new BuildException("genstubs failed", e); + } catch (InterruptedException e) { + throw new BuildException("genstubs failed", e); + } + } + } + + String[] filter(File srcDir, File destDir, String[] files) { + List results = new ArrayList(); + for (String f: files) { + long srcTime = new File(srcDir, f).lastModified(); + long destTime = new File(destDir, f).lastModified(); + if (srcTime > destTime) + results.add(f); + } + return results.toArray(new String[results.size()]); + } + } +} diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/src/share/classes/com/sun/tools/classfile/Instruction.java --- a/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/classfile/Instruction.java Wed Jul 05 17:04:26 2017 +0200 @@ -106,9 +106,9 @@ /** See {@link Kind#LOCAL_UBYTE}. */ R visitLocalAndValue(Instruction instr, int index, int value, P p); /** See {@link Kind#DYNAMIC}. */ - R visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets); + R visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, P p); /** See {@link Kind#DYNAMIC}. */ - R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets); + R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, P p); /** See {@link Kind#BYTE}, {@link Kind#SHORT}. */ R visitValue(Instruction instr, int value, P p); /** Instruction is unrecognized. */ @@ -282,7 +282,7 @@ for (int i = 0; i < values.length; i++) values[i] = getInt(pad + 12 + 4 * i); return visitor.visitTableSwitch( - this, default_, low, high, values); + this, default_, low, high, values, p); } case LOOKUPSWITCH: { int pad = align(pc + 1) - pc; @@ -295,7 +295,7 @@ offsets[i] = getInt(pad + 12 + i * 8); } return visitor.visitLookupSwitch( - this, default_, npairs, matches, offsets); + this, default_, npairs, matches, offsets, p); } default: throw new IllegalStateException(); diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/src/share/classes/com/sun/tools/javac/code/Source.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Wed Jul 05 17:04:26 2017 +0200 @@ -110,9 +110,6 @@ } /** Allow encoding errors, giving only warnings. */ - public boolean allowStringsInSwitch() { - return compareTo(JDK1_7) >= 0; - } public boolean allowEncodingErrors() { return compareTo(JDK1_6) < 0; } @@ -168,6 +165,9 @@ public boolean allowUnderscoresInLiterals() { return compareTo(JDK1_7) >= 0; } + public boolean allowStringsInSwitch() { + return compareTo(JDK1_7) >= 0; + } public static SourceVersion toSourceVersion(Source source) { switch(source) { case JDK1_2: diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java Wed Jul 05 17:04:26 2017 +0200 @@ -3117,7 +3117,6 @@ tree.cases = translateCases(tree.cases); if (enumSwitch) { result = visitEnumSwitch(tree); - patchTargets(result, tree, result); } else if (stringSwitch) { result = visitStringSwitch(tree); } else { @@ -3146,7 +3145,9 @@ cases.append(c); } } - return make.Switch(selector, cases.toList()); + JCSwitch enumSwitch = make.Switch(selector, cases.toList()); + patchTargets(enumSwitch, tree, enumSwitch); + return enumSwitch; } public JCTree visitStringSwitch(JCSwitch tree) { @@ -3187,7 +3188,14 @@ * of String is the same in the compilation environment as * in the environment the code will run in. The string * hashing algorithm in the SE JDK has been unchanged - * since at least JDK 1.2. + * since at least JDK 1.2. Since the algorithm has been + * specified since that release as well, it is very + * unlikely to be changed in the future. + * + * Different hashing algorithms, such as the length of the + * strings or a perfect hashing algorithm over the + * particular set of case labels, could potentially be + * used instead of String.hashCode. */ ListBuffer stmtList = new ListBuffer(); diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java --- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Wed Jul 05 17:04:26 2017 +0200 @@ -1002,7 +1002,7 @@ // Do nothing } finally { try { - if (raf == null) { + if (raf != null) { raf.close(); } } catch (Throwable t) { diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/src/share/classes/com/sun/tools/javac/main/JavacOption.java --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavacOption.java Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavacOption.java Wed Jul 05 17:04:26 2017 +0200 @@ -130,7 +130,7 @@ private static Map createChoices(String... choices) { Map map = new LinkedHashMap(); for (String c: choices) - map.put(c, true); + map.put(c, false); return map; } diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java --- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java Wed Jul 05 17:04:26 2017 +0200 @@ -54,7 +54,7 @@ /** Set when we are producing source output. If we're not * producing source output, we can sometimes give more detail in * the output even though that detail would not be valid java - * soruce. + * source. */ private final boolean sourceOutput; @@ -489,6 +489,20 @@ print("/*public static final*/ "); print(tree.name); if (tree.init != null) { + if (sourceOutput && tree.init.getTag() == JCTree.NEWCLASS) { + print(" /*enum*/ "); + JCNewClass init = (JCNewClass) tree.init; + if (init.args != null && init.args.nonEmpty()) { + print("("); + print(init.args); + print(")"); + } + if (init.def != null && init.def.defs != null) { + print(" "); + printBlock(init.def.defs); + } + return; + } print(" /* = "); printExpr(tree.init); print(" */"); diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java --- a/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java Wed Jul 05 17:04:22 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java Wed Jul 05 17:04:26 2017 +0200 @@ -118,28 +118,33 @@ public void writeInstr(Instruction instr) { print(String.format("%4d: %-13s ", instr.getPC(), instr.getMnemonic())); - instr.accept(instructionPrinter, null); + // compute the number of indentations for the body of multi-line instructions + // This is 6 (the width of "%4d: "), divided by the width of each indentation level, + // and rounded up to the next integer. + int indentWidth = options.indentWidth; + int indent = (6 + indentWidth - 1) / indentWidth; + instr.accept(instructionPrinter, indent); println(); } // where - Instruction.KindVisitor instructionPrinter = - new Instruction.KindVisitor() { + Instruction.KindVisitor instructionPrinter = + new Instruction.KindVisitor() { - public Void visitNoOperands(Instruction instr, Void p) { + public Void visitNoOperands(Instruction instr, Integer indent) { return null; } - public Void visitArrayType(Instruction instr, TypeKind kind, Void p) { + public Void visitArrayType(Instruction instr, TypeKind kind, Integer indent) { print(" " + kind.name); return null; } - public Void visitBranch(Instruction instr, int offset, Void p) { + public Void visitBranch(Instruction instr, int offset, Integer indent) { print((instr.getPC() + offset)); return null; } - public Void visitConstantPoolRef(Instruction instr, int index, Void p) { + public Void visitConstantPoolRef(Instruction instr, int index, Integer indent) { print("#" + index); tab(); print("// "); @@ -147,7 +152,7 @@ return null; } - public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Void p) { + public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Integer indent) { print("#" + index + ", " + value); tab(); print("// "); @@ -155,46 +160,48 @@ return null; } - public Void visitLocal(Instruction instr, int index, Void p) { + public Void visitLocal(Instruction instr, int index, Integer indent) { print(index); return null; } - public Void visitLocalAndValue(Instruction instr, int index, int value, Void p) { + public Void visitLocalAndValue(Instruction instr, int index, int value, Integer indent) { print(index + ", " + value); return null; } - public Void visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets) { + public Void visitLookupSwitch(Instruction instr, + int default_, int npairs, int[] matches, int[] offsets, Integer indent) { int pc = instr.getPC(); print("{ // " + npairs); - indent(+1); + indent(indent); for (int i = 0; i < npairs; i++) { - print("\n" + matches[i] + ": " + (pc + offsets[i])); + print(String.format("%n%12d: %d", matches[i], (pc + offsets[i]))); } - print("\ndefault: " + (pc + default_) + " }"); - indent(-1); + print("\n default: " + (pc + default_) + "\n}"); + indent(-indent); return null; } - public Void visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets) { + public Void visitTableSwitch(Instruction instr, + int default_, int low, int high, int[] offsets, Integer indent) { int pc = instr.getPC(); - print("{ //" + low + " to " + high); - indent(+1); + print("{ // " + low + " to " + high); + indent(indent); for (int i = 0; i < offsets.length; i++) { - print("\n" + (low + i) + ": " + (pc + offsets[i])); + print(String.format("%n%12d: %d", (low + i), (pc + offsets[i]))); } - print("\ndefault: " + (pc + default_) + " }"); - indent(-1); + print("\n default: " + (pc + default_) + "\n}"); + indent(-indent); return null; } - public Void visitValue(Instruction instr, int value, Void p) { + public Void visitValue(Instruction instr, int value, Integer indent) { print(value); return null; } - public Void visitUnknown(Instruction instr, Void p) { + public Void visitUnknown(Instruction instr, Integer indent) { return null; } }; diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/test/tools/javac/6902720/E1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/6902720/E1.java Wed Jul 05 17:04:26 2017 +0200 @@ -0,0 +1,28 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +enum E1 { + A, + B { }, + C { void m() { } }; +} diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/test/tools/javac/6902720/E2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/6902720/E2.java Wed Jul 05 17:04:26 2017 +0200 @@ -0,0 +1,29 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +enum E2 { + A(1), + B(2) { }, + C(3) { void m() { } }; + E2(int i) { } +} diff -r 80dcc8ac5696 -r ade55a65b0f2 langtools/test/tools/javac/6902720/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/6902720/Test.java Wed Jul 05 17:04:26 2017 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.io.*; +import java.net.*; +import javax.tools.*; +import java.util.*; + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.Pretty; + +/** + * @test + * @bug 6902720 + * @summary javac pretty printer does not handle enums correctly + */ + +public class Test { + + public static void main(String[] args) throws Exception { + Test t = new Test(); + t.run("E1.java", "E2.java"); + } + + void run(String... args) throws Exception { + File testSrcDir = new File(System.getProperty("test.src")); + for (String arg: args) { + test(new File(testSrcDir, arg)); + } + } + + void test(File test) throws Exception { + JavacTool tool1 = JavacTool.create(); + StandardJavaFileManager fm = tool1.getStandardFileManager(null, null, null); + Iterable files = fm.getJavaFileObjects(test); + + // parse test file into a tree, and write it out to a stringbuffer using Pretty + JavacTask t1 = tool1.getTask(null, fm, null, null, null, files); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + Iterable trees = t1.parse(); + for (CompilationUnitTree tree: trees) { + new Pretty(pw, true).printExpr((JCTree) tree); + } + pw.close(); + + final String out = sw.toString(); + System.err.println("generated code:\n" + out + "\n"); + + // verify the generated code is valid Java by compiling it + JavacTool tool2 = JavacTool.create(); + JavaFileObject fo = new SimpleJavaFileObject(URI.create("output"), JavaFileObject.Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return out; + } + }; + JavacTask t2 = tool2.getTask(null, fm, null, null, null, Collections.singleton(fo)); + boolean ok = t2.call(); + if (!ok) + throw new Exception("compilation of generated code failed"); + + File expectedClass = new File(test.getName().replace(".java", ".class")); + if (!expectedClass.exists()) + throw new Exception(expectedClass + " not found"); + } +} +