Mon, 10 Jun 2013 15:57:32 +0100
8013576: Add stat support to LambdaToMethod
Summary: LambdaToMethod should emit info to help diagnose/test lambda metafactory problems
Reviewed-by: jjg, vromero
1.1 --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Mon Jun 10 15:18:47 2013 +0100 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Mon Jun 10 15:57:32 2013 +0100 1.3 @@ -68,6 +68,8 @@ 1.4 */ 1.5 public class LambdaToMethod extends TreeTranslator { 1.6 1.7 + private JCDiagnostic.Factory diags; 1.8 + private Log log; 1.9 private Lower lower; 1.10 private Names names; 1.11 private Symtab syms; 1.12 @@ -89,6 +91,9 @@ 1.13 /** info about the current class being processed */ 1.14 private KlassInfo kInfo; 1.15 1.16 + /** dump statistics about lambda code generation */ 1.17 + private boolean dumpLambdaToMethodStats; 1.18 + 1.19 /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */ 1.20 public static final int FLAG_SERIALIZABLE = 1 << 0; 1.21 1.22 @@ -146,6 +151,8 @@ 1.23 } 1.24 1.25 private LambdaToMethod(Context context) { 1.26 + diags = JCDiagnostic.Factory.instance(context); 1.27 + log = Log.instance(context); 1.28 lower = Lower.instance(context); 1.29 names = Names.instance(context); 1.30 syms = Symtab.instance(context); 1.31 @@ -154,6 +161,8 @@ 1.32 types = Types.instance(context); 1.33 transTypes = TransTypes.instance(context); 1.34 analyzer = new LambdaAnalyzerPreprocessor(); 1.35 + Options options = Options.instance(context); 1.36 + dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats"); 1.37 } 1.38 // </editor-fold> 1.39 1.40 @@ -1101,7 +1110,9 @@ 1.41 Map<String, Integer> prevSerializableLambdaCount = 1.42 serializableLambdaCounts; 1.43 Map<ClassSymbol, Symbol> prevClinits = clinits; 1.44 + DiagnosticSource prevSource = log.currentSource(); 1.45 try { 1.46 + log.useSource(tree.sym.sourcefile); 1.47 serializableLambdaCounts = new HashMap<String, Integer>(); 1.48 prevClinits = new HashMap<ClassSymbol, Symbol>(); 1.49 if (tree.sym.owner.kind == MTH) { 1.50 @@ -1126,6 +1137,7 @@ 1.51 super.visitClassDef(tree); 1.52 } 1.53 finally { 1.54 + log.useSource(prevSource.getFile()); 1.55 frameStack = prevStack; 1.56 serializableLambdaCounts = prevSerializableLambdaCount; 1.57 clinits = prevClinits; 1.58 @@ -1685,6 +1697,9 @@ 1.59 } 1.60 Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName(); 1.61 this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass()); 1.62 + if (dumpLambdaToMethodStats) { 1.63 + log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym); 1.64 + } 1.65 } 1.66 1.67 /** 1.68 @@ -1841,6 +1856,11 @@ 1.69 lambdaName().append(names.fromString("$bridge")), null, 1.70 owner.enclClass()) 1.71 : null; 1.72 + if (dumpLambdaToMethodStats) { 1.73 + String key = bridgeSym == null ? 1.74 + "mref.stat" : "mref.stat.1"; 1.75 + log.note(tree, key, needsAltMetafactory(), bridgeSym); 1.76 + } 1.77 } 1.78 1.79 /**
2.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Jun 10 15:18:47 2013 +0100 2.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Jun 10 15:57:32 2013 +0100 2.3 @@ -1163,6 +1163,23 @@ 2.4 compiler.note.potential.lambda.found=\ 2.5 This anonymous inner class creation can be turned into a lambda expression. 2.6 2.7 +# 0: boolean, 1: symbol 2.8 +compiler.note.lambda.stat=\ 2.9 + Translating lambda expression\n\ 2.10 + alternate metafactory = {0}\n\ 2.11 + synthetic method = {1} 2.12 + 2.13 +# 0: boolean, 1: unused 2.14 +compiler.note.mref.stat=\ 2.15 + Translating method reference\n\ 2.16 + alternate metafactory = {0}\n\ 2.17 + 2.18 +# 0: boolean, 1: symbol 2.19 +compiler.note.mref.stat.1=\ 2.20 + Translating method reference\n\ 2.21 + alternate metafactory = {0}\n\ 2.22 + bridge method = {1} 2.23 + 2.24 compiler.note.note=\ 2.25 Note:\u0020 2.26
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test/tools/javac/diags/examples/LambdaStat.java Mon Jun 10 15:57:32 2013 +0100 3.3 @@ -0,0 +1,29 @@ 3.4 +/* 3.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.7 + * 3.8 + * This code is free software; you can redistribute it and/or modify it 3.9 + * under the terms of the GNU General Public License version 2 only, as 3.10 + * published by the Free Software Foundation. 3.11 + * 3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 3.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 3.15 + * version 2 for more details (a copy is included in the LICENSE file that 3.16 + * accompanied this code). 3.17 + * 3.18 + * You should have received a copy of the GNU General Public License version 3.19 + * 2 along with this work; if not, write to the Free Software Foundation, 3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 3.21 + * 3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 3.23 + * or visit www.oracle.com if you need additional information or have any 3.24 + * questions. 3.25 + */ 3.26 + 3.27 +// key: compiler.note.lambda.stat 3.28 +// options: -XDdumpLambdaToMethodStats 3.29 + 3.30 +class LambdaStat { 3.31 + Runnable r = ()->{}; 3.32 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/tools/javac/diags/examples/MrefStat.java Mon Jun 10 15:57:32 2013 +0100 4.3 @@ -0,0 +1,31 @@ 4.4 +/* 4.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.7 + * 4.8 + * This code is free software; you can redistribute it and/or modify it 4.9 + * under the terms of the GNU General Public License version 2 only, as 4.10 + * published by the Free Software Foundation. 4.11 + * 4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 4.15 + * version 2 for more details (a copy is included in the LICENSE file that 4.16 + * accompanied this code). 4.17 + * 4.18 + * You should have received a copy of the GNU General Public License version 4.19 + * 2 along with this work; if not, write to the Free Software Foundation, 4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 4.21 + * 4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 4.23 + * or visit www.oracle.com if you need additional information or have any 4.24 + * questions. 4.25 + */ 4.26 + 4.27 +// key: compiler.note.mref.stat 4.28 +// options: -XDdumpLambdaToMethodStats 4.29 + 4.30 +class MrefStat { 4.31 + Runnable r = MrefStat::m; 4.32 + 4.33 + static void m() { } 4.34 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/tools/javac/diags/examples/MrefStat.java.rej Mon Jun 10 15:57:32 2013 +0100 5.3 @@ -0,0 +1,34 @@ 5.4 +--- MrefStat.java 5.5 ++++ MrefStat.java 5.6 +@@ -0,0 +1,31 @@ 5.7 ++/* 5.8 ++ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 5.9 ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.10 ++ * 5.11 ++ * This code is free software; you can redistribute it and/or modify it 5.12 ++ * under the terms of the GNU General Public License version 2 only, as 5.13 ++ * published by the Free Software Foundation. 5.14 ++ * 5.15 ++ * This code is distributed in the hope that it will be useful, but WITHOUT 5.16 ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.17 ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.18 ++ * version 2 for more details (a copy is included in the LICENSE file that 5.19 ++ * accompanied this code). 5.20 ++ * 5.21 ++ * You should have received a copy of the GNU General Public License version 5.22 ++ * 2 along with this work; if not, write to the Free Software Foundation, 5.23 ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.24 ++ * 5.25 ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.26 ++ * or visit www.oracle.com if you need additional information or have any 5.27 ++ * questions. 5.28 ++ */ 5.29 ++ 5.30 ++// key: compiler.note.mref.stat 5.31 ++// options: -XDdumpLambdaToMethodStats 5.32 ++ 5.33 ++class MrefStat { 5.34 ++ Runnable r = MrefStat::m; 5.35 ++ 5.36 ++ static void m() { } 5.37 ++}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/test/tools/javac/diags/examples/MrefStat1.java Mon Jun 10 15:57:32 2013 +0100 6.3 @@ -0,0 +1,34 @@ 6.4 +/* 6.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 + * 6.8 + * This code is free software; you can redistribute it and/or modify it 6.9 + * under the terms of the GNU General Public License version 2 only, as 6.10 + * published by the Free Software Foundation. 6.11 + * 6.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 6.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.15 + * version 2 for more details (a copy is included in the LICENSE file that 6.16 + * accompanied this code). 6.17 + * 6.18 + * You should have received a copy of the GNU General Public License version 6.19 + * 2 along with this work; if not, write to the Free Software Foundation, 6.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.21 + * 6.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 6.23 + * or visit www.oracle.com if you need additional information or have any 6.24 + * questions. 6.25 + */ 6.26 + 6.27 +// key: compiler.note.mref.stat.1 6.28 +// options: -XDdumpLambdaToMethodStats 6.29 + 6.30 +class MrefStat1 { 6.31 + 6.32 + void m() { } 6.33 + 6.34 + static class Sub extends MrefStat1 { 6.35 + Runnable r = super::m; 6.36 + } 6.37 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/tools/javac/diags/examples/MrefStat1.java.rej Mon Jun 10 15:57:32 2013 +0100 7.3 @@ -0,0 +1,37 @@ 7.4 +--- MrefStat1.java 7.5 ++++ MrefStat1.java 7.6 +@@ -0,0 +1,34 @@ 7.7 ++/* 7.8 ++ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 7.9 ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.10 ++ * 7.11 ++ * This code is free software; you can redistribute it and/or modify it 7.12 ++ * under the terms of the GNU General Public License version 2 only, as 7.13 ++ * published by the Free Software Foundation. 7.14 ++ * 7.15 ++ * This code is distributed in the hope that it will be useful, but WITHOUT 7.16 ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.17 ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.18 ++ * version 2 for more details (a copy is included in the LICENSE file that 7.19 ++ * accompanied this code). 7.20 ++ * 7.21 ++ * You should have received a copy of the GNU General Public License version 7.22 ++ * 2 along with this work; if not, write to the Free Software Foundation, 7.23 ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.24 ++ * 7.25 ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.26 ++ * or visit www.oracle.com if you need additional information or have any 7.27 ++ * questions. 7.28 ++ */ 7.29 ++ 7.30 ++// key: compiler.note.mref.stat.1 7.31 ++// options: -XDdumpLambdaToMethodStats 7.32 ++ 7.33 ++class MrefStat1 { 7.34 ++ 7.35 ++ void m() { } 7.36 ++ 7.37 ++ static class Sub extends MrefStat1 { 7.38 ++ Runnable r = super::m; 7.39 ++ } 7.40 ++}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/test/tools/javac/lambda/TestLambdaToMethodStats.java Mon Jun 10 15:57:32 2013 +0100 8.3 @@ -0,0 +1,192 @@ 8.4 +/* 8.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 8.7 + * 8.8 + * This code is free software; you can redistribute it and/or modify it 8.9 + * under the terms of the GNU General Public License version 2 only, as 8.10 + * published by the Free Software Foundation. 8.11 + * 8.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 8.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 8.15 + * version 2 for more details (a copy is included in the LICENSE file that 8.16 + * accompanied this code). 8.17 + * 8.18 + * You should have received a copy of the GNU General Public License version 8.19 + * 2 along with this work; if not, write to the Free Software Foundation, 8.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 8.21 + * 8.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 8.23 + * or visit www.oracle.com if you need additional information or have any 8.24 + * questions. 8.25 + */ 8.26 + 8.27 +/* 8.28 + * @test 8.29 + * @bug 8013576 8.30 + * @summary Add stat support to LambdaToMethod 8.31 + * @library ../lib 8.32 + * @build JavacTestingAbstractThreadedTest 8.33 + * @run main/othervm TestLambdaToMethodStats 8.34 + */ 8.35 + 8.36 +// use /othervm to avoid jtreg timeout issues (CODETOOLS-7900047) 8.37 +// see JDK-8006746 8.38 + 8.39 +import java.net.URI; 8.40 +import java.util.Arrays; 8.41 + 8.42 +import javax.tools.Diagnostic; 8.43 +import javax.tools.JavaFileObject; 8.44 +import javax.tools.SimpleJavaFileObject; 8.45 + 8.46 +import com.sun.source.util.JavacTask; 8.47 +import com.sun.tools.javac.api.ClientCodeWrapper; 8.48 +import com.sun.tools.javac.util.JCDiagnostic; 8.49 + 8.50 +public class TestLambdaToMethodStats 8.51 + extends JavacTestingAbstractThreadedTest 8.52 + implements Runnable { 8.53 + 8.54 + enum ExprKind { 8.55 + LAMBDA("()->null"), 8.56 + MREF1("this::g"), 8.57 + MREF2("this::h"); 8.58 + 8.59 + String exprStr; 8.60 + 8.61 + ExprKind(String exprStr) { 8.62 + this.exprStr = exprStr; 8.63 + } 8.64 + } 8.65 + 8.66 + enum TargetKind { 8.67 + IMPLICIT(""), 8.68 + SERIALIZABLE("(A & java.io.Serializable)"); 8.69 + 8.70 + String targetStr; 8.71 + 8.72 + TargetKind(String targetStr) { 8.73 + this.targetStr = targetStr; 8.74 + } 8.75 + } 8.76 + 8.77 + public static void main(String... args) throws Exception { 8.78 + for (ExprKind ek : ExprKind.values()) { 8.79 + for (TargetKind tk : TargetKind.values()) { 8.80 + pool.execute(new TestLambdaToMethodStats(ek, tk)); 8.81 + } 8.82 + } 8.83 + 8.84 + checkAfterExec(true); 8.85 + } 8.86 + 8.87 + ExprKind ek; 8.88 + TargetKind tk; 8.89 + JavaSource source; 8.90 + DiagnosticChecker diagChecker; 8.91 + 8.92 + 8.93 + TestLambdaToMethodStats(ExprKind ek, TargetKind tk) { 8.94 + this.ek = ek; 8.95 + this.tk = tk; 8.96 + this.source = new JavaSource(); 8.97 + this.diagChecker = new DiagnosticChecker(); 8.98 + } 8.99 + 8.100 + class JavaSource extends SimpleJavaFileObject { 8.101 + 8.102 + String template = "interface A {\n" + 8.103 + " Object o();\n" + 8.104 + "}\n" + 8.105 + "class Test {\n" + 8.106 + " A a = #C#E;\n" + 8.107 + " Object g() { return null; }\n" + 8.108 + " Object h(Object... o) { return null; }\n" + 8.109 + "}"; 8.110 + 8.111 + String source; 8.112 + 8.113 + public JavaSource() { 8.114 + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 8.115 + source = template.replaceAll("#E", ek.exprStr) 8.116 + .replaceAll("#C", tk.targetStr); 8.117 + } 8.118 + 8.119 + @Override 8.120 + public CharSequence getCharContent(boolean ignoreEncodingErrors) { 8.121 + return source; 8.122 + } 8.123 + } 8.124 + 8.125 + public void run() { 8.126 + JavacTask ct = (JavacTask)comp.getTask(null, fm.get(), diagChecker, 8.127 + Arrays.asList("-XDdumpLambdaToMethodStats"), 8.128 + null, Arrays.asList(source)); 8.129 + try { 8.130 + ct.generate(); 8.131 + } catch (Throwable ex) { 8.132 + throw new 8.133 + AssertionError("Error thron when analyzing the following source:\n" + 8.134 + source.getCharContent(true)); 8.135 + } 8.136 + check(); 8.137 + } 8.138 + 8.139 + void check() { 8.140 + checkCount.incrementAndGet(); 8.141 + 8.142 + boolean error = diagChecker.lambda != 8.143 + (ek == ExprKind.LAMBDA); 8.144 + 8.145 + error |= diagChecker.bridge != 8.146 + (ek == ExprKind.MREF2); 8.147 + 8.148 + error |= diagChecker.altMetafactory != 8.149 + (tk == TargetKind.SERIALIZABLE); 8.150 + 8.151 + if (error) { 8.152 + throw new AssertionError("Bad stat diagnostic found for source\n" + 8.153 + "lambda = " + diagChecker.lambda + "\n" + 8.154 + "bridge = " + diagChecker.bridge + "\n" + 8.155 + "altMF = " + diagChecker.altMetafactory + "\n" + 8.156 + source.source); 8.157 + } 8.158 + } 8.159 + 8.160 + static class DiagnosticChecker 8.161 + implements javax.tools.DiagnosticListener<JavaFileObject> { 8.162 + 8.163 + boolean altMetafactory; 8.164 + boolean bridge; 8.165 + boolean lambda; 8.166 + 8.167 + public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 8.168 + try { 8.169 + if (diagnostic.getKind() == Diagnostic.Kind.NOTE) { 8.170 + switch (diagnostic.getCode()) { 8.171 + case "compiler.note.lambda.stat": 8.172 + lambda = true; 8.173 + break; 8.174 + case "compiler.note.mref.stat": 8.175 + lambda = false; 8.176 + bridge = false; 8.177 + break; 8.178 + case "compiler.note.mref.stat.1": 8.179 + lambda = false; 8.180 + bridge = true; 8.181 + break; 8.182 + default: 8.183 + throw new AssertionError("unexpected note: " + diagnostic.getCode()); 8.184 + } 8.185 + ClientCodeWrapper.DiagnosticSourceUnwrapper dsu = 8.186 + (ClientCodeWrapper.DiagnosticSourceUnwrapper)diagnostic; 8.187 + altMetafactory = (Boolean)dsu.d.getArgs()[0]; 8.188 + } 8.189 + } catch (RuntimeException t) { 8.190 + t.printStackTrace(); 8.191 + throw t; 8.192 + } 8.193 + } 8.194 + } 8.195 +}