1 /*
  2  * Copyright (c) 2017, 2018, 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 8186046 8199875
 27  * @summary Test basic invocation of bootstrap methods
 28  * @library /java/lang/invoke/common
 29  * @enablePreview
 30  * @run testng CondyBSMInvocation
 31  * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 CondyBSMInvocation
 32  */
 33 
 34 
 35 import org.testng.Assert;
 36 import org.testng.annotations.Test;
 37 import test.java.lang.invoke.lib.InstructionHelper;
 38 
 39 import java.lang.constant.ConstantDesc;
 40 import java.lang.invoke.MethodHandle;
 41 import java.lang.invoke.MethodHandles;
 42 import java.lang.invoke.MethodType;
 43 import java.lang.invoke.WrongMethodTypeException;
 44 import java.util.Arrays;
 45 import java.util.Collections;
 46 import java.util.stream.IntStream;
 47 import java.util.stream.Stream;
 48 
 49 import static java.lang.invoke.MethodType.methodType;
 50 
 51 public class CondyBSMInvocation {
 52     static final MethodHandles.Lookup L = MethodHandles.lookup();
 53 
 54 
 55     @Test
 56     public void testNonexistent() throws Throwable {
 57         MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 58                 L, "name", Object.class,
 59                 "bsm", methodType(Object.class)
 60         );
 61 
 62         try {
 63             mh.invoke();
 64             Assert.fail("NoSuchMethodError expected to be thrown");
 65         } catch (NoSuchMethodError e) {
 66         }
 67     }
 68 
 69     static MethodHandle[] bsms(String bsmName) {
 70         return Stream.of(CondyBSMInvocation.class.getDeclaredMethods()).
 71                 filter(m -> m.getName().equals(bsmName)).
 72                 map(m -> {
 73                     try {
 74                         return MethodHandles.lookup().unreflect(m);
 75                     } catch (IllegalAccessException e) {
 76                         throw new RuntimeException();
 77                     }
 78                 }).toArray(MethodHandle[]::new);
 79     }
 80 
 81     public static Object shape_bsm() {
 82         return "0";
 83     }
 84 
 85     public static Object shape_bsm(Object a1) {
 86         return "0";
 87     }
 88 
 89     public static Object shape_bsm(Object... args) {
 90         return "0";
 91     }
 92 
 93     public static Object shape_bsm(Object a1, Object a2) {
 94         return "0";
 95     }
 96 
 97     public static Object shape_bsm(Object a1, Object... args) {
 98         return "0";
 99     }
100 
101     public static Object shape_bsm(Object a1, Object a2, Object a3) {
102         return "0";
103     }
104 
105     public static Object shape_bsm(MethodHandles.Lookup a1) {
106         return "0";
107     }
108 
109     @Test
110     public void testWrongShape() throws Throwable {
111         for (MethodHandle bsm : bsms("shape_bsm")) {
112             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
113                     L, "name", Object.class,
114                     "shape_bsm", bsm.type()
115             );
116 
117             try {
118                 Object r = mh.invoke();
119                 Assert.fail("BootstrapMethodError expected to be thrown for " + bsm);
120             } catch (BootstrapMethodError e) {
121             }
122         }
123     }
124 
125 
126     public static Object sig_bsm(MethodHandles.Lookup a1, String[] a2) {
127         return "0";
128     }
129 
130     public static Object sig_bsm(MethodHandles.Lookup a1, String a2, String a3) {
131         return "0";
132     }
133 
134     @Test
135     public void testWrongSignature() throws Throwable {
136         for (MethodHandle bsm : bsms("sig_bsm")) {
137             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
138                     L, "name", Object.class,
139                     "sig_bsm", bsm.type()
140             );
141 
142             try {
143                 Object r = mh.invoke();
144                 Assert.fail("BootstrapMethodError expected to be thrown for " + bsm);
145             } catch (BootstrapMethodError e) {
146             }
147         }
148     }
149 
150 
151     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type) {
152         return "0";
153     }
154 
155     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
156                              Object a1) {
157         assertAll(a1);
158         return "1";
159     }
160 
161     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
162                              Object a1, Object a2) {
163         assertAll(a1, a2);
164         return "2";
165     }
166 
167     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
168                              Object a1, Object a2, Object a3) {
169         assertAll(a1, a2, a3);
170         return "3";
171     }
172 
173     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
174                              Object a1, Object a2, Object a3, Object a4) {
175         assertAll(a1, a2, a3, a4);
176         return "4";
177     }
178 
179     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
180                              Object a1, Object a2, Object a3, Object a4, Object a5) {
181         assertAll(a1, a2, a3, a4, a5);
182         return "5";
183     }
184 
185     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
186                              Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) {
187         assertAll(a1, a2, a3, a4, a5, a6);
188         return "6";
189     }
190 
191     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
192                              Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) {
193         assertAll(a1, a2, a3, a4, a5, a6, a7);
194         return "7";
195     }
196 
197     public static Object bsm(MethodHandles.Lookup l, Object... args) {
198         Object[] staticArgs = Arrays.copyOfRange(args, 2, args.length);
199         assertAll(staticArgs);
200         return Integer.toString(staticArgs.length);
201     }
202 
203     static void assertAll(Object... as) {
204         for (int i = 0; i < as.length; i++) {
205             Assert.assertEquals(as[i], i);
206         }
207     }
208 
209     @Test
210     public void testArity() throws Throwable {
211         for (int i = 0; i < 8; i++) {
212             final int n = i;
213             MethodType mt = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class)
214                     .appendParameterTypes(Collections.nCopies(n, Object.class));
215             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
216                     L, "name", Object.class,
217                     "bsm", mt,
218                     IntStream.range(0, n).boxed().toArray(ConstantDesc[]::new)
219             );
220 
221             Object r = mh.invoke();
222             Assert.assertEquals(r, Integer.toString(n));
223         }
224 
225         {
226             MethodType mt = methodType(Object.class, MethodHandles.Lookup.class, Object[].class);
227             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
228                     L, "name", Object.class,
229                     "bsm", mt,
230                     IntStream.range(0, 9).boxed().toArray(ConstantDesc[]::new)
231             );
232 
233             Object r = mh.invoke();
234             Assert.assertEquals(r, Integer.toString(9));
235 
236         }
237     }
238 
239     @Test
240     public void testWrongNumberOfStaticArguments() throws Throwable {
241         for (int i = 1; i < 8; i++) {
242             final int n = i;
243             MethodType mt = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class)
244                     .appendParameterTypes(Collections.nCopies(n, Object.class));
245             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
246                     L, "name", Object.class,
247                     "bsm", mt,
248                     IntStream.range(0, n - 1).boxed().toArray(ConstantDesc[]::new)
249             );
250 
251             try {
252                 Object r = mh.invoke();
253                 Assert.fail("BootstrapMethodError expected to be thrown for arrity " + n);
254             } catch (BootstrapMethodError e) {
255                 Throwable t = e.getCause();
256                 Assert.assertTrue(WrongMethodTypeException.class.isAssignableFrom(t.getClass()));
257             }
258         }
259     }
260 }