1 /*
2  * Copyright (c) 2010, 2019, 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 /* @test
25  * @bug 7050328 8007035
26  * @summary smoke test for invokedynamic instructions
27  * @build indify.Indify
28  * @compile InvokeDynamicPrintArgs.java
29  * @run main/othervm
30  *      indify.Indify
31  *      --verify-specifier-count=8
32  *      --expand-properties --classpath ${test.classes}
33  *      --java test.java.lang.invoke.InvokeDynamicPrintArgs --check-output
34  * @run main/othervm
35  *      indify.Indify
36  *      --expand-properties --classpath ${test.classes}
37  *      --java test.java.lang.invoke.InvokeDynamicPrintArgs --security-manager
38  */
39 
40 package test.java.lang.invoke;
41 
42 import java.util.*;
43 import java.io.*;
44 
45 import java.lang.invoke.*;
46 import java.security.*;
47 import static java.lang.invoke.MethodHandles.*;
48 import static java.lang.invoke.MethodType.*;
49 
50 public class InvokeDynamicPrintArgs {
main(String... av)51     public static void main(String... av) throws Throwable {
52         if (av.length > 0 && av[0].equals("--check-output"))  openBuf();
53         if (av.length > 0 && av[0].equals("--security-manager"))  setSM();
54         System.out.println("Printing some argument lists, starting with a empty one:");
55         INDY_nothing().invokeExact();                 // BSM specifier #0 = {bsm}
56         INDY_bar().invokeExact("bar arg", 1);         // BSM specifier #1 = {bsm2, Void.class, "void type"}
57         INDY_bar2().invokeExact("bar2 arg", 222);     // BSM specifier #1 = (same)
58         INDY_baz().invokeExact("baz arg", 2, 3.14);   // BSM specifier #2 = {bsm2, 1234.5}
59         INDY_foo().invokeExact("foo arg");            // BSM specifier #0 = (same)
60         // Hence, BSM specifier count should be 3.  See "--verify-specifier-count=3" above.
61         System.out.println("Done printing argument lists.");
62         closeBuf();
63         checkConstantRefs();
64     }
65 
checkConstantRefs()66     private static void checkConstantRefs() throws Throwable {
67         // check some constant references to its self class
68         assertEquals(MT_bsm(), MH_bsm().type());
69         assertEquals(MT_bsm2(), MH_bsm2().type());
70         assertEquals(MT_bsm(), non_MH_bsm().type());
71     }
assertEquals(Object exp, Object act)72     private static void assertEquals(Object exp, Object act) {
73         if (exp == act || (exp != null && exp.equals(act)))  return;
74         throw new AssertionError("not equal: "+exp+", "+act);
75     }
76 
setSM()77     private static void setSM() {
78         Policy.setPolicy(new TestPolicy());
79         System.setSecurityManager(new SecurityManager());
80     }
81 
82     private static PrintStream oldOut;
83     private static ByteArrayOutputStream buf;
openBuf()84     private static void openBuf() {
85         oldOut = System.out;
86         buf = new ByteArrayOutputStream();
87         System.setOut(new PrintStream(buf));
88     }
closeBuf()89     private static void closeBuf() {
90         if (buf == null)  return;
91         System.out.flush();
92         System.setOut(oldOut);
93         String[] haveLines = new String(buf.toByteArray()).split("[\n\r]+");
94         for (String line : haveLines)  System.out.println(line);
95         Iterator<String> iter = Arrays.asList(haveLines).iterator();
96         for (String want : EXPECT_OUTPUT) {
97             String have = iter.hasNext() ? iter.next() : "[EOF]";
98             if (want.equals(have))  continue;
99             System.err.println("want line: "+want);
100             System.err.println("have line: "+have);
101             throw new AssertionError("unexpected output: "+have);
102         }
103         if (iter.hasNext())
104             throw new AssertionError("unexpected output: "+iter.next());
105     }
106     private static final String[] EXPECT_OUTPUT = {
107         "Printing some argument lists, starting with a empty one:",
108         "[test.java.lang.invoke.InvokeDynamicPrintArgs, nothing, ()void][]",
109         "[test.java.lang.invoke.InvokeDynamicPrintArgs, bar, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar arg, 1]",
110         "[test.java.lang.invoke.InvokeDynamicPrintArgs, bar2, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar2 arg, 222]",
111         "[test.java.lang.invoke.InvokeDynamicPrintArgs, baz, (String,int,double)void, 1234.5][baz arg, 2, 3.14]",
112         "[test.java.lang.invoke.InvokeDynamicPrintArgs, foo, (String)void][foo arg]",
113         "Done printing argument lists."
114     };
115 
116     private static boolean doPrint = true;
printArgs(Object bsmInfo, Object... args)117     private static void printArgs(Object bsmInfo, Object... args) {
118         String message = bsmInfo+Arrays.deepToString(args);
119         if (doPrint)  System.out.println(message);
120     }
MH_printArgs()121     private static MethodHandle MH_printArgs() throws ReflectiveOperationException {
122         shouldNotCallThis();
123         return lookup().findStatic(lookup().lookupClass(),
124                                    "printArgs", methodType(void.class, Object.class, Object[].class));
125     }
126 
bsm(Lookup caller, String name, MethodType type)127     private static CallSite bsm(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
128         // ignore caller and name, but match the type:
129         Object bsmInfo = Arrays.asList(caller, name, type);
130         return new ConstantCallSite(MH_printArgs().bindTo(bsmInfo).asCollector(Object[].class, type.parameterCount()).asType(type));
131     }
MT_bsm()132     private static MethodType MT_bsm() {
133         shouldNotCallThis();
134         return methodType(CallSite.class, Lookup.class, String.class, MethodType.class);
135     }
MH_bsm()136     private static MethodHandle MH_bsm() throws ReflectiveOperationException {
137         shouldNotCallThis();
138         return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
139     }
non_MH_bsm()140     private static MethodHandle non_MH_bsm() throws ReflectiveOperationException {
141         return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
142     }
143 
144     /* Example of a constant call site with user-data.
145      * In this case, the user data is exactly the BSM data.
146      * Note that a CCS with user data must use the "hooked" constructor
147      * to bind the CCS itself into the resulting target.
148      * A normal constructor would not allow a circular relation
149      * between the CCS and its target.
150      */
151     public static class PrintingCallSite extends ConstantCallSite {
152         final Lookup caller;
153         final String name;
154         final Object[] staticArgs;
155 
PrintingCallSite(Lookup caller, String name, MethodType type, Object... staticArgs)156         PrintingCallSite(Lookup caller, String name, MethodType type, Object... staticArgs) throws Throwable {
157             super(type, MH_createTarget());
158             this.caller = caller;
159             this.name = name;
160             this.staticArgs = staticArgs;
161         }
162 
createTarget()163         public MethodHandle createTarget() {
164             try {
165                 return lookup().bind(this, "runTarget", genericMethodType(0, true)).asType(type());
166             } catch (ReflectiveOperationException ex) {
167                 throw new RuntimeException(ex);
168             }
169         }
170 
runTarget(Object... dynamicArgs)171         public Object runTarget(Object... dynamicArgs) {
172             List<Object> bsmInfo = new ArrayList<>(Arrays.asList(caller, name, type()));
173             bsmInfo.addAll(Arrays.asList(staticArgs));
174             printArgs(bsmInfo, dynamicArgs);
175             return null;
176         }
177 
MH_createTarget()178         private static MethodHandle MH_createTarget() throws ReflectiveOperationException {
179             shouldNotCallThis();
180             return lookup().findVirtual(lookup().lookupClass(), "createTarget", methodType(MethodHandle.class));
181         }
182     }
bsm2(Lookup caller, String name, MethodType type, Object... arg)183     private static CallSite bsm2(Lookup caller, String name, MethodType type, Object... arg) throws Throwable {
184         // ignore caller and name, but match the type:
185         return new PrintingCallSite(caller, name, type, arg);
186     }
MT_bsm2()187     private static MethodType MT_bsm2() {
188         shouldNotCallThis();
189         return methodType(CallSite.class, Lookup.class, String.class, MethodType.class, Object[].class);
190     }
MH_bsm2()191     private static MethodHandle MH_bsm2() throws ReflectiveOperationException {
192         shouldNotCallThis();
193         return lookup().findStatic(lookup().lookupClass(), "bsm2", MT_bsm2());
194     }
195 
INDY_nothing()196     private static MethodHandle INDY_nothing() throws Throwable {
197         shouldNotCallThis();
198         return ((CallSite) MH_bsm().invoke(lookup(),
199                                                   "nothing", methodType(void.class)
200                                                   )).dynamicInvoker();
201     }
INDY_foo()202     private static MethodHandle INDY_foo() throws Throwable {
203         shouldNotCallThis();
204         return ((CallSite) MH_bsm().invoke(lookup(),
205                                                   "foo", methodType(void.class, String.class)
206                                                   )).dynamicInvoker();
207     }
INDY_bar()208     private static MethodHandle INDY_bar() throws Throwable {
209         shouldNotCallThis();
210         return ((CallSite) MH_bsm2().invoke(lookup(),
211                                                   "bar", methodType(void.class, String.class, int.class)
212                                                   , Void.class, "void type!", 1, 234.5F, 67.5, (long)89
213                                                   )).dynamicInvoker();
214     }
INDY_bar2()215     private static MethodHandle INDY_bar2() throws Throwable {
216         shouldNotCallThis();
217         return ((CallSite) MH_bsm2().invoke(lookup(),
218                                                   "bar2", methodType(void.class, String.class, int.class)
219                                                   , Void.class, "void type!", 1, 234.5F, 67.5, (long)89
220                                                   )).dynamicInvoker();
221     }
INDY_baz()222     private static MethodHandle INDY_baz() throws Throwable {
223         shouldNotCallThis();
224         return ((CallSite) MH_bsm2().invoke(lookup(),
225                                                   "baz", methodType(void.class, String.class, int.class, double.class)
226                                                   , 1234.5
227                                                   )).dynamicInvoker();
228     }
229 
shouldNotCallThis()230     private static void shouldNotCallThis() {
231         // if this gets called, the transformation has not taken place
232         if (System.getProperty("InvokeDynamicPrintArgs.allow-untransformed") != null)  return;
233         throw new AssertionError("this code should be statically transformed away by Indify");
234     }
235 
236     static class TestPolicy extends Policy {
237         static final Policy DEFAULT_POLICY = Policy.getPolicy();
238 
239         final PermissionCollection permissions = new Permissions();
TestPolicy()240         TestPolicy() {
241             permissions.add(new java.io.FilePermission("<<ALL FILES>>", "read"));
242         }
getPermissions(ProtectionDomain domain)243         public PermissionCollection getPermissions(ProtectionDomain domain) {
244             return permissions;
245         }
246 
getPermissions(CodeSource codesource)247         public PermissionCollection getPermissions(CodeSource codesource) {
248             return permissions;
249         }
250 
implies(ProtectionDomain domain, Permission perm)251         public boolean implies(ProtectionDomain domain, Permission perm) {
252             return permissions.implies(perm) || DEFAULT_POLICY.implies(domain, perm);
253         }
254     }
255 }
256