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 MethodHandlesInvokersTest.java remote/RemoteExample.java 28 * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions 29 * -XX:-VerifyDependencies 30 * -esa 31 * test.java.lang.invoke.MethodHandlesInvokersTest 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.CallSite; 40 import java.lang.invoke.MethodHandle; 41 import java.lang.invoke.MethodHandles; 42 import java.lang.invoke.MethodType; 43 import java.lang.invoke.MutableCallSite; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.HashSet; 47 import java.util.List; 48 import java.util.Set; 49 50 import static org.junit.Assert.*; 51 52 public class MethodHandlesInvokersTest extends MethodHandlesTest { 53 54 @Test // SLOW 55 public void testInvokers() throws Throwable { 56 CodeCacheOverflowProcessor.runMHTest(this::testInvokers0); 57 } 58 59 public void testInvokers0() throws Throwable { 60 if (CAN_SKIP_WORKING) return; 61 startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker"); 62 // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker 63 Set<MethodType> done = new HashSet<>(); 64 for (int i = 0; i <= 6; i++) { 65 if (CAN_TEST_LIGHTLY && i > 3) break; 66 MethodType gtype = MethodType.genericMethodType(i); 67 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) { 68 for (int j = -1; j < i; j++) { 69 MethodType type = gtype; 70 if (j < 0) 71 type = type.changeReturnType(argType); 72 else if (argType == void.class) 73 continue; 74 else 75 type = type.changeParameterType(j, argType); 76 if (done.add(type)) 77 testInvokersWithCatch(type); 78 MethodType vtype = type.changeReturnType(void.class); 79 if (done.add(vtype)) 80 testInvokersWithCatch(vtype); 81 } 82 } 83 } 84 } 85 86 public void testInvokersWithCatch(MethodType type) throws Throwable { 87 try { 88 testInvokers(type); 89 } catch (Throwable ex) { 90 System.out.println("*** testInvokers on "+type+" => "); 91 ex.printStackTrace(System.out); 92 } 93 } 94 95 public void testInvokers(MethodType type) throws Throwable { 96 if (verbosity >= 3) 97 System.out.println("test invokers for "+type); 98 int nargs = type.parameterCount(); 99 boolean testRetCode = type.returnType() != void.class; 100 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee", 101 MethodType.genericMethodType(0, true)); 102 assertTrue(target.isVarargsCollector()); 103 target = target.asType(type); 104 Object[] args = randomArgs(type.parameterArray()); 105 List<Object> targetPlusArgs = new ArrayList<>(Arrays.asList(args)); 106 targetPlusArgs.add(0, target); 107 int code = (Integer) invokee(args); 108 Object log = logEntry("invokee", args); 109 assertEquals(log.hashCode(), code); 110 assertCalled("invokee", args); 111 MethodHandle inv; 112 Object result; 113 // exact invoker 114 countTest(); 115 calledLog.clear(); 116 inv = MethodHandles.exactInvoker(type); 117 result = inv.invokeWithArguments(targetPlusArgs); 118 if (testRetCode) assertEquals(code, result); 119 assertCalled("invokee", args); 120 // generic invoker 121 countTest(); 122 inv = MethodHandles.invoker(type); 123 if (nargs <= 3 && type == type.generic()) { 124 calledLog.clear(); 125 switch (nargs) { 126 case 0: 127 result = inv.invokeExact(target); 128 break; 129 case 1: 130 result = inv.invokeExact(target, args[0]); 131 break; 132 case 2: 133 result = inv.invokeExact(target, args[0], args[1]); 134 break; 135 case 3: 136 result = inv.invokeExact(target, args[0], args[1], args[2]); 137 break; 138 } 139 if (testRetCode) assertEquals(code, result); 140 assertCalled("invokee", args); 141 } 142 calledLog.clear(); 143 result = inv.invokeWithArguments(targetPlusArgs); 144 if (testRetCode) assertEquals(code, result); 145 assertCalled("invokee", args); 146 // varargs invoker #0 147 calledLog.clear(); 148 inv = MethodHandles.spreadInvoker(type, 0); 149 if (type.returnType() == Object.class) { 150 result = inv.invokeExact(target, args); 151 } else if (type.returnType() == void.class) { 152 result = null; inv.invokeExact(target, args); 153 } else { 154 result = inv.invokeWithArguments(target, (Object) args); 155 } 156 if (testRetCode) assertEquals(code, result); 157 assertCalled("invokee", args); 158 if (nargs >= 1 && type == type.generic()) { 159 // varargs invoker #1 160 calledLog.clear(); 161 inv = MethodHandles.spreadInvoker(type, 1); 162 result = inv.invokeExact(target, args[0], Arrays.copyOfRange(args, 1, nargs)); 163 if (testRetCode) assertEquals(code, result); 164 assertCalled("invokee", args); 165 } 166 if (nargs >= 2 && type == type.generic()) { 167 // varargs invoker #2 168 calledLog.clear(); 169 inv = MethodHandles.spreadInvoker(type, 2); 170 result = inv.invokeExact(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs)); 171 if (testRetCode) assertEquals(code, result); 172 assertCalled("invokee", args); 173 } 174 if (nargs >= 3 && type == type.generic()) { 175 // varargs invoker #3 176 calledLog.clear(); 177 inv = MethodHandles.spreadInvoker(type, 3); 178 result = inv.invokeExact(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs)); 179 if (testRetCode) assertEquals(code, result); 180 assertCalled("invokee", args); 181 } 182 for (int k = 0; k <= nargs; k++) { 183 // varargs invoker #0..N 184 if (CAN_TEST_LIGHTLY && (k > 1 || k < nargs - 1)) continue; 185 countTest(); 186 calledLog.clear(); 187 inv = MethodHandles.spreadInvoker(type, k); 188 MethodType expType = (type.dropParameterTypes(k, nargs) 189 .appendParameterTypes(Object[].class) 190 .insertParameterTypes(0, MethodHandle.class)); 191 assertEquals(expType, inv.type()); 192 List<Object> targetPlusVarArgs = new ArrayList<>(targetPlusArgs); 193 List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs); 194 Object[] tail = tailList.toArray(); 195 tailList.clear(); tailList.add(tail); 196 result = inv.invokeWithArguments(targetPlusVarArgs); 197 if (testRetCode) assertEquals(code, result); 198 assertCalled("invokee", args); 199 } 200 201 // dynamic invoker 202 countTest(); 203 CallSite site = new MutableCallSite(type); 204 inv = site.dynamicInvoker(); 205 206 // see if we get the result of the original target: 207 try { 208 result = inv.invokeWithArguments(args); 209 assertTrue("should not reach here", false); 210 } catch (IllegalStateException ex) { 211 String msg = ex.getMessage(); 212 assertTrue(msg, msg.contains("site")); 213 } 214 215 // set new target after invoker is created, to make sure we track target 216 site.setTarget(target); 217 calledLog.clear(); 218 result = inv.invokeWithArguments(args); 219 if (testRetCode) assertEquals(code, result); 220 assertCalled("invokee", args); 221 } 222 }