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 /lib/testlibrary/bytecode /java/lang/invoke/common
  29  * @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper
  30  * @run testng/timeout=999999 CondyBSMInvocation
  31  */
  32 
  33 
  34 import org.testng.Assert;
  35 import org.testng.annotations.Test;
  36 import test.java.lang.invoke.lib.InstructionHelper;
  37 
  38 import java.lang.invoke.MethodHandle;
  39 import java.lang.invoke.MethodHandles;
  40 import java.lang.invoke.MethodType;
  41 import java.lang.invoke.WrongMethodTypeException;
  42 import java.util.Arrays;
  43 import java.util.Collections;
  44 import java.util.stream.IntStream;
  45 import java.util.stream.Stream;
  46 
  47 import static java.lang.invoke.MethodType.methodType;
  48 
  49 public class CondyBSMInvocation {
  50     static final MethodHandles.Lookup L = MethodHandles.lookup();
  51 
  52 
  53     @Test
  54     public void testNonexistent() throws Throwable {
  55         MethodHandle mh = InstructionHelper.ldcDynamicConstant(
  56                 L, "invoke", Object.class,
  57                 "noSuchMethod", methodType(Object.class),
  58                 S -> {});
  59 
  60         try {
  61             mh.invoke();
  62             Assert.fail("NoSuchMethodError expected to be thrown");
  63         } catch (NoSuchMethodError e) {
  64         }
  65     }
  66 
  67     @Test
  68     public void testBadExpr() throws Throwable {
  69         MethodHandle mh = InstructionHelper.ldcDynamicConstant(
  70                 L, "noSuchExprMode", Object.class,
  71                 "bsm", methodType(Object.class),
  72                 S -> {});
  73 
  74         try {
  75             mh.invoke();
  76             Assert.fail("BootstrapMethodError expected to be thrown");
  77         } catch (BootstrapMethodError e) {
  78             Assert.assertEquals(e.getCause().getClass(), IllegalArgumentException.class);
  79             // Example: java.lang.IllegalArgumentException: invalid name
  80             //     for expression-mode constant: CondyBSMInvocation.bsm()Object
  81             //     /invokeStatic/noSuchExprMode:class java.lang.Object[]
  82 
  83         }
  84     }
  85 
  86     static MethodHandle[] bsms(String bsmName) {
  87         return Stream.of(CondyBSMInvocation.class.getDeclaredMethods()).
  88                 filter(m -> m.getName().equals(bsmName)).
  89                 map(m -> {
  90                     try {
  91                         return MethodHandles.lookup().unreflect(m);
  92                     } catch (IllegalAccessException e) {
  93                         throw new RuntimeException();
  94                     }
  95                 }).toArray(MethodHandle[]::new);
  96     }
  97 
  98     public static Object shape_bsm() {
  99         return "0";
 100     }
 101 
 102     public static Object shape_bsm(Object a1) {
 103         return "0";
 104     }
 105 
 106     public static Object shape_bsm(Object... args) {
 107         return "0";
 108     }
 109 
 110     public static Object shape_bsm(Object a1, Object a2) {
 111         return "0";
 112     }
 113 
 114     public static Object shape_bsm(Object a1, Object... args) {
 115         return "0";
 116     }
 117 
 118     public static Object shape_bsm(Object a1, Object a2, Object a3) {
 119         return "0";
 120     }
 121 
 122     public static Object shape_bsm(MethodHandles.Lookup a1) {
 123         return "0";
 124     }
 125 
 126     @Test
 127     public void testWrongShape() throws Throwable {
 128         for (MethodHandle bsm : bsms("shape_bsm")) {
 129             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 130                     L, "name", Object.class,
 131                     "shape_bsm", bsm.type(),
 132                     S -> {}
 133             );
 134 
 135             try {
 136                 Object r = mh.invoke();
 137                 Assert.fail("BootstrapMethodError expected to be thrown for " + bsm);
 138             } catch (BootstrapMethodError e) {
 139             }
 140         }
 141     }
 142 
 143 
 144     public static Object sig_bsm(MethodHandles.Lookup a1, String[] a2) {
 145         return "0";
 146     }
 147 
 148     public static Object sig_bsm(MethodHandles.Lookup a1, String a2, String a3) {
 149         return "0";
 150     }
 151 
 152     @Test
 153     public void testWrongSignature() throws Throwable {
 154         for (MethodHandle bsm : bsms("sig_bsm")) {
 155             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 156                     L, "name", Object.class,
 157                     "sig_bsm", bsm.type(),
 158                     S -> {}
 159             );
 160 
 161             try {
 162                 Object r = mh.invoke();
 163                 Assert.fail("BootstrapMethodError expected to be thrown for " + bsm);
 164             } catch (BootstrapMethodError e) {
 165             }
 166         }
 167     }
 168 
 169 
 170     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type) {
 171         return "0";
 172     }
 173 
 174     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
 175                              Object a1) {
 176         assertAll(a1);
 177         return "1";
 178     }
 179 
 180     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
 181                              Object a1, Object a2) {
 182         assertAll(a1, a2);
 183         return "2";
 184     }
 185 
 186     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
 187                              Object a1, Object a2, Object a3) {
 188         assertAll(a1, a2, a3);
 189         return "3";
 190     }
 191 
 192     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
 193                              Object a1, Object a2, Object a3, Object a4) {
 194         assertAll(a1, a2, a3, a4);
 195         return "4";
 196     }
 197 
 198     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
 199                              Object a1, Object a2, Object a3, Object a4, Object a5) {
 200         assertAll(a1, a2, a3, a4, a5);
 201         return "5";
 202     }
 203 
 204     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
 205                              Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) {
 206         assertAll(a1, a2, a3, a4, a5, a6);
 207         return "6";
 208     }
 209 
 210     public static Object bsm(MethodHandles.Lookup l, String name, Class<?> type,
 211                              Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) {
 212         assertAll(a1, a2, a3, a4, a5, a6, a7);
 213         return "7";
 214     }
 215 
 216     public static Object bsm(MethodHandles.Lookup l, Object... args) {
 217         Object[] staticArgs = Arrays.copyOfRange(args, 2, args.length);
 218         assertAll(staticArgs);
 219         return Integer.toString(staticArgs.length);
 220     }
 221 
 222     // expression mode BSMs
 223     public static Object bsm() {
 224         return bsm((MethodHandles.Lookup)null, null, null);
 225     }
 226     public static Object bsm(Object a1) {
 227         return bsm((MethodHandles.Lookup)null, null, null, a1);
 228     }
 229     public static Object bsm(Object a1, Object a2) {
 230         return bsm((MethodHandles.Lookup)null, null, null, a1, a2);
 231     }
 232     public static Object bsm(Object a1, Object a2, Object a3) {
 233         return bsm((MethodHandles.Lookup)null, null, null, a1, a2, a3);
 234     }
 235     public static Object bsm(Object a1, Object a2, Object a3, Object a4) {
 236         return bsm((MethodHandles.Lookup)null, null, null, a1, a2, a3, a4);
 237     }
 238     public static Object bsm(Object a1, Object a2, Object a3, Object a4, Object a5) {
 239         return bsm((MethodHandles.Lookup)null, null, null, a1, a2, a3, a4, a5);
 240     }
 241     public static Object bsm(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) {
 242         return bsm((MethodHandles.Lookup)null, null, null, a1, a2, a3, a4, a5, a6);
 243     }
 244     public static Object bsm(Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) {
 245         return bsm((MethodHandles.Lookup)null, null, null, a1, a2, a3, a4, a5, a6, a7);
 246     }
 247     public static Object bsm(Object... args) {
 248         assertAll(args);
 249         return Integer.toString(args.length);
 250     }
 251 
 252     static void assertAll(Object... as) {
 253         for (int i = 0; i < as.length; i++) {
 254             Assert.assertEquals(as[i], i);
 255         }
 256     }
 257 
 258     @Test
 259     public void testArity() throws Throwable {
 260         for (int i = 0; i < 8; i++) {
 261             final int n = i;
 262             MethodType mt = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class)
 263                     .appendParameterTypes(Collections.nCopies(n, Object.class));
 264             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 265                     L, "name", Object.class,
 266                     "bsm", mt,
 267                     S -> IntStream.range(0, n).forEach(S::add)
 268                     );
 269 
 270             Object r = mh.invoke();
 271             Assert.assertEquals(r, Integer.toString(n));
 272         }
 273 
 274         {
 275             MethodType mt = methodType(Object.class, MethodHandles.Lookup.class, Object[].class);
 276             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 277                     L, "name", Object.class,
 278                     "bsm", mt,
 279                     S -> IntStream.range(0, 9).forEach(S::add)
 280             );
 281 
 282             Object r = mh.invoke();
 283             Assert.assertEquals(r, Integer.toString(9));
 284 
 285         }
 286     }
 287 
 288     @Test
 289     public void testArityWithoutMetadata() throws Throwable {
 290         for (int i = 0; i < 8; i++) {
 291             final int n = i;
 292             MethodType mt = methodType(Object.class)
 293                     .appendParameterTypes(Collections.nCopies(n, Object.class));
 294             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 295                     L, "invoke", Object.class,
 296                     "bsm", mt,
 297                     S -> IntStream.range(0, n).forEach(S::add)
 298             );
 299 
 300             Object r = mh.invoke();
 301             Assert.assertEquals(r, Integer.toString(n));
 302         }
 303 
 304         {
 305             MethodType mt = methodType(Object.class, Object[].class);
 306             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 307                     L, "invoke", Object.class,
 308                     "bsm", mt,
 309                     S -> IntStream.range(0, 9).forEach(S::add)
 310             );
 311 
 312             Object r = mh.invoke();
 313             Assert.assertEquals(r, Integer.toString(9));
 314         }
 315     }
 316     @Test
 317     public void testArityAsSymbolic() throws Throwable {
 318         for (int i = 0; i < 8; i++) {
 319             final int n = i;
 320             MethodType mt = methodType(Object.class)
 321                     .appendParameterTypes(Collections.nCopies(n, Object.class));
 322             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 323                     L, "symbolic", Object.class,
 324                     "bsm", mt,
 325                     S -> IntStream.range(0, n).forEach(S::add)
 326             );
 327 
 328             Object r = mh.invoke();
 329             Assert.assertEquals(r, Integer.toString(n));
 330         }
 331 
 332         {
 333             MethodType mt = methodType(Object.class, Object[].class);
 334             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 335                     L, "symbolic", Object.class,
 336                     "bsm", mt,
 337                     S -> IntStream.range(0, 9).forEach(S::add)
 338             );
 339 
 340             Object r = mh.invoke();
 341             Assert.assertEquals(r, Integer.toString(9));
 342         }
 343     }
 344 
 345     @Test
 346     public void testWrongNumberOfStaticArgumentsWithMetaData() throws Throwable {
 347         for (int i = 1; i < 8; i++) {
 348             final int n = i;
 349             MethodType mt = methodType(Object.class, MethodHandles.Lookup.class, String.class, Class.class)
 350                     .appendParameterTypes(Collections.nCopies(n, Object.class));
 351             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 352                     L, "name", Object.class,
 353                     "bsm", mt,
 354                     S -> IntStream.range(0, n - 1).forEach(S::add)
 355             );
 356 
 357             try {
 358                 Object r = mh.invoke();
 359                 Assert.fail("BootstrapMethodError expected to be thrown for arrity " + n);
 360             } catch (BootstrapMethodError e) {
 361                 Throwable t = e.getCause();
 362                 Assert.assertTrue(WrongMethodTypeException.class.isAssignableFrom(t.getClass()));
 363             }
 364         }
 365     }
 366 
 367     @Test
 368     public void testWrongNumberOfStaticArgumentsWithoutMetaData() throws Throwable {
 369         for (int i = 1; i < 8; i++) {
 370             final int n = i;
 371             MethodType mt = methodType(Object.class)
 372                     .appendParameterTypes(Collections.nCopies(n, Object.class));
 373             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 374                     L, "invoke", Object.class,
 375                     "bsm", mt,
 376                     S -> IntStream.range(0, n - 1).forEach(S::add)
 377             );
 378 
 379             try {
 380                 Object r = mh.invoke();
 381                 Assert.fail("BootstrapMethodError expected to be thrown for arrity " + n);
 382             } catch (BootstrapMethodError e) {
 383                 Throwable t = e.getCause();
 384                 Assert.assertTrue(WrongMethodTypeException.class.isAssignableFrom(t.getClass()));
 385             }
 386         }
 387     }
 388 
 389 }