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  * @run testng/othervm -XX:+UnlockDiagnosticVMOptions -XX:UseBootstrapCallInfo=3 BootstrapMethodJumboArgsTest
  32  */
  33 
  34 import jdk.experimental.bytecode.PoolHelper;
  35 import org.testng.Assert;
  36 import org.testng.annotations.Test;
  37 import test.java.lang.invoke.lib.InstructionHelper;
  38 
  39 import java.lang.invoke.ConstantCallSite;
  40 import java.lang.invoke.MethodHandle;
  41 import java.lang.invoke.MethodHandles;
  42 import java.lang.invoke.MethodType;
  43 import java.util.stream.IntStream;
  44 
  45 import static java.lang.invoke.MethodType.methodType;
  46 
  47 public class BootstrapMethodJumboArgsTest {
  48     static final MethodHandles.Lookup L = MethodHandles.lookup();
  49 
  50 
  51     static Object bsmZero(MethodHandles.Lookup l, String name, Object type,
  52                       Object... args) {
  53         Object[] a = args.clone();
  54         if (type instanceof MethodType) {
  55             return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
  56         }
  57         else {
  58             return a;
  59         }
  60     }
  61 
  62     static Object bsmOne(MethodHandles.Lookup l, String name, Object type,
  63                          Object first, Object... args) {
  64         Object[] a = new Object[args.length + 1];
  65         a[0] = first;
  66         System.arraycopy(args, 0, a, 1, args.length);
  67         if (type instanceof MethodType) {
  68             return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
  69         }
  70         else {
  71             return a;
  72         }
  73     }
  74 
  75     static Object bsmTwo(MethodHandles.Lookup l, String name, Object type,
  76                          Object first, Object second, Object... args) {
  77         Object[] a = new Object[args.length + 2];
  78         a[0] = first;
  79         a[1] = second;
  80         System.arraycopy(args, 0, a, 2, args.length);
  81         if (type instanceof MethodType) {
  82             return new ConstantCallSite(MethodHandles.constant(Object[].class, a));
  83         }
  84         else {
  85             return a;
  86         }
  87     }
  88 
  89     static void manyStaticStrings(String[] args, PoolHelper.StaticArgListBuilder<String, String, byte[]> staticArgs) {
  90         for (String s : args) {
  91             staticArgs.add(s);
  92         }
  93     }
  94 
  95     @Test
  96     public void testCondyWithJumboArgs() throws Throwable {
  97         String[] expected = IntStream.range(0, 1000).mapToObj(Integer::toString).toArray(String[]::new);
  98 
  99         {
 100             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 101                     L, "name", Object[].class,
 102                     "bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object[].class),
 103                     S -> manyStaticStrings(expected, S));
 104 
 105             Object[] actual = (Object[]) mh.invoke();
 106             Assert.assertEquals(actual, expected);
 107         }
 108 
 109         {
 110             MethodHandle mh = InstructionHelper.ldcDynamicConstant(
 111                     L, "name", Object[].class,
 112                     "bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.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                     "bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.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     @Test
 131     public void testIndyWithJumboArgs() throws Throwable {
 132         String[] expected = IntStream.range(0, 1000).mapToObj(Integer::toString).toArray(String[]::new);
 133 
 134         {
 135             MethodHandle mh = InstructionHelper.invokedynamic(
 136                     L, "name", methodType(Object[].class),
 137                     "bsmZero", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, Object[].class),
 138                     S -> manyStaticStrings(expected, S));
 139 
 140             Object[] actual = (Object[]) mh.invoke();
 141             Assert.assertEquals(actual, expected);
 142         }
 143 
 144         {
 145             MethodHandle mh = InstructionHelper.invokedynamic(
 146                     L, "name", methodType(Object[].class),
 147                     "bsmOne", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, 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.invokedynamic(
 156                     L, "name", methodType(Object[].class),
 157                     "bsmTwo", methodType(Object.class, MethodHandles.Lookup.class, String.class, Object.class, 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 }