| /* | |
| * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| /* @test | |
| * @summary unit tests for java.lang.invoke.MethodHandles | |
| * @library /test/lib /java/lang/invoke/common | |
| * @compile MethodHandlesTest.java MethodHandlesSpreadArgumentsTest.java remote/RemoteExample.java | |
| * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions | |
| * -XX:-VerifyDependencies | |
| * -esa | |
| * test.java.lang.invoke.MethodHandlesSpreadArgumentsTest | |
| */ | |
| package test.java.lang.invoke; | |
| import org.junit.*; | |
| import test.java.lang.invoke.lib.CodeCacheOverflowProcessor; | |
| import java.lang.invoke.MethodHandle; | |
| import java.lang.invoke.MethodType; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.List; | |
| import static org.junit.Assert.*; | |
| public class MethodHandlesSpreadArgumentsTest extends MethodHandlesTest { | |
| @Test // SLOW | |
| public void testSpreadArguments() throws Throwable { | |
| CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments0); | |
| CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments1); | |
| } | |
| public void testSpreadArguments0() throws Throwable { | |
| if (CAN_SKIP_WORKING) return; | |
| startTest("spreadArguments"); | |
| for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) { | |
| if (verbosity >= 3) | |
| System.out.println("spreadArguments "+argType); | |
| Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass(); | |
| for (int nargs = 0; nargs < 50; nargs++) { | |
| if (CAN_TEST_LIGHTLY && nargs > 11) break; | |
| for (int pos = 0; pos <= nargs; pos++) { | |
| if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue; | |
| if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3) | |
| continue; | |
| testSpreadArguments(argType, arrayType, pos, nargs); | |
| } | |
| } | |
| } | |
| } | |
| public void testSpreadArguments(Class<?> argType, Class<?> arrayType, int pos, int nargs) throws Throwable { | |
| countTest(); | |
| MethodHandle target2 = varargsArray(arrayType, nargs); | |
| MethodHandle target = target2.asType(target2.type().generic()); | |
| if (verbosity >= 3) | |
| System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]"); | |
| Object[] args = randomArgs(target2.type().parameterArray()); | |
| // make sure the target does what we think it does: | |
| checkTarget(argType, pos, nargs, target, args); | |
| List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList()); | |
| { // modify newParams in place | |
| List<Class<?>> spreadParams = newParams.subList(pos, nargs); | |
| spreadParams.clear(); spreadParams.add(arrayType); | |
| } | |
| MethodType newType = MethodType.methodType(arrayType, newParams); | |
| MethodHandle result = target2.asSpreader(arrayType, nargs-pos); | |
| assert(result.type() == newType) : Arrays.asList(result, newType); | |
| result = result.asType(newType.generic()); | |
| Object returnValue; | |
| if (pos == 0) { | |
| Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length)); | |
| returnValue = result.invokeExact(args2); | |
| } else { | |
| Object[] args1 = Arrays.copyOfRange(args, 0, pos+1); | |
| args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length)); | |
| returnValue = result.invokeWithArguments(args1); | |
| } | |
| checkReturnValue(argType, args, result, returnValue); | |
| } | |
| public void testSpreadArguments1() throws Throwable { | |
| if (CAN_SKIP_WORKING) return; | |
| startTest("spreadArguments/pos"); | |
| for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) { | |
| if (verbosity >= 3) | |
| System.out.println("spreadArguments "+argType); | |
| Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass(); | |
| for (int nargs = 0; nargs < 50; nargs++) { | |
| if (CAN_TEST_LIGHTLY && nargs > 11) break; | |
| for (int pos = 0; pos <= nargs; pos++) { | |
| if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue; | |
| if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3) | |
| continue; | |
| for (int spr = 1; spr < nargs - pos; ++spr) { | |
| if (spr > 4 && spr != 7 && spr != 11 && spr != 20 && spr < nargs - pos - 4) continue; | |
| testSpreadArguments(argType, arrayType, pos, spr, nargs); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| public void testSpreadArguments(Class<?> argType, Class<?> arrayType, | |
| int pos, int spread, int nargs) throws Throwable { | |
| countTest(); | |
| MethodHandle target2 = varargsArray(arrayType, nargs); | |
| MethodHandle target = target2.asType(target2.type().generic()); | |
| if (verbosity >= 3) | |
| System.out.println("spread into " + target2 + " [" + pos + ".." + (pos + spread) + "["); | |
| Object[] args = randomArgs(target2.type().parameterArray()); | |
| // make sure the target does what we think it does: | |
| checkTarget(argType, pos, nargs, target, args); | |
| List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList()); | |
| { // modify newParams in place | |
| List<Class<?>> spreadParams = newParams.subList(pos, pos + spread); | |
| spreadParams.clear(); | |
| spreadParams.add(arrayType); | |
| } | |
| MethodType newType = MethodType.methodType(arrayType, newParams); | |
| MethodHandle result = target2.asSpreader(pos, arrayType, spread); | |
| assert (result.type() == newType) : Arrays.asList(result, newType); | |
| result = result.asType(newType.generic()); | |
| // args1 has nargs-spread entries, plus one for the to-be-spread array | |
| int args1Length = nargs - (spread - 1); | |
| Object[] args1 = new Object[args1Length]; | |
| System.arraycopy(args, 0, args1, 0, pos); | |
| args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, pos + spread)); | |
| System.arraycopy(args, pos + spread, args1, pos + 1, nargs - spread - pos); | |
| Object returnValue = result.invokeWithArguments(args1); | |
| checkReturnValue(argType, args, result, returnValue); | |
| } | |
| private static void checkTarget(Class<?> argType, int pos, int nargs, | |
| MethodHandle target, Object[] args) throws Throwable { | |
| if (pos == 0 && nargs < 5 && !argType.isPrimitive()) { | |
| Object[] check = (Object[]) target.invokeWithArguments(args); | |
| assertArrayEquals(args, check); | |
| switch (nargs) { | |
| case 0: | |
| check = (Object[]) (Object) target.invokeExact(); | |
| assertArrayEquals(args, check); | |
| break; | |
| case 1: | |
| check = (Object[]) (Object) target.invokeExact(args[0]); | |
| assertArrayEquals(args, check); | |
| break; | |
| case 2: | |
| check = (Object[]) (Object) target.invokeExact(args[0], args[1]); | |
| assertArrayEquals(args, check); | |
| break; | |
| } | |
| } | |
| } | |
| private static void checkReturnValue(Class<?> argType, Object[] args, MethodHandle result, Object returnValue) { | |
| String argstr = Arrays.toString(args); | |
| if (!argType.isPrimitive()) { | |
| Object[] rv = (Object[]) returnValue; | |
| String rvs = Arrays.toString(rv); | |
| if (!Arrays.equals(args, rv)) { | |
| System.out.println("method: "+result); | |
| System.out.println("expected: "+argstr); | |
| System.out.println("returned: "+rvs); | |
| assertArrayEquals(args, rv); | |
| } | |
| } else if (argType == int.class) { | |
| String rvs = Arrays.toString((int[]) returnValue); | |
| if (!argstr.equals(rvs)) { | |
| System.out.println("method: "+result); | |
| System.out.println("expected: "+argstr); | |
| System.out.println("returned: "+rvs); | |
| assertEquals(argstr, rvs); | |
| } | |
| } else if (argType == long.class) { | |
| String rvs = Arrays.toString((long[]) returnValue); | |
| if (!argstr.equals(rvs)) { | |
| System.out.println("method: "+result); | |
| System.out.println("expected: "+argstr); | |
| System.out.println("returned: "+rvs); | |
| assertEquals(argstr, rvs); | |
| } | |
| } else { | |
| // cannot test... | |
| } | |
| } | |
| } |