1 /*
   2  * Copyright (c) 2017, 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
  27  * @summary Test bootstrap methods throwing an exception
  28  * @library /lib/testlibrary/bytecode /java/lang/invoke/common
  29  * @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper
  30  * @run testng BootstrapMethodJumboArgsTest
  31  */
  32 
  33 import jdk.experimental.bytecode.PoolHelper;
  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.ConstantCallSite;
  39 import java.lang.invoke.MethodHandle;
  40 import java.lang.invoke.MethodHandles;
  41 import java.lang.invoke.MethodType;
  42 import java.util.stream.IntStream;
  43 
  44 import static java.lang.invoke.MethodType.methodType;
  45 
  46 public class BootstrapMethodJumboArgsTest {
  47     static final MethodHandles.Lookup L = MethodHandles.lookup();
  48 
  49 
  50     static Object bsmZero(MethodHandles.Lookup l, String name, Object type,
  51                       Object... args) {
  52         Object[] a = args.clone();
  53         if (type instanceof MethodType) {
  54             return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
  55         }
  56         else {
  57             return a;
  58         }
  59     }
  60 
  61     static Object bsmOne(MethodHandles.Lookup l, String name, Object type,
  62                          Object first, Object... args) {
  63         Object[] a = new Object[args.length + 1];
  64         a[0] = first;
  65         System.arraycopy(args, 0, a, 1, args.length);
  66         if (type instanceof MethodType) {
  67             return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
  68         }
  69         else {
  70             return a;
  71         }
  72     }
  73 
  74     static Object bsmTwo(MethodHandles.Lookup l, String name, Object type,
  75                          Object first, Object second, Object... args) {
  76         Object[] a = new Object[args.length + 2];
  77         a[0] = first;
  78         a[1] = second;
  79         System.arraycopy(args, 0, a, 2, args.length);
  80         if (type instanceof MethodType) {
  81             return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
  82         }
  83         else {
  84             return a;
  85         }
  86     }
  87 
  88     // Expression-mode versions of bsm*
  89     static Object bsmZeroExpr(Object... args) {
  90         return bsmZero(null, null, null, args);
  91     }
  92     static Object bsmOneExpr(Object first, Object... args) {
  93         return bsmOne(null, null, null, first, args);
  94     }
  95     static Object bsmTwoExpr(Object first, Object second, Object... args) {
  96         return bsmTwo(null, null, null, first, second, args);
  97     }
  98 
  99     static void manyStaticStrings(String[] args, PoolHelper.StaticArgListBuilder<String, String, byte[]> staticArgs) {
 100         for (String s : args) {
 101             staticArgs.add(s);
 102         }
 103     }
 104 
 105     @Test
 106     public void testCondyWithJumboArgs() throws Throwable {
 107         String[] expected = IntStream.range(0, 1000).mapToObj(Integer::toString).toArray(String[]::new);
 108 
 109         {
 110             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 111                     L, "name", Object[].class,
 112                     "bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object[].class),
 113                     S -> manyStaticStrings(expected, S));
 114 
 115             Object[] actual = (Object[]) mh.invoke();
 116             Assert.assertEquals(actual, expected);
 117         }
 118 
 119         {
 120             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 121                     L, "name", Object[].class,
 122                     "bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object[].class),
 123                     S -> manyStaticStrings(expected, S));
 124 
 125             Object[] actual = (Object[]) mh.invoke();
 126             Assert.assertEquals(actual, expected);
 127         }
 128 
 129         {
 130             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 131                     L, "name", Object[].class,
 132                     "bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object.class, Object[].class),
 133                     S -> manyStaticStrings(expected, S));
 134 
 135             Object[] actual = (Object[]) mh.invoke();
 136             Assert.assertEquals(actual, expected);
 137         }
 138     }
 139 
 140     @Test
 141     public void testCondyWithJumboArgsWithoutMetaData() throws Throwable {
 142         String[] expected = IntStream.range(0, 1000).mapToObj(Integer::toString).toArray(String[]::new);
 143 
 144         {
 145             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 146                     L, "invoke", Object[].class,
 147                     "bsmZeroExpr", methodType(Object.class, Object[].class),
 148                     S -> manyStaticStrings(expected, S));
 149 
 150             Object[] actual = (Object[]) mh.invoke();
 151             Assert.assertEquals(actual, expected);
 152         }
 153 
 154         {
 155             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 156                     L, "invoke", Object[].class,
 157                     "bsmOneExpr", methodType(Object.class, Object.class, Object[].class),
 158                     S -> manyStaticStrings(expected, S));
 159 
 160             Object[] actual = (Object[]) mh.invoke();
 161             Assert.assertEquals(actual, expected);
 162         }
 163 
 164         {
 165             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 166                     L, "invoke", Object[].class,
 167                     "bsmTwoExpr", methodType(Object.class, Object.class, Object.class, Object[].class),
 168                     S -> manyStaticStrings(expected, S));
 169 
 170             Object[] actual = (Object[]) mh.invoke();
 171             Assert.assertEquals(actual, expected);
 172         }
 173     }
 174 
 175     @Test
 176     public void testIndyWithJumboArgs() throws Throwable {
 177         String[] expected = IntStream.range(0, 1000).mapToObj(Integer::toString).toArray(String[]::new);
 178 
 179         {
 180             MethodHandle mh = InstructionHelper.invokedynamic(
 181                     L, "name", methodType(Object[].class),
 182                     "bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object[].class),
 183                     S -> manyStaticStrings(expected, S));
 184 
 185             Object[] actual = (Object[]) mh.invoke();
 186             Assert.assertEquals(actual, expected);
 187         }
 188 
 189         {
 190             MethodHandle mh = InstructionHelper.invokedynamic(
 191                     L, "name", methodType(Object[].class),
 192                     "bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object[].class),
 193                     S -> manyStaticStrings(expected, S));
 194 
 195             Object[] actual = (Object[]) mh.invoke();
 196             Assert.assertEquals(actual, expected);
 197         }
 198 
 199         {
 200             MethodHandle mh = InstructionHelper.invokedynamic(
 201                     L, "name", methodType(Object[].class),
 202                     "bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object.class, Object.class, Object[].class),
 203                     S -> manyStaticStrings(expected, S));
 204 
 205             Object[] actual = (Object[]) mh.invoke();
 206             Assert.assertEquals(actual, expected);
 207         }
 208     }
 209 }