TestBootstrapMethodsCount.java revision 3294:9adfb22ff08f
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.jvm 33 * jdk.compiler/com.sun.tools.javac.tree 34 * jdk.compiler/com.sun.tools.javac.util 35 */ 36 37import java.io.File; 38import java.net.URI; 39import java.util.ArrayList; 40import java.util.Arrays; 41import java.util.Locale; 42 43import javax.tools.Diagnostic; 44import javax.tools.JavaCompiler; 45import javax.tools.JavaFileObject; 46import javax.tools.SimpleJavaFileObject; 47import javax.tools.ToolProvider; 48 49import com.sun.source.tree.MethodInvocationTree; 50import com.sun.source.tree.MethodTree; 51import com.sun.source.util.TaskEvent; 52import com.sun.source.util.TaskListener; 53import com.sun.source.util.TreeScanner; 54 55import com.sun.tools.classfile.Attribute; 56import com.sun.tools.classfile.BootstrapMethods_attribute; 57import com.sun.tools.classfile.ClassFile; 58 59import com.sun.tools.javac.api.JavacTaskImpl; 60import com.sun.tools.javac.code.Symbol; 61import com.sun.tools.javac.code.Symbol.MethodSymbol; 62import com.sun.tools.javac.code.Symtab; 63import com.sun.tools.javac.code.Types; 64import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; 65import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 66import com.sun.tools.javac.tree.JCTree.JCIdent; 67import com.sun.tools.javac.util.Context; 68import com.sun.tools.javac.util.Names; 69 70import static com.sun.tools.javac.jvm.ClassFile.*; 71 72public class TestBootstrapMethodsCount { 73 74 public static void main(String... args) throws Exception { 75 JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 76 new TestBootstrapMethodsCount().run(comp); 77 } 78 79 DiagChecker dc; 80 81 TestBootstrapMethodsCount() { 82 dc = new DiagChecker(); 83 } 84 85 public void run(JavaCompiler comp) { 86 JavaSource source = new JavaSource(); 87 JavacTaskImpl ct = (JavacTaskImpl)comp.getTask(null, null, dc, 88 Arrays.asList("-g"), null, Arrays.asList(source)); 89 Context context = ct.getContext(); 90 Symtab syms = Symtab.instance(context); 91 Names names = Names.instance(context); 92 Types types = Types.instance(context); 93 ct.addTaskListener(new Indifier(syms, names, types)); 94 try { 95 ct.generate(); 96 } catch (Throwable t) { 97 t.printStackTrace(); 98 throw new AssertionError( 99 String.format("Error thrown when compiling following code\n%s", 100 source.source)); 101 } 102 if (dc.diagFound) { 103 throw new AssertionError( 104 String.format("Diags found when compiling following code\n%s\n\n%s", 105 source.source, dc.printDiags())); 106 } 107 verifyBytecode(); 108 } 109 110 void verifyBytecode() { 111 File compiledTest = new File("Test.class"); 112 try { 113 ClassFile cf = ClassFile.read(compiledTest); 114 BootstrapMethods_attribute bsm_attr = 115 (BootstrapMethods_attribute)cf 116 .getAttribute(Attribute.BootstrapMethods); 117 int length = bsm_attr.bootstrap_method_specifiers.length; 118 if (length != 1) { 119 throw new Error("Bad number of method specifiers " + 120 "in BootstrapMethods attribute: " + length); 121 } 122 } catch (Exception e) { 123 e.printStackTrace(); 124 throw new Error("error reading " + compiledTest +": " + e); 125 } 126 } 127 128 class JavaSource extends SimpleJavaFileObject { 129 130 static final String source = "import java.lang.invoke.*;\n" + 131 "class Bootstrap {\n" + 132 " public static CallSite bsm(MethodHandles.Lookup lookup, " + 133 "String name, MethodType methodType) {\n" + 134 " return null;\n" + 135 " }\n" + 136 "}\n" + 137 "class Test {\n" + 138 " void m1() { }\n" + 139 " void m2(Object arg1) { }\n" + 140 " void test1() {\n" + 141 " Object o = this; // marker statement \n" + 142 " m1();\n" + 143 " }\n" + 144 " void test2(Object arg1) {\n" + 145 " Object o = this; // marker statement \n" + 146 " m2(arg1);\n" + 147 " }\n" + 148 "}"; 149 150 JavaSource() { 151 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); 152 } 153 154 @Override 155 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 156 return source; 157 } 158 } 159 160 class Indifier extends TreeScanner<Void, Void> implements TaskListener { 161 162 MethodSymbol bsm; 163 Symtab syms; 164 Names names; 165 Types types; 166 167 Indifier(Symtab syms, Names names, Types types) { 168 this.syms = syms; 169 this.names = names; 170 this.types = types; 171 } 172 173 @Override 174 public void started(TaskEvent e) { 175 //do nothing 176 } 177 178 @Override 179 public void finished(TaskEvent e) { 180 if (e.getKind() == TaskEvent.Kind.ANALYZE) { 181 scan(e.getCompilationUnit(), null); 182 } 183 } 184 185 @Override 186 public Void visitMethodInvocation(MethodInvocationTree node, Void p) { 187 super.visitMethodInvocation(node, p); 188 JCMethodInvocation apply = (JCMethodInvocation)node; 189 JCIdent ident = (JCIdent)apply.meth; 190 Symbol oldSym = ident.sym; 191 if (!oldSym.isConstructor()) { 192 ident.sym = new Symbol.DynamicMethodSymbol(oldSym.name, 193 oldSym.owner, REF_invokeStatic, bsm, oldSym.type, new Object[0]); 194 } 195 return null; 196 } 197 198 @Override 199 public Void visitMethod(MethodTree node, Void p) { 200 super.visitMethod(node, p); 201 if (node.getName().toString().equals("bsm")) { 202 bsm = ((JCMethodDecl)node).sym; 203 } 204 return null; 205 } 206 } 207 208 static class DiagChecker 209 implements javax.tools.DiagnosticListener<JavaFileObject> { 210 211 boolean diagFound; 212 ArrayList<String> diags = new ArrayList<>(); 213 214 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 215 diags.add(diagnostic.getMessage(Locale.getDefault())); 216 diagFound = true; 217 } 218 219 String printDiags() { 220 StringBuilder buf = new StringBuilder(); 221 for (String s : diags) { 222 buf.append(s); 223 buf.append("\n"); 224 } 225 return buf.toString(); 226 } 227 } 228 229} 230