1 /*
   2  * Copyright (c) 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 /* @test
  25  * @summary unit tests for java.lang.invoke.MethodHandles
  26  * @library /lib/testlibrary /java/lang/invoke/common
  27  * @compile MethodHandlesTest.java MethodHandlesAsCollectorTest.java remote/RemoteExample.java
  28  * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions
  29  *                                 -XX:-VerifyDependencies
  30  *                                 -esa
  31  *                                 test.java.lang.invoke.MethodHandlesAsCollectorTest
  32  */
  33 
  34 package test.java.lang.invoke;
  35 
  36 import org.junit.*;
  37 import test.java.lang.invoke.lib.CodeCacheOverflowProcessor;
  38 
  39 import java.lang.invoke.MethodHandle;
  40 import java.lang.invoke.MethodType;
  41 import java.util.Arrays;
  42 
  43 import static org.junit.Assert.*;
  44 
  45 public class MethodHandlesAsCollectorTest extends MethodHandlesTest {
  46 
  47     @Test // SLOW
  48     public void testAsCollector() throws Throwable {
  49         CodeCacheOverflowProcessor.runMHTest(this::testAsCollector0);
  50         CodeCacheOverflowProcessor.runMHTest(this::testAsCollector1);
  51     }
  52 
  53     public void testAsCollector0() throws Throwable {
  54         if (CAN_SKIP_WORKING)  return;
  55         startTest("asCollector");
  56         for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
  57             if (verbosity >= 3)
  58                 System.out.println("asCollector "+argType);
  59             for (int nargs = 0; nargs < 50; nargs++) {
  60                 if (CAN_TEST_LIGHTLY && nargs > 11)  break;
  61                 for (int pos = 0; pos <= nargs; pos++) {
  62                     if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2)  continue;
  63                     if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
  64                         continue;
  65                     testAsCollector(argType, pos, nargs);
  66                 }
  67             }
  68         }
  69     }
  70 
  71     public void testAsCollector(Class<?> argType, int pos, int nargs) throws Throwable {
  72         countTest();
  73         // fake up a MH with the same type as the desired adapter:
  74         MethodHandle fake = varargsArray(nargs);
  75         fake = changeArgTypes(fake, argType);
  76         MethodType newType = fake.type();
  77         Object[] args = randomArgs(newType.parameterArray());
  78         // here is what should happen:
  79         Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1);
  80         collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length);
  81         // here is the MH which will witness the collected argument tail:
  82         MethodHandle target = varargsArray(pos+1);
  83         target = changeArgTypes(target, 0, pos, argType);
  84         target = changeArgTypes(target, pos, pos+1, Object[].class);
  85         if (verbosity >= 3)
  86             System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
  87         MethodHandle result = target.asCollector(Object[].class, nargs-pos).asType(newType);
  88         Object[] returnValue = (Object[]) result.invokeWithArguments(args);
  89         assertArrayEquals(collectedArgs, returnValue);
  90     }
  91 
  92     public void testAsCollector1() throws Throwable {
  93         if (CAN_SKIP_WORKING)  return;
  94         startTest("asCollector/pos");
  95         for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
  96             if (verbosity >= 3)
  97                 System.out.println("asCollector/pos "+argType);
  98             for (int nargs = 0; nargs < 50; nargs++) {
  99                 if (CAN_TEST_LIGHTLY && nargs > 11)  break;
 100                 for (int pos = 0; pos <= nargs; pos++) {
 101                     if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2)  continue;
 102                     if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
 103                         continue;
 104                     for (int coll = 1; coll < nargs - pos; ++coll) {
 105                         if (coll > 4 && coll != 7 && coll != 11 && coll != 20 && coll < nargs - pos - 4) continue;
 106                         testAsCollector(argType, pos, coll, nargs);
 107                     }
 108                 }
 109             }
 110         }
 111     }
 112 
 113     public void testAsCollector(Class<?> argType, int pos, int collect, int nargs) throws Throwable {
 114         countTest();
 115         // fake up a MH with the same type as the desired adapter:
 116         MethodHandle fake = varargsArray(nargs);
 117         fake = changeArgTypes(fake, argType);
 118         MethodType newType = fake.type();
 119         Object[] args = randomArgs(newType.parameterArray());
 120         // here is what should happen:
 121         // new arg list has "collect" less arguments, but one extra for collected arguments array
 122         int collectedLength = nargs-(collect-1);
 123         Object[] collectedArgs = new Object[collectedLength];
 124         System.arraycopy(args, 0, collectedArgs, 0, pos);
 125         collectedArgs[pos] = Arrays.copyOfRange(args, pos, pos+collect);
 126         System.arraycopy(args, pos+collect, collectedArgs, pos+1, args.length-(pos+collect));
 127         // here is the MH which will witness the collected argument part (not tail!):
 128         MethodHandle target = varargsArray(collectedLength);
 129         target = changeArgTypes(target, 0, pos, argType);
 130         target = changeArgTypes(target, pos, pos+1, Object[].class);
 131         target = changeArgTypes(target, pos+1, collectedLength, argType);
 132         if (verbosity >= 3)
 133             System.out.println("collect "+collect+" from "+Arrays.asList(args)+" ["+pos+".."+(pos+collect)+"[");
 134         MethodHandle result = target.asCollector(pos, Object[].class, collect).asType(newType);
 135         Object[] returnValue = (Object[]) result.invokeWithArguments(args);
 136         assertArrayEquals(collectedArgs, returnValue);
 137     }
 138 }