TestBootstrapMethodsCount.java revision 3019:176472b94f2e
1/* 2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 8129547 27 * @summary Excess entries in BootstrapMethods with the same (bsm, bsmKind, bsmStaticArgs), but different dynamicArgs 28 * @library /tools/javac/lib 29 * @modules jdk.jdeps/com.sun.tools.classfile 30 * jdk.compiler/com.sun.tools.javac.api 31 * jdk.compiler/com.sun.tools.javac.code 32 * jdk.compiler/com.sun.tools.javac.tree 33 * jdk.compiler/com.sun.tools.javac.util 34 */ 35 36import java.io.File; 37import java.net.URI; 38import java.util.ArrayList; 39import java.util.Arrays; 40import java.util.Locale; 41 42import javax.tools.Diagnostic; 43import javax.tools.JavaCompiler; 44import javax.tools.JavaFileObject; 45import javax.tools.SimpleJavaFileObject; 46import javax.tools.ToolProvider; 47 48import com.sun.source.tree.MethodInvocationTree; 49import com.sun.source.tree.MethodTree; 50import com.sun.source.util.TaskEvent; 51import com.sun.source.util.TaskListener; 52import com.sun.source.util.TreeScanner; 53 54import com.sun.tools.classfile.Attribute; 55import com.sun.tools.classfile.BootstrapMethods_attribute; 56import com.sun.tools.classfile.ClassFile; 57 58import com.sun.tools.javac.api.JavacTaskImpl; 59import com.sun.tools.javac.code.Symbol; 60import com.sun.tools.javac.code.Symbol.MethodSymbol; 61import com.sun.tools.javac.code.Symtab; 62import com.sun.tools.javac.code.Types; 63import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; 64import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 65import com.sun.tools.javac.tree.JCTree.JCIdent; 66import com.sun.tools.javac.util.Context; 67import com.sun.tools.javac.util.Names; 68 69import static com.sun.tools.javac.jvm.ClassFile.*; 70 71public class TestBootstrapMethodsCount { 72 73 public static void main(String... args) throws Exception { 74 JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 75 new TestBootstrapMethodsCount().run(comp); 76 } 77 78 DiagChecker dc; 79 80 TestBootstrapMethodsCount() { 81 dc = new DiagChecker(); 82 } 83 84 public void run(JavaCompiler comp) { 85 JavaSource source = new JavaSource(); 86 JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, null, dc, 87 Arrays.asList("-g"), null, Arrays.asList(source)); 88 Context context = ct.getContext(); 89 Symtab syms = Symtab.instance(context); 90 Names names = Names.instance(context); 91 Types types = Types.instance(context); 92 ct.addTaskListener(new Indifier(syms, names, types)); 93 try { 94 ct.generate(); 95 } catch (Throwable t) { 96 t.printStackTrace(); 97 throw new AssertionError( 98 String.format("Error thrown when compiling following code\n%s", 99 source.source)); 100 } 101 if (dc.diagFound) { 102 throw new AssertionError( 103 String.format("Diags found when compiling following code\n%s\n\n%s", 104 source.source, dc.printDiags())); 105 } 106 verifyBytecode(); 107 } 108 109 void verifyBytecode() { 110 File compiledTest = new File("Test.class"); 111 try { 112 ClassFile cf = ClassFile.read(compiledTest); 113 BootstrapMethods_attribute bsm_attr = 114 (BootstrapMethods_attribute)cf 115 .getAttribute(Attribute.BootstrapMethods); 116 int length = bsm_attr.bootstrap_method_specifiers.length; 117 if (length != 1) { 118 throw new Error("Bad number of method specifiers " + 119 "in BootstrapMethods attribute: " + length); 120 } 121 } catch (Exception e) { 122 e.printStackTrace(); 123 throw new Error("error reading " + compiledTest +": " + e); 124 } 125 } 126 127 class JavaSource extends SimpleJavaFileObject { 128 129 static final String source = "import java.lang.invoke.*;\n" + 130 "class Bootstrap {\n" + 131 " public static CallSite bsm(MethodHandles.Lookup lookup, " + 132 "String name, MethodType methodType) {\n" + 133 " return null;\n" + 134 " }\n" + 135 "}\n" + 136 "class Test {\n" + 137 " void m1() { }\n" + 138 " void m2(Object arg1) { }\n" + 139 " void test1() {\n" + 140 " Object o = this; // marker statement \n" + 141 " m1();\n" + 142 " }\n" + 143 " void test2(Object arg1) {\n" + 144 " Object o = this; // marker statement \n" + 145 " m2(arg1);\n" + 146 " }\n" + 147 "}"; 148 149 JavaSource() { 150 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 151 } 152 153 @Override 154 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 155 return source; 156 } 157 } 158 159 class Indifier extends TreeScanner<Void, Void> implements TaskListener { 160 161 MethodSymbol bsm; 162 Symtab syms; 163 Names names; 164 Types types; 165 166 Indifier(Symtab syms, Names names, Types types) { 167 this.syms = syms; 168 this.names = names; 169 this.types = types; 170 } 171 172 @Override 173 public void started(TaskEvent e) { 174 //do nothing 175 } 176 177 @Override 178 public void finished(TaskEvent e) { 179 if (e.getKind() == TaskEvent.Kind.ANALYZE) { 180 scan(e.getCompilationUnit(), null); 181 } 182 } 183 184 @Override 185 public Void visitMethodInvocation(MethodInvocationTree node, Void p) { 186 super.visitMethodInvocation(node, p); 187 JCMethodInvocation apply = (JCMethodInvocation)node; 188 JCIdent ident = (JCIdent)apply.meth; 189 Symbol oldSym = ident.sym; 190 if (!oldSym.isConstructor()) { 191 ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name, 192 oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]); 193 } 194 return null; 195 } 196 197 @Override 198 public Void visitMethod(MethodTree node, Void p) { 199 super.visitMethod(node, p); 200 if (node.getName().toString().equals("bsm")) { 201 bsm = ((JCMethodDecl)node).sym; 202 } 203 return null; 204 } 205 } 206 207 static class DiagChecker 208 implements javax.tools.DiagnosticListener<JavaFileObject> { 209 210 boolean diagFound; 211 ArrayList<String> diags = new ArrayList<>(); 212 213 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 214 diags.add(diagnostic.getMessage(Locale.getDefault())); 215 diagFound = true; 216 } 217 218 String printDiags() { 219 StringBuilder buf = new StringBuilder(); 220 for (String s : diags) { 221 buf.append(s); 222 buf.append("\n"); 223 } 224 return buf.toString(); 225 } 226 } 227 228} 229