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