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 MethodHandlesSpreadArgumentsTest.java remote/RemoteExample.java 28 * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions 29 * -XX:-VerifyDependencies 30 * -esa 31 * test.java.lang.invoke.MethodHandlesSpreadArgumentsTest 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.ArrayList; 42 import java.util.Arrays; 43 import java.util.List; 44 45 import static org.junit.Assert.*; 46 47 public class MethodHandlesSpreadArgumentsTest extends MethodHandlesTest { 48 49 @Test // SLOW 50 public void testSpreadArguments() throws Throwable { 51 CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments0); 52 CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments1); 53 } 54 55 public void testSpreadArguments0() throws Throwable { 56 if (CAN_SKIP_WORKING) return; 57 startTest("spreadArguments"); 58 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) { 59 if (verbosity >= 3) 60 System.out.println("spreadArguments "+argType); 61 Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass(); 62 for (int nargs = 0; nargs < 50; nargs++) { 63 if (CAN_TEST_LIGHTLY && nargs > 11) break; 64 for (int pos = 0; pos <= nargs; pos++) { 65 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue; 66 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3) 67 continue; 68 testSpreadArguments(argType, arrayType, pos, nargs); 69 } 70 } 71 } 72 } 73 74 public void testSpreadArguments(Class<?> argType, Class<?> arrayType, int pos, int nargs) throws Throwable { 75 countTest(); 76 MethodHandle target2 = varargsArray(arrayType, nargs); 77 MethodHandle target = target2.asType(target2.type().generic()); 78 if (verbosity >= 3) 79 System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]"); 80 Object[] args = randomArgs(target2.type().parameterArray()); 81 // make sure the target does what we think it does: 82 checkTarget(argType, pos, nargs, target, args); 83 List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList()); 84 { // modify newParams in place 85 List<Class<?>> spreadParams = newParams.subList(pos, nargs); 86 spreadParams.clear(); spreadParams.add(arrayType); 87 } 88 MethodType newType = MethodType.methodType(arrayType, newParams); 89 MethodHandle result = target2.asSpreader(arrayType, nargs-pos); 90 assert(result.type() == newType) : Arrays.asList(result, newType); 91 result = result.asType(newType.generic()); 92 Object returnValue; 93 if (pos == 0) { 94 Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length)); 95 returnValue = result.invokeExact(args2); 96 } else { 97 Object[] args1 = Arrays.copyOfRange(args, 0, pos+1); 98 args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length)); 99 returnValue = result.invokeWithArguments(args1); 100 } 101 checkReturnValue(argType, args, result, returnValue); 102 } 103 104 public void testSpreadArguments1() throws Throwable { 105 if (CAN_SKIP_WORKING) return; 106 startTest("spreadArguments/pos"); 107 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) { 108 if (verbosity >= 3) 109 System.out.println("spreadArguments "+argType); 110 Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass(); 111 for (int nargs = 0; nargs < 50; nargs++) { 112 if (CAN_TEST_LIGHTLY && nargs > 11) break; 113 for (int pos = 0; pos <= nargs; pos++) { 114 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue; 115 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3) 116 continue; 117 for (int spr = 1; spr < nargs - pos; ++spr) { 118 if (spr > 4 && spr != 7 && spr != 11 && spr != 20 && spr < nargs - pos - 4) continue; 119 testSpreadArguments(argType, arrayType, pos, spr, nargs); 120 } 121 } 122 } 123 } 124 } 125 126 public void testSpreadArguments(Class<?> argType, Class<?> arrayType, 127 int pos, int spread, int nargs) throws Throwable { 128 countTest(); 129 MethodHandle target2 = varargsArray(arrayType, nargs); 130 MethodHandle target = target2.asType(target2.type().generic()); 131 if (verbosity >= 3) 132 System.out.println("spread into " + target2 + " [" + pos + ".." + (pos + spread) + "["); 133 Object[] args = randomArgs(target2.type().parameterArray()); 134 // make sure the target does what we think it does: 135 checkTarget(argType, pos, nargs, target, args); 136 List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList()); 137 { // modify newParams in place 138 List<Class<?>> spreadParams = newParams.subList(pos, pos + spread); 139 spreadParams.clear(); 140 spreadParams.add(arrayType); 141 } 142 MethodType newType = MethodType.methodType(arrayType, newParams); 143 MethodHandle result = target2.asSpreader(pos, arrayType, spread); 144 assert (result.type() == newType) : Arrays.asList(result, newType); 145 result = result.asType(newType.generic()); 146 // args1 has nargs-spread entries, plus one for the to-be-spread array 147 int args1Length = nargs - (spread - 1); 148 Object[] args1 = new Object[args1Length]; 149 System.arraycopy(args, 0, args1, 0, pos); 150 args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, pos + spread)); 151 System.arraycopy(args, pos + spread, args1, pos + 1, nargs - spread - pos); 152 Object returnValue = result.invokeWithArguments(args1); 153 checkReturnValue(argType, args, result, returnValue); 154 } 155 156 private static void checkTarget(Class<?> argType, int pos, int nargs, 157 MethodHandle target, Object[] args) throws Throwable { 158 if (pos == 0 && nargs < 5 && !argType.isPrimitive()) { 159 Object[] check = (Object[]) target.invokeWithArguments(args); 160 assertArrayEquals(args, check); 161 switch (nargs) { 162 case 0: 163 check = (Object[]) (Object) target.invokeExact(); 164 assertArrayEquals(args, check); 165 break; 166 case 1: 167 check = (Object[]) (Object) target.invokeExact(args[0]); 168 assertArrayEquals(args, check); 169 break; 170 case 2: 171 check = (Object[]) (Object) target.invokeExact(args[0], args[1]); 172 assertArrayEquals(args, check); 173 break; 174 } 175 } 176 } 177 178 private static void checkReturnValue(Class<?> argType, Object[] args, MethodHandle result, Object returnValue) { 179 String argstr = Arrays.toString(args); 180 if (!argType.isPrimitive()) { 181 Object[] rv = (Object[]) returnValue; 182 String rvs = Arrays.toString(rv); 183 if (!Arrays.equals(args, rv)) { 184 System.out.println("method: "+result); 185 System.out.println("expected: "+argstr); 186 System.out.println("returned: "+rvs); 187 assertArrayEquals(args, rv); 188 } 189 } else if (argType == int.class) { 190 String rvs = Arrays.toString((int[]) returnValue); 191 if (!argstr.equals(rvs)) { 192 System.out.println("method: "+result); 193 System.out.println("expected: "+argstr); 194 System.out.println("returned: "+rvs); 195 assertEquals(argstr, rvs); 196 } 197 } else if (argType == long.class) { 198 String rvs = Arrays.toString((long[]) returnValue); 199 if (!argstr.equals(rvs)) { 200 System.out.println("method: "+result); 201 System.out.println("expected: "+argstr); 202 System.out.println("returned: "+rvs); 203 assertEquals(argstr, rvs); 204 } 205 } else { 206 // cannot test... 207 } 208 } 209 210 }