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 MethodHandlesPermuteArgumentsTest.java remote/RemoteExample.java
  28  * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions
  29  *                                 -XX:-VerifyDependencies
  30  *                                 -esa
  31  *                                 test.java.lang.invoke.MethodHandlesPermuteArgumentsTest
  32  */
  33 
  34 
  35 package test.java.lang.invoke;
  36 
  37 import org.junit.*;
  38 import test.java.lang.invoke.lib.CodeCacheOverflowProcessor;
  39 
  40 import java.lang.invoke.MethodHandle;
  41 import java.lang.invoke.MethodHandles;
  42 import java.lang.invoke.MethodType;
  43 import java.util.Arrays;
  44 
  45 import static org.junit.Assert.*;
  46 
  47 public class MethodHandlesPermuteArgumentsTest extends MethodHandlesTest {
  48 
  49     @Test // SLOW
  50     public void testPermuteArguments() throws Throwable {
  51         CodeCacheOverflowProcessor.runMHTest(this::testPermuteArguments0);
  52     }
  53 
  54     public void testPermuteArguments0() throws Throwable {
  55         if (CAN_SKIP_WORKING)  return;
  56         startTest("permuteArguments");
  57         testPermuteArguments(4, Integer.class, 2, long.class, 6);
  58         if (CAN_TEST_LIGHTLY)  return;
  59         testPermuteArguments(4, Integer.class, 2, String.class, 0);
  60         testPermuteArguments(6, Integer.class, 0, null, 30);
  61     }
  62 
  63     public void testPermuteArguments(int max, Class<?> type1, int t2c, Class<?> type2, int dilution) throws Throwable {
  64         if (verbosity >= 2)
  65             System.out.println("permuteArguments "+max+"*"+type1.getName()
  66                     +(t2c==0?"":"/"+t2c+"*"+type2.getName())
  67                     +(dilution > 0 ? " with dilution "+dilution : ""));
  68         int t2pos = t2c == 0 ? 0 : 1;
  69         for (int inargs = t2pos+1; inargs <= max; inargs++) {
  70             Class<?>[] types = new Class<?>[inargs];
  71             Arrays.fill(types, type1);
  72             if (t2c != 0) {
  73                 // Fill in a middle range with type2:
  74                 Arrays.fill(types, t2pos, Math.min(t2pos+t2c, inargs), type2);
  75             }
  76             Object[] args = randomArgs(types);
  77             int numcases = 1;
  78             for (int outargs = 0; outargs <= max; outargs++) {
  79                 if (outargs - inargs >= MAX_ARG_INCREASE)  continue;
  80                 int casStep = dilution + 1;
  81                 // Avoid some common factors:
  82                 while ((casStep > 2 && casStep % 2 == 0 && inargs % 2 == 0) ||
  83                        (casStep > 3 && casStep % 3 == 0 && inargs % 3 == 0))
  84                     casStep++;
  85                 testPermuteArguments(args, types, outargs, numcases, casStep);
  86                 numcases *= inargs;
  87                 if (CAN_TEST_LIGHTLY && outargs < max-2)  continue;
  88                 if (dilution > 10 && outargs >= 4) {
  89                     if (CAN_TEST_LIGHTLY)  continue;
  90                     int[] reorder = new int[outargs];
  91                     // Do some special patterns, which we probably missed.
  92                     // Replication of a single argument or argument pair.
  93                     for (int i = 0; i < inargs; i++) {
  94                         Arrays.fill(reorder, i);
  95                         testPermuteArguments(args, types, reorder);
  96                         for (int d = 1; d <= 2; d++) {
  97                             if (i + d >= inargs)  continue;
  98                             for (int j = 1; j < outargs; j += 2)
  99                                 reorder[j] += 1;
 100                             testPermuteArguments(args, types, reorder);
 101                             testPermuteArguments(args, types, reverse(reorder));
 102                         }
 103                     }
 104                     // Repetition of a sequence of 3 or more arguments.
 105                     for (int i = 1; i < inargs; i++) {
 106                         for (int len = 3; len <= inargs; len++) {
 107                             for (int j = 0; j < outargs; j++)
 108                                 reorder[j] = (i + (j % len)) % inargs;
 109                             testPermuteArguments(args, types, reorder);
 110                             testPermuteArguments(args, types, reverse(reorder));
 111                         }
 112                     }
 113                 }
 114             }
 115         }
 116     }
 117 
 118     public void testPermuteArguments(Object[] args, Class<?>[] types,
 119                                      int outargs, int numcases, int casStep) throws Throwable {
 120         int inargs = args.length;
 121         int[] reorder = new int[outargs];
 122         for (int cas = 0; cas < numcases; cas += casStep) {
 123             for (int i = 0, c = cas; i < outargs; i++) {
 124                 reorder[i] = c % inargs;
 125                 c /= inargs;
 126             }
 127             if (CAN_TEST_LIGHTLY && outargs >= 3 &&
 128                (reorder[0] == reorder[1] || reorder[1] == reorder[2]))
 129                    continue;
 130             testPermuteArguments(args, types, reorder);
 131         }
 132     }
 133 
 134     static int[] reverse(int[] reorder) {
 135         reorder = reorder.clone();
 136         for (int i = 0, imax = reorder.length / 2; i < imax; i++) {
 137             int j = reorder.length - 1 - i;
 138             int tem = reorder[i];
 139             reorder[i] = reorder[j];
 140             reorder[j] = tem;
 141         }
 142         return reorder;
 143     }
 144 
 145     void testPermuteArguments(Object[] args, Class<?>[] types, int[] reorder) throws Throwable {
 146         countTest();
 147         if (args == null && types == null) {
 148             int max = 0;
 149             for (int j : reorder) {
 150                 if (max < j)  max = j;
 151             }
 152             args = randomArgs(max+1, Integer.class);
 153         }
 154         if (args == null) {
 155             args = randomArgs(types);
 156         }
 157         if (types == null) {
 158             types = new Class<?>[args.length];
 159             for (int i = 0; i < args.length; i++)
 160                 types[i] = args[i].getClass();
 161         }
 162         int inargs = args.length, outargs = reorder.length;
 163         assertTrue(inargs == types.length);
 164         if (verbosity >= 3)
 165             System.out.println("permuteArguments "+Arrays.toString(reorder));
 166         Object[] permArgs = new Object[outargs];
 167         Class<?>[] permTypes = new Class<?>[outargs];
 168         for (int i = 0; i < outargs; i++) {
 169             permArgs[i] = args[reorder[i]];
 170             permTypes[i] = types[reorder[i]];
 171         }
 172         if (verbosity >= 4) {
 173             System.out.println("in args:   "+Arrays.asList(args));
 174             System.out.println("out args:  "+Arrays.asList(permArgs));
 175             System.out.println("in types:  "+Arrays.asList(types));
 176             System.out.println("out types: "+Arrays.asList(permTypes));
 177         }
 178         MethodType inType  = MethodType.methodType(Object.class, types);
 179         MethodType outType = MethodType.methodType(Object.class, permTypes);
 180         MethodHandle target = varargsList(outargs).asType(outType);
 181         MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
 182         if (verbosity >= 5)  System.out.println("newTarget = "+newTarget);
 183         Object result = newTarget.invokeWithArguments(args);
 184         Object expected = Arrays.asList(permArgs);
 185         if (!expected.equals(result)) {
 186             System.out.println("*** failed permuteArguments "+Arrays.toString(reorder)+
 187                                " types="+Arrays.asList(types));
 188             System.out.println("in args:   "+Arrays.asList(args));
 189             System.out.println("out args:  "+expected);
 190             System.out.println("bad args:  "+result);
 191         }
 192         assertEquals(expected, result);
 193     }
 194 }