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 /test/lib /java/lang/invoke/common 27 * @compile MethodHandlesTest.java MethodHandlesGeneralTest.java remote/RemoteExample.java 28 * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions 29 * -XX:-VerifyDependencies 30 * -esa 31 * test.java.lang.invoke.MethodHandlesGeneralTest 32 */ 33 34 package test.java.lang.invoke; 35 36 import org.junit.*; 37 import test.java.lang.invoke.lib.CodeCacheOverflowProcessor; 38 import test.java.lang.invoke.remote.RemoteExample; 39 40 import java.lang.invoke.MethodHandle; 41 import java.lang.invoke.MethodHandleProxies; 42 import java.lang.invoke.MethodHandles; 43 import java.lang.invoke.MethodType; 44 import java.lang.invoke.WrongMethodTypeException; 45 import java.lang.invoke.MethodHandles.Lookup; 46 import java.lang.reflect.Array; 47 import java.lang.reflect.Field; 48 import java.lang.reflect.Method; 49 import java.lang.reflect.Modifier; 50 import java.lang.reflect.UndeclaredThrowableException; 51 import java.util.ArrayList; 52 import java.util.Arrays; 53 import java.util.Collections; 54 import java.util.Formatter; 55 import java.util.HashMap; 56 import java.util.List; 57 import java.util.Map; 58 59 import static java.lang.invoke.MethodType.methodType; 60 import static org.junit.Assert.*; 61 62 public class MethodHandlesGeneralTest extends MethodHandlesTest { 63 64 @Test 65 public void testFirst() throws Throwable { 66 verbosity += 9; 67 try { 68 // left blank for debugging 69 } finally { printCounts(); verbosity -= 9; } 70 } 71 72 @Test 73 public void testFindStatic() throws Throwable { 74 CodeCacheOverflowProcessor.runMHTest(this::testFindStatic0); 75 } 76 77 public void testFindStatic0() throws Throwable { 78 if (CAN_SKIP_WORKING) return; 79 startTest("findStatic"); 80 testFindStatic(PubExample.class, void.class, "s0"); 81 testFindStatic(Example.class, void.class, "s0"); 82 testFindStatic(Example.class, void.class, "pkg_s0"); 83 testFindStatic(Example.class, void.class, "pri_s0"); 84 testFindStatic(Example.class, void.class, "pro_s0"); 85 testFindStatic(PubExample.class, void.class, "Pub/pro_s0"); 86 87 testFindStatic(Example.class, Object.class, "s1", Object.class); 88 testFindStatic(Example.class, Object.class, "s2", int.class); 89 testFindStatic(Example.class, Object.class, "s3", long.class); 90 testFindStatic(Example.class, Object.class, "s4", int.class, int.class); 91 testFindStatic(Example.class, Object.class, "s5", long.class, int.class); 92 testFindStatic(Example.class, Object.class, "s6", int.class, long.class); 93 testFindStatic(Example.class, Object.class, "s7", float.class, double.class); 94 95 testFindStatic(false, PRIVATE, Example.class, void.class, "bogus"); 96 testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", int.class); 97 testFindStatic(false, PRIVATE, Example.class, void.class, "<init>", Void.class); 98 testFindStatic(false, PRIVATE, Example.class, void.class, "v0"); 99 } 100 101 void testFindStatic(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 102 for (Object[] ac : accessCases(defc, name)) { 103 testFindStatic((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); 104 } 105 } 106 107 void testFindStatic(Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 108 testFindStatic(true, lookup, defc, ret, name, params); 109 } 110 111 void testFindStatic(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 112 countTest(positive); 113 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 114 MethodType type = MethodType.methodType(ret, params); 115 MethodHandle target = null; 116 Exception noAccess = null; 117 try { 118 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 119 target = maybeMoveIn(lookup, defc).findStatic(defc, methodName, type); 120 } catch (ReflectiveOperationException ex) { 121 noAccess = ex; 122 assertExceptionClass( 123 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 124 ? NoSuchMethodException.class 125 : IllegalAccessException.class, 126 noAccess); 127 if (verbosity >= 5) ex.printStackTrace(System.out); 128 } 129 if (verbosity >= 3) 130 System.out.println("findStatic "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target 131 +(noAccess == null ? "" : " !! "+noAccess)); 132 if (positive && noAccess != null) throw noAccess; 133 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 134 if (!positive) return; // negative test failed as expected 135 assertEquals(type, target.type()); 136 assertNameStringContains(target, methodName); 137 Object[] args = randomArgs(params); 138 printCalled(target, name, args); 139 target.invokeWithArguments(args); 140 assertCalled(name, args); 141 if (verbosity >= 1) 142 System.out.print(':'); 143 } 144 145 @Test 146 public void testFindVirtual() throws Throwable { 147 CodeCacheOverflowProcessor.runMHTest(this::testFindVirtual0); 148 } 149 150 public void testFindVirtual0() throws Throwable { 151 if (CAN_SKIP_WORKING) return; 152 startTest("findVirtual"); 153 testFindVirtual(Example.class, void.class, "v0"); 154 testFindVirtual(Example.class, void.class, "pkg_v0"); 155 testFindVirtual(Example.class, void.class, "pri_v0"); 156 testFindVirtual(Example.class, Object.class, "v1", Object.class); 157 testFindVirtual(Example.class, Object.class, "v2", Object.class, Object.class); 158 testFindVirtual(Example.class, Object.class, "v2", Object.class, int.class); 159 testFindVirtual(Example.class, Object.class, "v2", int.class, Object.class); 160 testFindVirtual(Example.class, Object.class, "v2", int.class, int.class); 161 testFindVirtual(Example.class, void.class, "pro_v0"); 162 testFindVirtual(PubExample.class, void.class, "Pub/pro_v0"); 163 164 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "bogus"); 165 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", int.class); 166 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "<init>", Void.class); 167 testFindVirtual(false, PRIVATE, Example.class, Example.class, void.class, "s0"); 168 169 // test dispatch 170 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/v0"); 171 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/v0"); 172 testFindVirtual(SubExample.class, IntExample.class, void.class, "Sub/v0"); 173 testFindVirtual(SubExample.class, SubExample.class, void.class, "Sub/pkg_v0"); 174 testFindVirtual(SubExample.class, Example.class, void.class, "Sub/pkg_v0"); 175 testFindVirtual(Example.class, IntExample.class, void.class, "v0"); 176 testFindVirtual(IntExample.Impl.class, IntExample.class, void.class, "Int/v0"); 177 } 178 179 @Test 180 public void testFindVirtualClone() throws Throwable { 181 CodeCacheOverflowProcessor.runMHTest(this::testFindVirtualClone0); 182 } 183 184 public void testFindVirtualClone0() throws Throwable { 185 if (CAN_SKIP_WORKING) return; 186 // test some ad hoc system methods 187 testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone"); 188 189 // ##### FIXME - disable tests for clone until we figure out how they should work with modules 190 191 /* 192 testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone"); 193 testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone"); 194 for (Class<?> cls : new Class<?>[]{ boolean[].class, long[].class, float[].class, char[].class }) 195 testFindVirtual(true, PUBLIC, cls, Object.class, "clone"); 196 */ 197 } 198 199 void testFindVirtual(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 200 Class<?> rcvc = defc; 201 testFindVirtual(rcvc, defc, ret, name, params); 202 } 203 204 void testFindVirtual(Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 205 for (Object[] ac : accessCases(defc, name)) { 206 testFindVirtual((Boolean)ac[0], (Lookup)ac[1], rcvc, defc, ret, name, params); 207 } 208 } 209 210 void testFindVirtual(Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 211 testFindVirtual(true, lookup, rcvc, defc, ret, name, params); 212 } 213 214 void testFindVirtual(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 215 testFindVirtual(positive, lookup, defc, defc, ret, name, params); 216 } 217 218 void testFindVirtual(boolean positive, Lookup lookup, Class<?> rcvc, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 219 countTest(positive); 220 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 221 MethodType type = MethodType.methodType(ret, params); 222 MethodHandle target = null; 223 Exception noAccess = null; 224 try { 225 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 226 target = maybeMoveIn(lookup, defc).findVirtual(defc, methodName, type); 227 } catch (ReflectiveOperationException ex) { 228 noAccess = ex; 229 assertExceptionClass( 230 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 231 ? NoSuchMethodException.class 232 : IllegalAccessException.class, 233 noAccess); 234 if (verbosity >= 5) ex.printStackTrace(System.out); 235 } 236 if (verbosity >= 3) 237 System.out.println("findVirtual "+lookup+": "+defc.getName()+"."+name+"/"+type+" => "+target 238 +(noAccess == null ? "" : " !! "+noAccess)); 239 if (positive && noAccess != null) throw noAccess; 240 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 241 if (!positive) return; // negative test failed as expected 242 Class<?> selfc = defc; 243 // predict receiver type narrowing: 244 if (lookup == SUBCLASS && 245 name.contains("pro_") && 246 selfc.isAssignableFrom(lookup.lookupClass())) { 247 selfc = lookup.lookupClass(); 248 if (name.startsWith("Pub/")) name = "Rem/"+name.substring(4); 249 } 250 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)selfc), params); 251 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); 252 assertEquals(typeWithSelf, target.type()); 253 assertNameStringContains(target, methodName); 254 Object[] argsWithSelf = randomArgs(paramsWithSelf); 255 if (selfc.isAssignableFrom(rcvc) && rcvc != selfc) argsWithSelf[0] = randomArg(rcvc); 256 printCalled(target, name, argsWithSelf); 257 Object res = target.invokeWithArguments(argsWithSelf); 258 if (Example.class.isAssignableFrom(defc) || IntExample.class.isAssignableFrom(defc)) { 259 assertCalled(name, argsWithSelf); 260 } else if (name.equals("clone")) { 261 // Ad hoc method call outside Example. For Object[].clone. 262 printCalled(target, name, argsWithSelf); 263 assertEquals(MethodType.methodType(Object.class, rcvc), target.type()); 264 Object orig = argsWithSelf[0]; 265 assertEquals(orig.getClass(), res.getClass()); 266 if (res instanceof Object[]) 267 assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]); 268 assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]})); 269 } else { 270 assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params)); 271 } 272 if (verbosity >= 1) 273 System.out.print(':'); 274 } 275 276 @Test 277 public void testFindSpecial() throws Throwable { 278 CodeCacheOverflowProcessor.runMHTest(this::testFindSpecial0); 279 } 280 281 public void testFindSpecial0() throws Throwable { 282 if (CAN_SKIP_WORKING) return; 283 startTest("findSpecial"); 284 testFindSpecial(SubExample.class, Example.class, void.class, false, "v0"); 285 testFindSpecial(SubExample.class, Example.class, void.class, false, "pkg_v0"); 286 testFindSpecial(RemoteExample.class, PubExample.class, void.class, false, "Pub/pro_v0"); 287 testFindSpecial(Example.class, IntExample.class, void.class, true, "vd"); 288 // Do some negative testing: 289 for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) { 290 testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0"); 291 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus"); 292 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class); 293 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class); 294 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0"); 295 testFindSpecial(false, lookup, Example.class, IntExample.class, void.class, "v0"); 296 } 297 } 298 299 void testFindSpecial(Class<?> specialCaller, 300 Class<?> defc, Class<?> ret, boolean dflt, String name, Class<?>... params) throws Throwable { 301 if (specialCaller == RemoteExample.class) { 302 testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params); 303 testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params); 304 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params); 305 testFindSpecial(true, SUBCLASS, specialCaller, defc, ret, name, params); 306 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params); 307 return; 308 } 309 testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params); 310 testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params); 311 testFindSpecial(false || dflt, PACKAGE, specialCaller, defc, ret, name, params); 312 testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params); 313 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params); 314 } 315 316 void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller, 317 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 318 countTest(positive); 319 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 320 MethodType type = MethodType.methodType(ret, params); 321 Lookup specialLookup = maybeMoveIn(lookup, specialCaller); 322 boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller && 323 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0); 324 MethodHandle target = null; 325 Exception noAccess = null; 326 try { 327 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 328 if (verbosity >= 5) System.out.println(" lookup => "+specialLookup); 329 target = specialLookup.findSpecial(defc, methodName, type, specialCaller); 330 } catch (ReflectiveOperationException ex) { 331 noAccess = ex; 332 assertExceptionClass( 333 (!specialAccessOK) // this check should happen first 334 ? IllegalAccessException.class 335 : (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 336 ? NoSuchMethodException.class 337 : IllegalAccessException.class, 338 noAccess); 339 if (verbosity >= 5) ex.printStackTrace(System.out); 340 } 341 if (verbosity >= 3) 342 System.out.println("findSpecial from "+specialCaller.getName()+" to "+defc.getName()+"."+name+"/"+type+" => "+target 343 +(target == null ? "" : target.type()) 344 +(noAccess == null ? "" : " !! "+noAccess)); 345 if (positive && noAccess != null) throw noAccess; 346 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 347 if (!positive) return; // negative test failed as expected 348 assertEquals(specialCaller, target.type().parameterType(0)); 349 assertEquals(type, target.type().dropParameterTypes(0,1)); 350 Class<?>[] paramsWithSelf = cat(array(Class[].class, (Class)specialCaller), params); 351 MethodType typeWithSelf = MethodType.methodType(ret, paramsWithSelf); 352 assertNameStringContains(target, methodName); 353 Object[] args = randomArgs(paramsWithSelf); 354 printCalled(target, name, args); 355 target.invokeWithArguments(args); 356 assertCalled(name, args); 357 } 358 359 @Test 360 public void testFindConstructor() throws Throwable { 361 CodeCacheOverflowProcessor.runMHTest(this::testFindConstructor0); 362 } 363 364 public void testFindConstructor0() throws Throwable { 365 if (CAN_SKIP_WORKING) return; 366 startTest("findConstructor"); 367 testFindConstructor(true, EXAMPLE, Example.class); 368 testFindConstructor(true, EXAMPLE, Example.class, int.class); 369 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class); 370 testFindConstructor(true, EXAMPLE, Example.class, int.class, long.class); 371 testFindConstructor(true, EXAMPLE, Example.class, int.class, float.class); 372 testFindConstructor(true, EXAMPLE, Example.class, int.class, double.class); 373 testFindConstructor(true, EXAMPLE, Example.class, String.class); 374 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class); 375 testFindConstructor(true, EXAMPLE, Example.class, int.class, int.class, int.class, int.class); 376 } 377 378 void testFindConstructor(boolean positive, Lookup lookup, 379 Class<?> defc, Class<?>... params) throws Throwable { 380 countTest(positive); 381 MethodType type = MethodType.methodType(void.class, params); 382 MethodHandle target = null; 383 Exception noAccess = null; 384 try { 385 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" <init>"+type); 386 target = lookup.findConstructor(defc, type); 387 } catch (ReflectiveOperationException ex) { 388 noAccess = ex; 389 assertTrue(noAccess.getClass().getName(), noAccess instanceof IllegalAccessException); 390 } 391 if (verbosity >= 3) 392 System.out.println("findConstructor "+defc.getName()+".<init>/"+type+" => "+target 393 +(target == null ? "" : target.type()) 394 +(noAccess == null ? "" : " !! "+noAccess)); 395 if (positive && noAccess != null) throw noAccess; 396 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 397 if (!positive) return; // negative test failed as expected 398 assertEquals(type.changeReturnType(defc), target.type()); 399 Object[] args = randomArgs(params); 400 printCalled(target, defc.getSimpleName(), args); 401 Object obj = target.invokeWithArguments(args); 402 if (!(defc == Example.class && params.length < 2)) 403 assertCalled(defc.getSimpleName()+".<init>", args); 404 assertTrue("instance of "+defc.getName(), defc.isInstance(obj)); 405 } 406 407 @Test 408 public void testBind() throws Throwable { 409 CodeCacheOverflowProcessor.runMHTest(this::testBind0); 410 } 411 412 public void testBind0() throws Throwable { 413 if (CAN_SKIP_WORKING) return; 414 startTest("bind"); 415 testBind(Example.class, void.class, "v0"); 416 testBind(Example.class, void.class, "pkg_v0"); 417 testBind(Example.class, void.class, "pri_v0"); 418 testBind(Example.class, Object.class, "v1", Object.class); 419 testBind(Example.class, Object.class, "v2", Object.class, Object.class); 420 testBind(Example.class, Object.class, "v2", Object.class, int.class); 421 testBind(Example.class, Object.class, "v2", int.class, Object.class); 422 testBind(Example.class, Object.class, "v2", int.class, int.class); 423 testBind(false, PRIVATE, Example.class, void.class, "bogus"); 424 testBind(false, PRIVATE, Example.class, void.class, "<init>", int.class); 425 testBind(false, PRIVATE, Example.class, void.class, "<init>", Void.class); 426 testBind(SubExample.class, void.class, "Sub/v0"); 427 testBind(SubExample.class, void.class, "Sub/pkg_v0"); 428 testBind(IntExample.Impl.class, void.class, "Int/v0"); 429 } 430 431 void testBind(Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 432 for (Object[] ac : accessCases(defc, name)) { 433 testBind((Boolean)ac[0], (Lookup)ac[1], defc, ret, name, params); 434 } 435 } 436 437 void testBind(boolean positive, Lookup lookup, Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable { 438 countTest(positive); 439 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 440 MethodType type = MethodType.methodType(ret, params); 441 Object receiver = randomArg(defc); 442 MethodHandle target = null; 443 Exception noAccess = null; 444 try { 445 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 446 target = maybeMoveIn(lookup, defc).bind(receiver, methodName, type); 447 } catch (ReflectiveOperationException ex) { 448 noAccess = ex; 449 assertExceptionClass( 450 (name.contains("bogus") || INIT_REF_CAUSES_NSME && name.contains("<init>")) 451 ? NoSuchMethodException.class 452 : IllegalAccessException.class, 453 noAccess); 454 if (verbosity >= 5) ex.printStackTrace(System.out); 455 } 456 if (verbosity >= 3) 457 System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target 458 +(noAccess == null ? "" : " !! "+noAccess)); 459 if (positive && noAccess != null) throw noAccess; 460 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 461 if (!positive) return; // negative test failed as expected 462 assertEquals(type, target.type()); 463 Object[] args = randomArgs(params); 464 printCalled(target, name, args); 465 target.invokeWithArguments(args); 466 Object[] argsWithReceiver = cat(array(Object[].class, receiver), args); 467 assertCalled(name, argsWithReceiver); 468 if (verbosity >= 1) 469 System.out.print(':'); 470 } 471 472 @Test 473 public void testUnreflect() throws Throwable { 474 CodeCacheOverflowProcessor.runMHTest(this::testUnreflect0); 475 } 476 477 public void testUnreflect0() throws Throwable { 478 if (CAN_SKIP_WORKING) return; 479 startTest("unreflect"); 480 testUnreflect(Example.class, true, void.class, "s0"); 481 testUnreflect(Example.class, true, void.class, "pro_s0"); 482 testUnreflect(Example.class, true, void.class, "pkg_s0"); 483 testUnreflect(Example.class, true, void.class, "pri_s0"); 484 485 testUnreflect(Example.class, true, Object.class, "s1", Object.class); 486 testUnreflect(Example.class, true, Object.class, "s2", int.class); 487 testUnreflect(Example.class, true, Object.class, "s3", long.class); 488 testUnreflect(Example.class, true, Object.class, "s4", int.class, int.class); 489 testUnreflect(Example.class, true, Object.class, "s5", long.class, int.class); 490 testUnreflect(Example.class, true, Object.class, "s6", int.class, long.class); 491 492 testUnreflect(Example.class, false, void.class, "v0"); 493 testUnreflect(Example.class, false, void.class, "pkg_v0"); 494 testUnreflect(Example.class, false, void.class, "pri_v0"); 495 testUnreflect(Example.class, false, Object.class, "v1", Object.class); 496 testUnreflect(Example.class, false, Object.class, "v2", Object.class, Object.class); 497 testUnreflect(Example.class, false, Object.class, "v2", Object.class, int.class); 498 testUnreflect(Example.class, false, Object.class, "v2", int.class, Object.class); 499 testUnreflect(Example.class, false, Object.class, "v2", int.class, int.class); 500 501 // Test a public final member in another package: 502 testUnreflect(RemoteExample.class, false, void.class, "Rem/fin_v0"); 503 } 504 505 void testUnreflect(Class<?> defc, boolean isStatic, Class<?> ret, String name, Class<?>... params) throws Throwable { 506 for (Object[] ac : accessCases(defc, name)) { 507 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, (isStatic ? null : defc), ret, name, params); 508 } 509 } 510 511 void testUnreflect(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 512 for (Object[] ac : accessCases(defc, name)) { 513 testUnreflectMaybeSpecial(null, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params); 514 } 515 } 516 517 void testUnreflectMaybeSpecial(Class<?> specialCaller, 518 boolean positive, Lookup lookup, 519 Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 520 countTest(positive); 521 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo 522 MethodType type = MethodType.methodType(ret, params); 523 Lookup specialLookup = (specialCaller != null ? maybeMoveIn(lookup, specialCaller) : null); 524 boolean specialAccessOK = (specialCaller != null && 525 specialLookup.lookupClass() == specialCaller && 526 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0); 527 Method rmethod = defc.getDeclaredMethod(methodName, params); 528 MethodHandle target = null; 529 Exception noAccess = null; 530 boolean isStatic = (rcvc == null); 531 boolean isSpecial = (specialCaller != null); 532 try { 533 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type); 534 if (isSpecial) 535 target = specialLookup.unreflectSpecial(rmethod, specialCaller); 536 else 537 target = maybeMoveIn(lookup, defc).unreflect(rmethod); 538 } catch (ReflectiveOperationException ex) { 539 noAccess = ex; 540 assertExceptionClass( 541 IllegalAccessException.class, // NSME is impossible, since it was already reflected 542 noAccess); 543 if (verbosity >= 5) ex.printStackTrace(System.out); 544 } 545 if (verbosity >= 3) 546 System.out.println("unreflect"+(isSpecial?"Special":"")+" "+defc.getName()+"."+name+"/"+type 547 +(!isSpecial ? "" : " specialCaller="+specialCaller) 548 +( isStatic ? "" : " receiver="+rcvc) 549 +" => "+target 550 +(noAccess == null ? "" : " !! "+noAccess)); 551 if (positive && noAccess != null) throw noAccess; 552 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 553 if (!positive) return; // negative test failed as expected 554 assertEquals(isStatic, Modifier.isStatic(rmethod.getModifiers())); 555 Class<?>[] paramsMaybeWithSelf = params; 556 if (!isStatic) { 557 paramsMaybeWithSelf = cat(array(Class[].class, (Class)rcvc), params); 558 } 559 MethodType typeMaybeWithSelf = MethodType.methodType(ret, paramsMaybeWithSelf); 560 if (isStatic) { 561 assertEquals(typeMaybeWithSelf, target.type()); 562 } else { 563 if (isSpecial) 564 assertEquals(specialCaller, target.type().parameterType(0)); 565 else 566 assertEquals(defc, target.type().parameterType(0)); 567 assertEquals(typeMaybeWithSelf, target.type().changeParameterType(0, rcvc)); 568 } 569 Object[] argsMaybeWithSelf = randomArgs(paramsMaybeWithSelf); 570 printCalled(target, name, argsMaybeWithSelf); 571 target.invokeWithArguments(argsMaybeWithSelf); 572 assertCalled(name, argsMaybeWithSelf); 573 if (verbosity >= 1) 574 System.out.print(':'); 575 } 576 577 void testUnreflectSpecial(Class<?> defc, Class<?> rcvc, Class<?> ret, String name, Class<?>... params) throws Throwable { 578 for (Object[] ac : accessCases(defc, name, true)) { 579 Class<?> specialCaller = rcvc; 580 testUnreflectMaybeSpecial(specialCaller, (Boolean)ac[0], (Lookup)ac[1], defc, rcvc, ret, name, params); 581 } 582 } 583 584 @Test 585 public void testUnreflectSpecial() throws Throwable { 586 CodeCacheOverflowProcessor.runMHTest(this::testUnreflectSpecial0); 587 } 588 589 public void testUnreflectSpecial0() throws Throwable { 590 if (CAN_SKIP_WORKING) return; 591 startTest("unreflectSpecial"); 592 testUnreflectSpecial(Example.class, Example.class, void.class, "v0"); 593 testUnreflectSpecial(Example.class, SubExample.class, void.class, "v0"); 594 testUnreflectSpecial(Example.class, Example.class, void.class, "pkg_v0"); 595 testUnreflectSpecial(Example.class, SubExample.class, void.class, "pkg_v0"); 596 testUnreflectSpecial(Example.class, Example.class, Object.class, "v2", int.class, int.class); 597 testUnreflectSpecial(Example.class, SubExample.class, Object.class, "v2", int.class, int.class); 598 testUnreflectMaybeSpecial(Example.class, false, PRIVATE, Example.class, Example.class, void.class, "s0"); 599 } 600 601 @Test 602 public void testUnreflectGetter() throws Throwable { 603 CodeCacheOverflowProcessor.runMHTest(this::testUnreflectGetter0); 604 } 605 606 public void testUnreflectGetter0() throws Throwable { 607 if (CAN_SKIP_WORKING) return; 608 startTest("unreflectGetter"); 609 testGetter(TEST_UNREFLECT); 610 } 611 612 @Test 613 public void testFindGetter() throws Throwable { 614 CodeCacheOverflowProcessor.runMHTest(this::testFindGetter0); 615 } 616 617 public void testFindGetter0() throws Throwable { 618 if (CAN_SKIP_WORKING) return; 619 startTest("findGetter"); 620 testGetter(TEST_FIND_FIELD); 621 testGetter(TEST_FIND_FIELD | TEST_BOUND); 622 } 623 624 @Test 625 public void testFindStaticGetter() throws Throwable { 626 CodeCacheOverflowProcessor.runMHTest(this::testFindStaticGetter0); 627 } 628 629 public void testFindStaticGetter0() throws Throwable { 630 if (CAN_SKIP_WORKING) return; 631 startTest("findStaticGetter"); 632 testGetter(TEST_FIND_STATIC); 633 } 634 635 public void testGetter(int testMode) throws Throwable { 636 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one 637 for (Object[] c : HasFields.cases(testMode)) { 638 boolean positive = (c[1] != Error.class); 639 testGetter(positive, lookup, c[0], c[1], testMode); 640 if (positive) 641 testGetter(positive, lookup, c[0], c[1], testMode | TEST_NPE); 642 } 643 testGetter(true, lookup, 644 new Object[]{ true, System.class, "out", java.io.PrintStream.class }, 645 System.out, testMode); 646 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { 647 testGetter(false, lookup, 648 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, 649 null, testMode); 650 } 651 } 652 653 public void testGetter(boolean positive, MethodHandles.Lookup lookup, 654 Object fieldRef, Object value, int testMode) throws Throwable { 655 testAccessor(positive, lookup, fieldRef, value, testMode); 656 } 657 658 public void testAccessor(boolean positive0, MethodHandles.Lookup lookup, 659 Object fieldRef, Object value, int testMode0) throws Throwable { 660 if (verbosity >= 4) 661 System.out.println("testAccessor"+Arrays.deepToString(new Object[]{positive0, lookup, fieldRef, value, testMode0})); 662 boolean isGetter = ((testMode0 & TEST_SETTER) == 0); 663 boolean doBound = ((testMode0 & TEST_BOUND) != 0); 664 boolean testNPE = ((testMode0 & TEST_NPE) != 0); 665 int testMode = testMode0 & ~(TEST_SETTER | TEST_BOUND | TEST_NPE); 666 boolean positive = positive0 && !testNPE; 667 boolean isStatic; 668 Class<?> fclass; 669 String fname; 670 Class<?> ftype; 671 Field f = (fieldRef instanceof Field ? (Field)fieldRef : null); 672 if (f != null) { 673 isStatic = Modifier.isStatic(f.getModifiers()); 674 fclass = f.getDeclaringClass(); 675 fname = f.getName(); 676 ftype = f.getType(); 677 } else { 678 Object[] scnt = (Object[]) fieldRef; 679 isStatic = (Boolean) scnt[0]; 680 fclass = (Class<?>) scnt[1]; 681 fname = (String) scnt[2]; 682 ftype = (Class<?>) scnt[3]; 683 try { 684 f = fclass.getDeclaredField(fname); 685 } catch (ReflectiveOperationException ex) { 686 f = null; 687 } 688 } 689 if (!testModeMatches(testMode, isStatic)) return; 690 if (f == null && testMode == TEST_UNREFLECT) return; 691 if (testNPE && isStatic) return; 692 countTest(positive); 693 MethodType expType; 694 if (isGetter) 695 expType = MethodType.methodType(ftype, HasFields.class); 696 else 697 expType = MethodType.methodType(void.class, HasFields.class, ftype); 698 if (isStatic) expType = expType.dropParameterTypes(0, 1); 699 Exception noAccess = null; 700 MethodHandle mh; 701 try { 702 switch (testMode0 & ~(TEST_BOUND | TEST_NPE)) { 703 case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break; 704 case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break; 705 case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break; 706 case TEST_SETTER| 707 TEST_UNREFLECT: mh = lookup.unreflectSetter(f); break; 708 case TEST_SETTER| 709 TEST_FIND_FIELD: mh = lookup.findSetter(fclass, fname, ftype); break; 710 case TEST_SETTER| 711 TEST_FIND_STATIC: mh = lookup.findStaticSetter(fclass, fname, ftype); break; 712 default: 713 throw new InternalError("testMode="+testMode); 714 } 715 } catch (ReflectiveOperationException ex) { 716 mh = null; 717 noAccess = ex; 718 assertExceptionClass( 719 (fname.contains("bogus")) 720 ? NoSuchFieldException.class 721 : IllegalAccessException.class, 722 noAccess); 723 if (verbosity >= 5) ex.printStackTrace(System.out); 724 } 725 if (verbosity >= 3) 726 System.out.format("%s%s %s.%s/%s => %s %s%n", 727 (testMode0 & TEST_UNREFLECT) != 0 728 ? "unreflect" 729 : "find" + ((testMode0 & TEST_FIND_STATIC) != 0 ? "Static" : ""), 730 (isGetter ? "Getter" : "Setter"), 731 fclass.getName(), fname, ftype, mh, 732 (noAccess == null ? "" : " !! "+noAccess)); 733 if (!positive && noAccess != null) return; 734 if (positive && !testNPE && noAccess != null) throw new RuntimeException(noAccess); 735 assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null); 736 if (!positive && !testNPE) return; // negative access test failed as expected 737 assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount()); 738 739 assertSame(mh.type(), expType); 740 //assertNameStringContains(mh, fname); // This does not hold anymore with LFs 741 HasFields fields = new HasFields(); 742 HasFields fieldsForMH = fields; 743 if (testNPE) fieldsForMH = null; // perturb MH argument to elicit expected error 744 if (doBound) 745 mh = mh.bindTo(fieldsForMH); 746 Object sawValue; 747 Class<?> vtype = ftype; 748 if (ftype != int.class) vtype = Object.class; 749 if (isGetter) { 750 mh = mh.asType(mh.type().generic() 751 .changeReturnType(vtype)); 752 } else { 753 int last = mh.type().parameterCount() - 1; 754 mh = mh.asType(mh.type().generic() 755 .changeReturnType(void.class) 756 .changeParameterType(last, vtype)); 757 } 758 if (f != null && f.getDeclaringClass() == HasFields.class) { 759 assertEquals(f.get(fields), value); // clean to start with 760 } 761 Throwable caughtEx = null; 762 boolean writeAccess = !Modifier.isFinal(f.getModifiers()) || 763 (!Modifier.isStatic(f.getModifiers()) && f.isAccessible()); 764 if (isGetter) { 765 Object expValue = value; 766 for (int i = 0; i <= 1; i++) { 767 sawValue = null; // make DA rules happy under try/catch 768 try { 769 if (isStatic || doBound) { 770 if (ftype == int.class) 771 sawValue = (int) mh.invokeExact(); // do these exactly 772 else 773 sawValue = mh.invokeExact(); 774 } else { 775 if (ftype == int.class) 776 sawValue = (int) mh.invokeExact((Object) fieldsForMH); 777 else 778 sawValue = mh.invokeExact((Object) fieldsForMH); 779 } 780 } catch (RuntimeException ex) { 781 if (ex instanceof NullPointerException && testNPE) { 782 caughtEx = ex; 783 break; 784 } 785 } 786 assertEquals(sawValue, expValue); 787 if (f != null && f.getDeclaringClass() == HasFields.class && writeAccess) { 788 Object random = randomArg(ftype); 789 f.set(fields, random); 790 expValue = random; 791 } else { 792 break; 793 } 794 } 795 } else { 796 for (int i = 0; i <= 1; i++) { 797 Object putValue = randomArg(ftype); 798 try { 799 if (isStatic || doBound) { 800 if (ftype == int.class) 801 mh.invokeExact((int)putValue); // do these exactly 802 else 803 mh.invokeExact(putValue); 804 } else { 805 if (ftype == int.class) 806 mh.invokeExact((Object) fieldsForMH, (int)putValue); 807 else 808 mh.invokeExact((Object) fieldsForMH, putValue); 809 } 810 } catch (RuntimeException ex) { 811 if (ex instanceof NullPointerException && testNPE) { 812 caughtEx = ex; 813 break; 814 } 815 } 816 if (f != null && f.getDeclaringClass() == HasFields.class) { 817 assertEquals(f.get(fields), putValue); 818 } 819 } 820 } 821 if (f != null && f.getDeclaringClass() == HasFields.class && writeAccess) { 822 f.set(fields, value); // put it back 823 } 824 if (testNPE) { 825 if (caughtEx == null || !(caughtEx instanceof NullPointerException)) 826 throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx); 827 caughtEx = null; // nullify expected exception 828 } 829 if (caughtEx != null) { 830 throw new RuntimeException("unexpected exception", caughtEx); 831 } 832 } 833 834 @Test 835 public void testUnreflectSetter() throws Throwable { 836 CodeCacheOverflowProcessor.runMHTest(this::testUnreflectSetter0); 837 } 838 839 public void testUnreflectSetter0() throws Throwable { 840 if (CAN_SKIP_WORKING) return; 841 startTest("unreflectSetter"); 842 testSetter(TEST_UNREFLECT); 843 } 844 845 @Test 846 public void testFindSetter() throws Throwable { 847 CodeCacheOverflowProcessor.runMHTest(this::testFindSetter0); 848 } 849 850 public void testFindSetter0() throws Throwable { 851 if (CAN_SKIP_WORKING) return; 852 startTest("findSetter"); 853 testSetter(TEST_FIND_FIELD); 854 testSetter(TEST_FIND_FIELD | TEST_BOUND); 855 } 856 857 @Test 858 public void testFindStaticSetter() throws Throwable { 859 CodeCacheOverflowProcessor.runMHTest(this::testFindStaticSetter0); 860 } 861 862 public void testFindStaticSetter0() throws Throwable { 863 if (CAN_SKIP_WORKING) return; 864 startTest("findStaticSetter"); 865 testSetter(TEST_FIND_STATIC); 866 } 867 868 public void testSetter(int testMode) throws Throwable { 869 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one 870 startTest("testSetter"); 871 for (Object[] c : HasFields.cases(testMode)) { 872 boolean positive = (c[1] != Error.class) && !(c.length == 3 && c[2] == Error.class); 873 if ((testMode & TEST_UNREFLECT) != 0 && c.length == 3) { 874 assertTrue(c[0] instanceof Field && c[2] == Error.class); 875 Field f = (Field)c[0]; 876 int mods = f.getModifiers(); 877 // unreflectSetter should only have write access on instance final field if accessible flag is true 878 positive = !Modifier.isFinal(mods) || 879 (!Modifier.isStatic(mods) && f.isAccessible()); 880 } 881 testSetter(positive, lookup, c[0], c[1], testMode); 882 if (positive) 883 testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE); 884 } 885 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { 886 testSetter(false, lookup, 887 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, 888 null, testMode); 889 } 890 } 891 892 public void testSetter(boolean positive, MethodHandles.Lookup lookup, 893 Object fieldRef, Object value, int testMode) throws Throwable { 894 testAccessor(positive, lookup, fieldRef, value, testMode | TEST_SETTER); 895 } 896 897 @Test 898 public void testArrayElementGetter() throws Throwable { 899 CodeCacheOverflowProcessor.runMHTest(this::testArrayElementGetter0); 900 } 901 902 public void testArrayElementGetter0() throws Throwable { 903 if (CAN_SKIP_WORKING) return; 904 startTest("arrayElementGetter"); 905 testArrayElementGetterSetter(false); 906 } 907 908 @Test 909 public void testArrayElementSetter() throws Throwable { 910 CodeCacheOverflowProcessor.runMHTest(this::testArrayElementSetter0); 911 } 912 913 public void testArrayElementSetter0() throws Throwable { 914 if (CAN_SKIP_WORKING) return; 915 startTest("arrayElementSetter"); 916 testArrayElementGetterSetter(true); 917 } 918 919 private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3; 920 921 public void testArrayElementGetterSetter(boolean testSetter) throws Throwable { 922 testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE); 923 } 924 925 @Test 926 public void testArrayElementErrors() throws Throwable { 927 CodeCacheOverflowProcessor.runMHTest(this::testArrayElementErrors0); 928 } 929 930 public void testArrayElementErrors0() throws Throwable { 931 if (CAN_SKIP_WORKING) return; 932 startTest("arrayElementErrors"); 933 testArrayElementGetterSetter(false, TEST_ARRAY_NPE); 934 testArrayElementGetterSetter(true, TEST_ARRAY_NPE); 935 testArrayElementGetterSetter(false, TEST_ARRAY_OOB); 936 testArrayElementGetterSetter(true, TEST_ARRAY_OOB); 937 testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE); 938 testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE); 939 testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE); 940 } 941 942 public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable { 943 testArrayElementGetterSetter(new String[10], testSetter, negTest); 944 testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest); 945 testArrayElementGetterSetter(new Example[10], testSetter, negTest); 946 testArrayElementGetterSetter(new IntExample[10], testSetter, negTest); 947 testArrayElementGetterSetter(new Object[10], testSetter, negTest); 948 testArrayElementGetterSetter(new boolean[10], testSetter, negTest); 949 testArrayElementGetterSetter(new byte[10], testSetter, negTest); 950 testArrayElementGetterSetter(new char[10], testSetter, negTest); 951 testArrayElementGetterSetter(new short[10], testSetter, negTest); 952 testArrayElementGetterSetter(new int[10], testSetter, negTest); 953 testArrayElementGetterSetter(new float[10], testSetter, negTest); 954 testArrayElementGetterSetter(new long[10], testSetter, negTest); 955 testArrayElementGetterSetter(new double[10], testSetter, negTest); 956 } 957 958 public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable { 959 boolean positive = (negTest == TEST_ARRAY_NONE); 960 int length = Array.getLength(array); 961 Class<?> arrayType = array.getClass(); 962 Class<?> elemType = arrayType.getComponentType(); 963 Object arrayToMH = array; 964 // this stanza allows negative tests to make argument perturbations: 965 switch (negTest) { 966 case TEST_ARRAY_NPE: 967 arrayToMH = null; 968 break; 969 case TEST_ARRAY_OOB: 970 assert(length > 0); 971 arrayToMH = Array.newInstance(elemType, 0); 972 break; 973 case TEST_ARRAY_ASE: 974 assert(testSetter && !elemType.isPrimitive()); 975 if (elemType == Object.class) 976 arrayToMH = new StringBuffer[length]; // very random subclass of Object! 977 else if (elemType == Example.class) 978 arrayToMH = new SubExample[length]; 979 else if (elemType == IntExample.class) 980 arrayToMH = new SubIntExample[length]; 981 else 982 return; // can't make an ArrayStoreException test 983 assert(arrayType.isInstance(arrayToMH)) 984 : Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest); 985 break; 986 } 987 countTest(positive); 988 if (verbosity > 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+length+"]"+(positive ? "" : " negative test #"+negTest+" using "+Arrays.deepToString(new Object[]{arrayToMH}))); 989 MethodType expType = !testSetter 990 ? MethodType.methodType(elemType, arrayType, int.class) 991 : MethodType.methodType(void.class, arrayType, int.class, elemType); 992 MethodHandle mh = !testSetter 993 ? MethodHandles.arrayElementGetter(arrayType) 994 : MethodHandles.arrayElementSetter(arrayType); 995 assertSame(mh.type(), expType); 996 if (elemType != int.class && elemType != boolean.class) { 997 MethodType gtype = mh.type().generic().changeParameterType(1, int.class); 998 if (testSetter) gtype = gtype.changeReturnType(void.class); 999 mh = mh.asType(gtype); 1000 } 1001 Object sawValue, expValue; 1002 List<Object> model = array2list(array); 1003 Throwable caughtEx = null; 1004 for (int i = 0; i < length; i++) { 1005 // update array element 1006 Object random = randomArg(elemType); 1007 model.set(i, random); 1008 if (testSetter) { 1009 try { 1010 if (elemType == int.class) 1011 mh.invokeExact((int[]) arrayToMH, i, (int)random); 1012 else if (elemType == boolean.class) 1013 mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random); 1014 else 1015 mh.invokeExact(arrayToMH, i, random); 1016 } catch (RuntimeException ex) { 1017 caughtEx = ex; 1018 break; 1019 } 1020 assertEquals(model, array2list(array)); 1021 } else { 1022 Array.set(array, i, random); 1023 } 1024 if (verbosity >= 5) { 1025 List<Object> array2list = array2list(array); 1026 System.out.println("a["+i+"]="+random+" => "+array2list); 1027 if (!array2list.equals(model)) 1028 System.out.println("*** != "+model); 1029 } 1030 // observe array element 1031 sawValue = Array.get(array, i); 1032 if (!testSetter) { 1033 expValue = sawValue; 1034 try { 1035 if (elemType == int.class) 1036 sawValue = (int) mh.invokeExact((int[]) arrayToMH, i); 1037 else if (elemType == boolean.class) 1038 sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i); 1039 else 1040 sawValue = mh.invokeExact(arrayToMH, i); 1041 } catch (RuntimeException ex) { 1042 caughtEx = ex; 1043 break; 1044 } 1045 assertEquals(sawValue, expValue); 1046 assertEquals(model, array2list(array)); 1047 } 1048 } 1049 if (!positive) { 1050 if (caughtEx == null) 1051 throw new RuntimeException("failed to catch exception for negTest="+negTest); 1052 // test the kind of exception 1053 Class<?> reqType = null; 1054 switch (negTest) { 1055 case TEST_ARRAY_ASE: reqType = ArrayStoreException.class; break; 1056 case TEST_ARRAY_OOB: reqType = ArrayIndexOutOfBoundsException.class; break; 1057 case TEST_ARRAY_NPE: reqType = NullPointerException.class; break; 1058 default: assert(false); 1059 } 1060 if (reqType.isInstance(caughtEx)) { 1061 caughtEx = null; // nullify expected exception 1062 } 1063 } 1064 if (caughtEx != null) { 1065 throw new RuntimeException("unexpected exception", caughtEx); 1066 } 1067 } 1068 1069 List<Object> array2list(Object array) { 1070 int length = Array.getLength(array); 1071 ArrayList<Object> model = new ArrayList<>(length); 1072 for (int i = 0; i < length; i++) 1073 model.add(Array.get(array, i)); 1074 return model; 1075 } 1076 1077 @Test 1078 public void testConvertArguments() throws Throwable { 1079 CodeCacheOverflowProcessor.runMHTest(this::testConvertArguments0); 1080 } 1081 1082 public void testConvertArguments0() throws Throwable { 1083 if (CAN_SKIP_WORKING) return; 1084 startTest("convertArguments"); 1085 testConvert(Callee.ofType(1), null, "id", int.class); 1086 testConvert(Callee.ofType(1), null, "id", String.class); 1087 testConvert(Callee.ofType(1), null, "id", Integer.class); 1088 testConvert(Callee.ofType(1), null, "id", short.class); 1089 testConvert(Callee.ofType(1), null, "id", char.class); 1090 testConvert(Callee.ofType(1), null, "id", byte.class); 1091 } 1092 1093 void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1094 testConvert(true, id, rtype, name, params); 1095 } 1096 1097 void testConvert(boolean positive, 1098 MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1099 countTest(positive); 1100 MethodType idType = id.type(); 1101 if (rtype == null) rtype = idType.returnType(); 1102 for (int i = 0; i < params.length; i++) { 1103 if (params[i] == null) params[i] = idType.parameterType(i); 1104 } 1105 // simulate the pairwise conversion 1106 MethodType newType = MethodType.methodType(rtype, params); 1107 Object[] args = randomArgs(newType.parameterArray()); 1108 Object[] convArgs = args.clone(); 1109 for (int i = 0; i < args.length; i++) { 1110 Class<?> src = newType.parameterType(i); 1111 Class<?> dst = idType.parameterType(i); 1112 if (src != dst) 1113 convArgs[i] = castToWrapper(convArgs[i], dst); 1114 } 1115 Object convResult = id.invokeWithArguments(convArgs); 1116 { 1117 Class<?> dst = newType.returnType(); 1118 Class<?> src = idType.returnType(); 1119 if (src != dst) 1120 convResult = castToWrapper(convResult, dst); 1121 } 1122 MethodHandle target = null; 1123 RuntimeException error = null; 1124 try { 1125 target = id.asType(newType); 1126 } catch (WrongMethodTypeException ex) { 1127 error = ex; 1128 } 1129 if (verbosity >= 3) 1130 System.out.println("convert "+id+ " to "+newType+" => "+target 1131 +(error == null ? "" : " !! "+error)); 1132 if (positive && error != null) throw error; 1133 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 1134 if (!positive) return; // negative test failed as expected 1135 assertEquals(newType, target.type()); 1136 printCalled(target, id.toString(), args); 1137 Object result = target.invokeWithArguments(args); 1138 assertCalled(name, convArgs); 1139 assertEquals(convResult, result); 1140 if (verbosity >= 1) 1141 System.out.print(':'); 1142 } 1143 1144 @Test 1145 public void testVarargsCollector() throws Throwable { 1146 CodeCacheOverflowProcessor.runMHTest(this::testVarargsCollector0); 1147 } 1148 1149 public void testVarargsCollector0() throws Throwable { 1150 if (CAN_SKIP_WORKING) return; 1151 startTest("varargsCollector"); 1152 MethodHandle vac0 = PRIVATE.findStatic(MethodHandlesTest.class, "called", 1153 MethodType.methodType(Object.class, String.class, Object[].class)); 1154 vac0 = vac0.bindTo("vac"); 1155 MethodHandle vac = vac0.asVarargsCollector(Object[].class); 1156 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1157 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1158 for (Class<?> at : new Class<?>[] { Object.class, String.class, Integer.class }) { 1159 testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at); 1160 testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at); 1161 } 1162 } 1163 1164 @Test 1165 public void testFilterReturnValue() throws Throwable { 1166 CodeCacheOverflowProcessor.runMHTest(this::testFilterReturnValue0); 1167 } 1168 1169 public void testFilterReturnValue0() throws Throwable { 1170 if (CAN_SKIP_WORKING) return; 1171 startTest("filterReturnValue"); 1172 Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass(); 1173 assertTrue(List.class.isAssignableFrom(classOfVCList)); 1174 for (int nargs = 0; nargs <= 3; nargs++) { 1175 for (Class<?> rtype : new Class<?>[] { Object.class, 1176 List.class, 1177 int.class, 1178 byte.class, 1179 long.class, 1180 CharSequence.class, 1181 String.class }) { 1182 testFilterReturnValue(nargs, rtype); 1183 } 1184 } 1185 } 1186 1187 void testFilterReturnValue(int nargs, Class<?> rtype) throws Throwable { 1188 countTest(); 1189 MethodHandle target = varargsList(nargs, rtype); 1190 MethodHandle filter; 1191 if (List.class.isAssignableFrom(rtype) || rtype.isAssignableFrom(List.class)) 1192 filter = varargsList(1); // add another layer of list-ness 1193 else 1194 filter = MethodHandles.identity(rtype); 1195 filter = filter.asType(MethodType.methodType(target.type().returnType(), rtype)); 1196 Object[] argsToPass = randomArgs(nargs, Object.class); 1197 if (verbosity >= 3) 1198 System.out.println("filter "+target+" to "+rtype.getSimpleName()+" with "+filter); 1199 MethodHandle target2 = MethodHandles.filterReturnValue(target, filter); 1200 if (verbosity >= 4) 1201 System.out.println("filtered target: "+target2); 1202 // Simulate expected effect of filter on return value: 1203 Object unfiltered = target.invokeWithArguments(argsToPass); 1204 Object expected = filter.invokeWithArguments(unfiltered); 1205 if (verbosity >= 4) 1206 System.out.println("unfiltered: "+unfiltered+" : "+unfiltered.getClass().getSimpleName()); 1207 if (verbosity >= 4) 1208 System.out.println("expected: "+expected+" : "+expected.getClass().getSimpleName()); 1209 Object result = target2.invokeWithArguments(argsToPass); 1210 if (verbosity >= 3) 1211 System.out.println("result: "+result+" : "+result.getClass().getSimpleName()); 1212 if (!expected.equals(result)) 1213 System.out.println("*** fail at n/rt = "+nargs+"/"+rtype.getSimpleName()+": "+ 1214 Arrays.asList(argsToPass)+" => "+result+" != "+expected); 1215 assertEquals(expected, result); 1216 } 1217 1218 @Test 1219 public void testFilterArguments() throws Throwable { 1220 CodeCacheOverflowProcessor.runMHTest(this::testFilterArguments0); 1221 } 1222 1223 public void testFilterArguments0() throws Throwable { 1224 if (CAN_SKIP_WORKING) return; 1225 startTest("filterArguments"); 1226 for (int nargs = 1; nargs <= 6; nargs++) { 1227 for (int pos = 0; pos < nargs; pos++) { 1228 testFilterArguments(nargs, pos); 1229 } 1230 } 1231 } 1232 1233 void testFilterArguments(int nargs, int pos) throws Throwable { 1234 countTest(); 1235 MethodHandle target = varargsList(nargs); 1236 MethodHandle filter = varargsList(1); 1237 filter = filter.asType(filter.type().generic()); 1238 Object[] argsToPass = randomArgs(nargs, Object.class); 1239 if (verbosity >= 3) 1240 System.out.println("filter "+target+" at "+pos+" with "+filter); 1241 MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter); 1242 // Simulate expected effect of filter on arglist: 1243 Object[] filteredArgs = argsToPass.clone(); 1244 filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]); 1245 List<Object> expected = Arrays.asList(filteredArgs); 1246 Object result = target2.invokeWithArguments(argsToPass); 1247 if (verbosity >= 3) 1248 System.out.println("result: "+result); 1249 if (!expected.equals(result)) 1250 System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected); 1251 assertEquals(expected, result); 1252 } 1253 1254 @Test 1255 public void testCollectArguments() throws Throwable { 1256 CodeCacheOverflowProcessor.runMHTest(this::testCollectArguments0); 1257 } 1258 1259 public void testCollectArguments0() throws Throwable { 1260 if (CAN_SKIP_WORKING) return; 1261 startTest("collectArguments"); 1262 testFoldOrCollectArguments(true, false); 1263 } 1264 1265 @Test 1266 public void testFoldArguments() throws Throwable { 1267 CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments0); 1268 CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments1); 1269 } 1270 1271 public void testFoldArguments0() throws Throwable { 1272 if (CAN_SKIP_WORKING) return; 1273 startTest("foldArguments"); 1274 testFoldOrCollectArguments(false, false); 1275 } 1276 1277 public void testFoldArguments1() throws Throwable { 1278 if (CAN_SKIP_WORKING) return; 1279 startTest("foldArguments/pos"); 1280 testFoldOrCollectArguments(false, true); 1281 } 1282 1283 void testFoldOrCollectArguments(boolean isCollect, boolean withFoldPos) throws Throwable { 1284 assert !(isCollect && withFoldPos); // exclude illegal argument combination 1285 for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) { 1286 for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) { 1287 int maxArity = 10; 1288 if (collectType != String.class) maxArity = 5; 1289 if (lastType != Object.class) maxArity = 4; 1290 for (int nargs = 0; nargs <= maxArity; nargs++) { 1291 ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class)); 1292 int maxMix = 20; 1293 if (collectType != Object.class) maxMix = 0; 1294 Map<Object,Integer> argTypesSeen = new HashMap<>(); 1295 for (int mix = 0; mix <= maxMix; mix++) { 1296 if (!mixArgs(argTypes, mix, argTypesSeen)) continue; 1297 for (int collect = 0; collect <= nargs; collect++) { 1298 for (int pos = 0; pos <= nargs - collect; pos++) { 1299 testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect, withFoldPos); 1300 } 1301 } 1302 } 1303 } 1304 } 1305 } 1306 } 1307 1308 boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) { 1309 assert(mix >= 0); 1310 if (mix == 0) return true; // no change 1311 if ((mix >>> argTypes.size()) != 0) return false; 1312 for (int i = 0; i < argTypes.size(); i++) { 1313 if (i >= 31) break; 1314 boolean bit = (mix & (1 << i)) != 0; 1315 if (bit) { 1316 Class<?> type = argTypes.get(i); 1317 if (type == Object.class) 1318 type = String.class; 1319 else if (type == String.class) 1320 type = int.class; 1321 else 1322 type = Object.class; 1323 argTypes.set(i, type); 1324 } 1325 } 1326 Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix); 1327 if (prev != null) { 1328 if (verbosity >= 4) System.out.println("mix "+prev+" repeated "+mix+": "+argTypes); 1329 return false; 1330 } 1331 if (verbosity >= 3) System.out.println("mix "+mix+" = "+argTypes); 1332 return true; 1333 } 1334 1335 void testFoldOrCollectArguments(List<Class<?>> argTypes, // argument types minus the inserted combineType 1336 int pos, int fold, // position and length of the folded arguments 1337 Class<?> combineType, // type returned from the combiner 1338 Class<?> lastType, // type returned from the target 1339 boolean isCollect, 1340 boolean withFoldPos) throws Throwable { 1341 int nargs = argTypes.size(); 1342 if (pos != 0 && !isCollect && !withFoldPos) return; // test MethodHandles.foldArguments(MH,MH) only for pos=0 1343 countTest(); 1344 List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold); 1345 List<Class<?>> targetArgTypes = new ArrayList<>(argTypes); 1346 if (isCollect) // does target see arg[pos..pos+cc-1]? 1347 targetArgTypes.subList(pos, pos + fold).clear(); 1348 if (combineType != void.class) 1349 targetArgTypes.add(pos, combineType); 1350 MethodHandle target = varargsList(targetArgTypes, lastType); 1351 MethodHandle combine = varargsList(combineArgTypes, combineType); 1352 List<Object> argsToPass = Arrays.asList(randomArgs(argTypes)); 1353 if (verbosity >= 3) 1354 System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine); 1355 MethodHandle target2; 1356 if (isCollect) 1357 target2 = MethodHandles.collectArguments(target, pos, combine); 1358 else 1359 target2 = withFoldPos ? MethodHandles.foldArguments(target, pos, combine) : MethodHandles.foldArguments(target, combine); 1360 // Simulate expected effect of combiner on arglist: 1361 List<Object> expectedList = new ArrayList<>(argsToPass); 1362 List<Object> argsToFold = expectedList.subList(pos, pos + fold); 1363 if (verbosity >= 3) 1364 System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2); 1365 Object foldedArgs = combine.invokeWithArguments(argsToFold); 1366 if (isCollect) 1367 argsToFold.clear(); 1368 if (combineType != void.class) 1369 argsToFold.add(0, foldedArgs); 1370 Object result = target2.invokeWithArguments(argsToPass); 1371 if (verbosity >= 3) 1372 System.out.println("result: "+result); 1373 Object expected = target.invokeWithArguments(expectedList); 1374 if (!expected.equals(result)) 1375 System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected); 1376 assertEquals(expected, result); 1377 } 1378 1379 @Test 1380 public void testDropArguments() throws Throwable { 1381 CodeCacheOverflowProcessor.runMHTest(this::testDropArguments0); 1382 } 1383 1384 public void testDropArguments0() throws Throwable { 1385 if (CAN_SKIP_WORKING) return; 1386 startTest("dropArguments"); 1387 for (int nargs = 0; nargs <= 4; nargs++) { 1388 for (int drop = 1; drop <= 4; drop++) { 1389 for (int pos = 0; pos <= nargs; pos++) { 1390 testDropArguments(nargs, pos, drop); 1391 } 1392 } 1393 } 1394 } 1395 1396 void testDropArguments(int nargs, int pos, int drop) throws Throwable { 1397 countTest(); 1398 MethodHandle target = varargsArray(nargs); 1399 Object[] args = randomArgs(target.type().parameterArray()); 1400 MethodHandle target2 = MethodHandles.dropArguments(target, pos, 1401 Collections.nCopies(drop, Object.class).toArray(new Class<?>[0])); 1402 List<Object> resList = Arrays.asList(args); 1403 List<Object> argsToDrop = new ArrayList<>(resList); 1404 for (int i = drop; i > 0; i--) { 1405 argsToDrop.add(pos, "blort#"+i); 1406 } 1407 Object res2 = target2.invokeWithArguments(argsToDrop); 1408 Object res2List = Arrays.asList((Object[])res2); 1409 //if (!resList.equals(res2List)) 1410 // System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List); 1411 assertEquals(resList, res2List); 1412 } 1413 1414 @Test 1415 public void testGuardWithTest() throws Throwable { 1416 CodeCacheOverflowProcessor.runMHTest(this::testGuardWithTest0); 1417 } 1418 1419 public void testGuardWithTest0() throws Throwable { 1420 if (CAN_SKIP_WORKING) return; 1421 startTest("guardWithTest"); 1422 for (int nargs = 0; nargs <= 50; nargs++) { 1423 if (CAN_TEST_LIGHTLY && nargs > 7) break; 1424 testGuardWithTest(nargs, Object.class); 1425 testGuardWithTest(nargs, String.class); 1426 } 1427 } 1428 1429 void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable { 1430 testGuardWithTest(nargs, 0, argClass); 1431 if (nargs <= 5 || nargs % 10 == 3) { 1432 for (int testDrops = 1; testDrops <= nargs; testDrops++) 1433 testGuardWithTest(nargs, testDrops, argClass); 1434 } 1435 } 1436 1437 void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable { 1438 countTest(); 1439 int nargs1 = Math.min(3, nargs); 1440 MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class)); 1441 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1)); 1442 MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1)); 1443 while (test.type().parameterCount() > nargs) 1444 // 0: test = constant(MISSING_ARG.equals(MISSING_ARG)) 1445 // 1: test = lambda (_) MISSING_ARG.equals(_) 1446 test = MethodHandles.insertArguments(test, 0, MISSING_ARG); 1447 if (argClass != Object.class) { 1448 test = changeArgTypes(test, argClass); 1449 target = changeArgTypes(target, argClass); 1450 fallback = changeArgTypes(fallback, argClass); 1451 } 1452 int testArgs = nargs - testDrops; 1453 assert(testArgs >= 0); 1454 test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass); 1455 target = addTrailingArgs(target, nargs, argClass); 1456 fallback = addTrailingArgs(fallback, nargs, argClass); 1457 Object[][] argLists = { 1458 { }, 1459 { "foo" }, { MethodHandlesTest.MISSING_ARG }, 1460 { "foo", "foo" }, { "foo", "bar" }, 1461 { "foo", "foo", "baz" }, { "foo", "bar", "baz" } 1462 }; 1463 for (Object[] argList : argLists) { 1464 Object[] argList1 = argList; 1465 if (argList.length != nargs) { 1466 if (argList.length != nargs1) continue; 1467 argList1 = Arrays.copyOf(argList, nargs); 1468 Arrays.fill(argList1, nargs1, nargs, MethodHandlesTest.MISSING_ARG_2); 1469 } 1470 MethodHandle test1 = test; 1471 if (test1.type().parameterCount() > testArgs) { 1472 int pc = test1.type().parameterCount(); 1473 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc)); 1474 } 1475 MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback); 1476 assertEquals(target.type(), mh.type()); 1477 boolean equals; 1478 switch (nargs) { 1479 case 0: equals = true; break; 1480 case 1: equals = MethodHandlesTest.MISSING_ARG.equals(argList[0]); break; 1481 default: equals = argList[0].equals(argList[1]); break; 1482 } 1483 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals"); 1484 if (verbosity >= 3) 1485 System.out.println(logEntry(willCall, argList)); 1486 Object result = mh.invokeWithArguments(argList1); 1487 assertCalled(willCall, argList); 1488 } 1489 } 1490 1491 @Test 1492 public void testGenericLoopCombinator() throws Throwable { 1493 CodeCacheOverflowProcessor.runMHTest(this::testGenericLoopCombinator0); 1494 } 1495 1496 public void testGenericLoopCombinator0() throws Throwable { 1497 if (CAN_SKIP_WORKING) return; 1498 startTest("loop"); 1499 // Test as follows: 1500 // * Have an increasing number of loop-local state. Local state type diversity grows with the number. 1501 // * Initializers set the starting value of loop-local state from the corresponding loop argument. 1502 // * For each local state element, there is a predicate - for all state combinations, exercise all predicates. 1503 // * Steps modify each local state element in each iteration. 1504 // * Finalizers group all local state elements into a resulting array. Verify end values. 1505 // * Exercise both pre- and post-checked loops. 1506 // Local state types, start values, predicates, and steps: 1507 // * int a, 0, a < 7, a = a + 1 1508 // * double b, 7.0, b > 0.5, b = b / 2.0 1509 // * String c, "start", c.length <= 9, c = c + a 1510 final Class<?>[] argTypes = new Class<?>[] {int.class, double.class, String.class}; 1511 final Object[][] args = new Object[][] { 1512 new Object[]{0 }, 1513 new Object[]{0, 7.0 }, 1514 new Object[]{0, 7.0, "start"} 1515 }; 1516 // These are the expected final state tuples for argument type tuple / predicate combinations, for pre- and 1517 // post-checked loops: 1518 final Object[][] preCheckedResults = new Object[][] { 1519 new Object[]{7 }, // (int) / int 1520 new Object[]{7, 0.0546875 }, // (int,double) / int 1521 new Object[]{5, 0.4375 }, // (int,double) / double 1522 new Object[]{7, 0.0546875, "start1234567"}, // (int,double,String) / int 1523 new Object[]{5, 0.4375, "start1234" }, // (int,double,String) / double 1524 new Object[]{6, 0.109375, "start12345" } // (int,double,String) / String 1525 }; 1526 final Object[][] postCheckedResults = new Object[][] { 1527 new Object[]{7 }, // (int) / int 1528 new Object[]{7, 0.109375 }, // (int,double) / int 1529 new Object[]{4, 0.4375 }, // (int,double) / double 1530 new Object[]{7, 0.109375, "start123456"}, // (int,double,String) / int 1531 new Object[]{4, 0.4375, "start123" }, // (int,double,String) / double 1532 new Object[]{5, 0.21875, "start12345" } // (int,double,String) / String 1533 }; 1534 final Lookup l = MethodHandles.lookup(); 1535 final Class<?> MHT = MethodHandlesTest.class; 1536 final Class<?> B = boolean.class; 1537 final Class<?> I = int.class; 1538 final Class<?> D = double.class; 1539 final Class<?> S = String.class; 1540 final MethodHandle hip = l.findStatic(MHT, "loopIntPred", methodType(B, I)); 1541 final MethodHandle hdp = l.findStatic(MHT, "loopDoublePred", methodType(B, I, D)); 1542 final MethodHandle hsp = l.findStatic(MHT, "loopStringPred", methodType(B, I, D, S)); 1543 final MethodHandle his = l.findStatic(MHT, "loopIntStep", methodType(I, I)); 1544 final MethodHandle hds = l.findStatic(MHT, "loopDoubleStep", methodType(D, I, D)); 1545 final MethodHandle hss = l.findStatic(MHT, "loopStringStep", methodType(S, I, D, S)); 1546 final MethodHandle[] preds = new MethodHandle[] {hip, hdp, hsp}; 1547 final MethodHandle[] steps = new MethodHandle[] {his, hds, hss}; 1548 for (int nargs = 1, useResultsStart = 0; nargs <= argTypes.length; useResultsStart += nargs++) { 1549 Class<?>[] useArgTypes = Arrays.copyOf(argTypes, nargs, Class[].class); 1550 MethodHandle[] usePreds = Arrays.copyOf(preds, nargs, MethodHandle[].class); 1551 MethodHandle[] useSteps = Arrays.copyOf(steps, nargs, MethodHandle[].class); 1552 Object[] useArgs = args[nargs - 1]; 1553 Object[][] usePreCheckedResults = new Object[nargs][]; 1554 Object[][] usePostCheckedResults = new Object[nargs][]; 1555 System.arraycopy(preCheckedResults, useResultsStart, usePreCheckedResults, 0, nargs); 1556 System.arraycopy(postCheckedResults, useResultsStart, usePostCheckedResults, 0, nargs); 1557 testGenericLoopCombinator(nargs, useArgTypes, usePreds, useSteps, useArgs, usePreCheckedResults, 1558 usePostCheckedResults); 1559 } 1560 } 1561 1562 void testGenericLoopCombinator(int nargs, Class<?>[] argTypes, MethodHandle[] preds, MethodHandle[] steps, 1563 Object[] args, Object[][] preCheckedResults, Object[][] postCheckedResults) 1564 throws Throwable { 1565 List<Class<?>> lArgTypes = Arrays.asList(argTypes); 1566 // Predicate and step handles are passed in as arguments, initializer and finalizer handles are constructed here 1567 // from the available information. 1568 MethodHandle[] inits = new MethodHandle[nargs]; 1569 for (int i = 0; i < nargs; ++i) { 1570 MethodHandle h; 1571 // Initializers are meant to return whatever they are passed at a given argument position. This means that 1572 // additional arguments may have to be appended and prepended. 1573 h = MethodHandles.identity(argTypes[i]); 1574 if (i < nargs - 1) { 1575 h = MethodHandles.dropArguments(h, 1, lArgTypes.subList(i + 1, nargs)); 1576 } 1577 if (i > 0) { 1578 h = MethodHandles.dropArguments(h, 0, lArgTypes.subList(0, i)); 1579 } 1580 inits[i] = h; 1581 } 1582 // Finalizers are all meant to collect all of the loop-local state in a single array and return that. Local 1583 // state is passed before the loop args. Construct such a finalizer by first taking a varargsArray collector for 1584 // the number of local state arguments, and then appending the loop args as to-be-dropped arguments. 1585 MethodHandle[] finis = new MethodHandle[nargs]; 1586 MethodHandle genericFini = MethodHandles.dropArguments( 1587 varargsArray(nargs).asType(methodType(Object[].class, lArgTypes)), nargs, lArgTypes); 1588 Arrays.fill(finis, genericFini); 1589 // The predicate and step handles' signatures need to be extended. They currently just accept local state args; 1590 // append possibly missing local state args and loop args using dropArguments. 1591 for (int i = 0; i < nargs; ++i) { 1592 List<Class<?>> additionalLocalStateArgTypes = lArgTypes.subList(i + 1, nargs); 1593 preds[i] = MethodHandles.dropArguments( 1594 MethodHandles.dropArguments(preds[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes); 1595 steps[i] = MethodHandles.dropArguments( 1596 MethodHandles.dropArguments(steps[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes); 1597 } 1598 // Iterate over all of the predicates, using only one of them at a time. 1599 for (int i = 0; i < nargs; ++i) { 1600 MethodHandle[] usePreds; 1601 if (nargs == 1) { 1602 usePreds = preds; 1603 } else { 1604 // Create an all-null preds array, and only use one predicate in this iteration. The null entries will 1605 // be substituted with true predicates by the loop combinator. 1606 usePreds = new MethodHandle[nargs]; 1607 usePreds[i] = preds[i]; 1608 } 1609 // Go for it. 1610 if (verbosity >= 3) { 1611 System.out.println("calling loop for argument types " + lArgTypes + " with predicate at index " + i); 1612 if (verbosity >= 5) { 1613 System.out.println("predicates: " + Arrays.asList(usePreds)); 1614 } 1615 } 1616 MethodHandle[] preInits = new MethodHandle[nargs + 1]; 1617 MethodHandle[] prePreds = new MethodHandle[nargs + 1]; 1618 MethodHandle[] preSteps = new MethodHandle[nargs + 1]; 1619 MethodHandle[] preFinis = new MethodHandle[nargs + 1]; 1620 System.arraycopy(inits, 0, preInits, 1, nargs); 1621 System.arraycopy(usePreds, 0, prePreds, 0, nargs); // preds are offset by 1 for pre-checked loops 1622 System.arraycopy(steps, 0, preSteps, 1, nargs); 1623 System.arraycopy(finis, 0, preFinis, 0, nargs); // finis are also offset by 1 for pre-checked loops 1624 // Convert to clause-major form. 1625 MethodHandle[][] preClauses = new MethodHandle[nargs + 1][4]; 1626 MethodHandle[][] postClauses = new MethodHandle[nargs][4]; 1627 toClauseMajor(preClauses, preInits, preSteps, prePreds, preFinis); 1628 toClauseMajor(postClauses, inits, steps, usePreds, finis); 1629 MethodHandle pre = MethodHandles.loop(preClauses); 1630 MethodHandle post = MethodHandles.loop(postClauses); 1631 if (verbosity >= 6) { 1632 System.out.println("pre-handle: " + pre); 1633 } 1634 Object[] preResults = (Object[]) pre.invokeWithArguments(args); 1635 if (verbosity >= 4) { 1636 System.out.println("pre-checked: expected " + Arrays.asList(preCheckedResults[i]) + ", actual " + 1637 Arrays.asList(preResults)); 1638 } 1639 if (verbosity >= 6) { 1640 System.out.println("post-handle: " + post); 1641 } 1642 Object[] postResults = (Object[]) post.invokeWithArguments(args); 1643 if (verbosity >= 4) { 1644 System.out.println("post-checked: expected " + Arrays.asList(postCheckedResults[i]) + ", actual " + 1645 Arrays.asList(postResults)); 1646 } 1647 assertArrayEquals(preCheckedResults[i], preResults); 1648 assertArrayEquals(postCheckedResults[i], postResults); 1649 } 1650 } 1651 1652 static void toClauseMajor(MethodHandle[][] clauses, MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini) { 1653 for (int i = 0; i < clauses.length; ++i) { 1654 clauses[i][0] = init[i]; 1655 clauses[i][1] = step[i]; 1656 clauses[i][2] = pred[i]; 1657 clauses[i][3] = fini[i]; 1658 } 1659 } 1660 1661 @Test 1662 public void testThrowException() throws Throwable { 1663 CodeCacheOverflowProcessor.runMHTest(this::testThrowException0); 1664 } 1665 1666 public void testThrowException0() throws Throwable { 1667 if (CAN_SKIP_WORKING) return; 1668 startTest("throwException"); 1669 testThrowException(int.class, new ClassCastException("testing")); 1670 testThrowException(void.class, new java.io.IOException("testing")); 1671 testThrowException(String.class, new LinkageError("testing")); 1672 } 1673 1674 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable { 1675 countTest(); 1676 Class<? extends Throwable> exType = thrown.getClass(); 1677 MethodHandle target = MethodHandles.throwException(returnType, exType); 1678 //System.out.println("throwing with "+target+" : "+thrown); 1679 MethodType expectedType = MethodType.methodType(returnType, exType); 1680 assertEquals(expectedType, target.type()); 1681 target = target.asType(target.type().generic()); 1682 Throwable caught = null; 1683 try { 1684 Object res = target.invokeExact((Object) thrown); 1685 fail("got "+res+" instead of throwing "+thrown); 1686 } catch (Throwable ex) { 1687 if (ex != thrown) { 1688 if (ex instanceof Error) throw (Error)ex; 1689 if (ex instanceof RuntimeException) throw (RuntimeException)ex; 1690 } 1691 caught = ex; 1692 } 1693 assertSame(thrown, caught); 1694 } 1695 1696 @Test 1697 public void testTryFinally() throws Throwable { 1698 CodeCacheOverflowProcessor.runMHTest(this::testTryFinally0); 1699 } 1700 1701 public void testTryFinally0() throws Throwable { 1702 if (CAN_SKIP_WORKING) return; 1703 startTest("tryFinally"); 1704 String inputMessage = "returned"; 1705 String augmentedMessage = "augmented"; 1706 String thrownMessage = "thrown"; 1707 String rethrownMessage = "rethrown"; 1708 // Test these cases: 1709 // * target returns, cleanup passes through 1710 // * target returns, cleanup augments 1711 // * target throws, cleanup augments and returns 1712 // * target throws, cleanup augments and rethrows 1713 MethodHandle target = MethodHandles.identity(String.class); 1714 MethodHandle targetThrow = MethodHandles.dropArguments( 1715 MethodHandles.throwException(String.class, Exception.class).bindTo(new Exception(thrownMessage)), 0, String.class); 1716 MethodHandle cleanupPassThrough = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, 1717 Throwable.class, String.class); 1718 MethodHandle cleanupAugment = MethodHandles.dropArguments(MethodHandles.constant(String.class, augmentedMessage), 1719 0, Throwable.class, String.class, String.class); 1720 MethodHandle cleanupCatch = MethodHandles.dropArguments(MethodHandles.constant(String.class, thrownMessage), 0, 1721 Throwable.class, String.class, String.class); 1722 MethodHandle cleanupThrow = MethodHandles.dropArguments(MethodHandles.throwException(String.class, Exception.class). 1723 bindTo(new Exception(rethrownMessage)), 0, Throwable.class, String.class, String.class); 1724 testTryFinally(target, cleanupPassThrough, inputMessage, inputMessage, false); 1725 testTryFinally(target, cleanupAugment, inputMessage, augmentedMessage, false); 1726 testTryFinally(targetThrow, cleanupCatch, inputMessage, thrownMessage, true); 1727 testTryFinally(targetThrow, cleanupThrow, inputMessage, rethrownMessage, true); 1728 // Test the same cases as above for void targets and cleanups. 1729 MethodHandles.Lookup lookup = MethodHandles.lookup(); 1730 Class<?> C = this.getClass(); 1731 MethodType targetType = methodType(void.class, String[].class); 1732 MethodType cleanupType = methodType(void.class, Throwable.class, String[].class); 1733 MethodHandle vtarget = lookup.findStatic(C, "vtarget", targetType); 1734 MethodHandle vtargetThrow = lookup.findStatic(C, "vtargetThrow", targetType); 1735 MethodHandle vcleanupPassThrough = lookup.findStatic(C, "vcleanupPassThrough", cleanupType); 1736 MethodHandle vcleanupAugment = lookup.findStatic(C, "vcleanupAugment", cleanupType); 1737 MethodHandle vcleanupCatch = lookup.findStatic(C, "vcleanupCatch", cleanupType); 1738 MethodHandle vcleanupThrow = lookup.findStatic(C, "vcleanupThrow", cleanupType); 1739 testTryFinally(vtarget, vcleanupPassThrough, inputMessage, inputMessage, false); 1740 testTryFinally(vtarget, vcleanupAugment, inputMessage, augmentedMessage, false); 1741 testTryFinally(vtargetThrow, vcleanupCatch, inputMessage, thrownMessage, true); 1742 testTryFinally(vtargetThrow, vcleanupThrow, inputMessage, rethrownMessage, true); 1743 } 1744 1745 void testTryFinally(MethodHandle target, MethodHandle cleanup, String input, String msg, boolean mustCatch) 1746 throws Throwable { 1747 countTest(); 1748 MethodHandle tf = MethodHandles.tryFinally(target, cleanup); 1749 String result = null; 1750 boolean isVoid = target.type().returnType() == void.class; 1751 String[] argArray = new String[]{input}; 1752 try { 1753 if (isVoid) { 1754 tf.invoke(argArray); 1755 } else { 1756 result = (String) tf.invoke(input); 1757 } 1758 } catch (Throwable t) { 1759 assertTrue(mustCatch); 1760 assertEquals(msg, t.getMessage()); 1761 return; 1762 } 1763 assertFalse(mustCatch); 1764 if (isVoid) { 1765 assertEquals(msg, argArray[0]); 1766 } else { 1767 assertEquals(msg, result); 1768 } 1769 } 1770 1771 @Test 1772 public void testAsInterfaceInstance() throws Throwable { 1773 CodeCacheOverflowProcessor.runMHTest(this::testAsInterfaceInstance0); 1774 } 1775 1776 public void testAsInterfaceInstance0() throws Throwable { 1777 if (CAN_SKIP_WORKING) return; 1778 startTest("asInterfaceInstance"); 1779 Lookup lookup = MethodHandles.lookup(); 1780 // test typical case: Runnable.run 1781 { 1782 countTest(); 1783 if (verbosity >= 2) System.out.println("Runnable"); 1784 MethodType mt = MethodType.methodType(void.class); 1785 MethodHandle mh = lookup.findStatic(MethodHandlesGeneralTest.class, "runForRunnable", mt); 1786 Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh); 1787 proxy.run(); 1788 assertCalled("runForRunnable"); 1789 } 1790 // well known single-name overloaded interface: Appendable.append 1791 { 1792 countTest(); 1793 if (verbosity >= 2) System.out.println("Appendable"); 1794 ArrayList<List<?>> appendResults = new ArrayList<>(); 1795 MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class)); 1796 append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type 1797 MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); 1798 MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class); 1799 Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh); 1800 proxy.append("one"); 1801 proxy.append("two", 3, 4); 1802 proxy.append('5'); 1803 assertEquals(Arrays.asList(Arrays.asList("one"), 1804 Arrays.asList("two", 3, 4), 1805 Arrays.asList('5')), 1806 appendResults); 1807 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 1808 appendResults.clear(); 1809 Formatter formatter = new Formatter(proxy); 1810 String fmt = "foo str=%s char='%c' num=%d"; 1811 Object[] fmtArgs = { "str!", 'C', 42 }; 1812 String expect = String.format(fmt, fmtArgs); 1813 formatter.format(fmt, fmtArgs); 1814 String actual = ""; 1815 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 1816 for (List<?> l : appendResults) { 1817 Object x = l.get(0); 1818 switch (l.size()) { 1819 case 1: actual += x; continue; 1820 case 3: actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue; 1821 } 1822 actual += l; 1823 } 1824 if (verbosity >= 3) System.out.println("expect="+expect); 1825 if (verbosity >= 3) System.out.println("actual="+actual); 1826 assertEquals(expect, actual); 1827 } 1828 // test case of an single name which is overloaded: Fooable.foo(...) 1829 { 1830 if (verbosity >= 2) System.out.println("Fooable"); 1831 MethodHandle mh = lookup.findStatic(MethodHandlesGeneralTest.class, "fooForFooable", 1832 MethodType.methodType(Object.class, String.class, Object[].class)); 1833 Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh); 1834 for (Method m : Fooable.class.getDeclaredMethods()) { 1835 countTest(); 1836 assertSame("foo", m.getName()); 1837 if (verbosity > 3) 1838 System.out.println("calling "+m); 1839 MethodHandle invoker = lookup.unreflect(m); 1840 MethodType mt = invoker.type(); 1841 Class<?>[] types = mt.parameterArray(); 1842 types[0] = int.class; // placeholder 1843 Object[] args = randomArgs(types); 1844 args[0] = proxy; 1845 if (verbosity > 3) 1846 System.out.println("calling "+m+" on "+Arrays.asList(args)); 1847 Object result = invoker.invokeWithArguments(args); 1848 if (verbosity > 4) 1849 System.out.println("result = "+result); 1850 String name = "fooForFooable/"+args[1]; 1851 Object[] argTail = Arrays.copyOfRange(args, 2, args.length); 1852 assertCalled(name, argTail); 1853 assertEquals(result, logEntry(name, argTail)); 1854 } 1855 } 1856 // test processing of thrown exceptions: 1857 for (Throwable ex : new Throwable[] { new NullPointerException("ok"), 1858 new InternalError("ok"), 1859 new Throwable("fail"), 1860 new Exception("fail"), 1861 new MyCheckedException() 1862 }) { 1863 MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class); 1864 mh = MethodHandles.insertArguments(mh, 0, ex); 1865 WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh); 1866 try { 1867 countTest(); 1868 proxy.willThrow(); 1869 System.out.println("Failed to throw: "+ex); 1870 assertTrue(false); 1871 } catch (Throwable ex1) { 1872 if (verbosity > 3) { 1873 System.out.println("throw "+ex); 1874 System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1)); 1875 } 1876 if (ex instanceof RuntimeException || 1877 ex instanceof Error) { 1878 assertSame("must pass unchecked exception out without wrapping", ex, ex1); 1879 } else if (ex instanceof MyCheckedException) { 1880 assertSame("must pass declared exception out without wrapping", ex, ex1); 1881 } else { 1882 assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1); 1883 if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) { 1884 ex1.printStackTrace(System.out); 1885 } 1886 assertSame(ex, ex1.getCause()); 1887 UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1; 1888 } 1889 } 1890 } 1891 // Test error checking on bad interfaces: 1892 for (Class<?> nonSMI : new Class<?>[] { Object.class, 1893 String.class, 1894 CharSequence.class, 1895 java.io.Serializable.class, 1896 PrivateRunnable.class, 1897 Example.class }) { 1898 if (verbosity > 2) System.out.println(nonSMI.getName()); 1899 try { 1900 countTest(false); 1901 MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0)); 1902 assertTrue("Failed to throw on "+nonSMI.getName(), false); 1903 } catch (IllegalArgumentException ex) { 1904 if (verbosity > 2) System.out.println(nonSMI.getSimpleName()+": "+ex); 1905 // Object: java.lang.IllegalArgumentException: 1906 // not a public interface: java.lang.Object 1907 // String: java.lang.IllegalArgumentException: 1908 // not a public interface: java.lang.String 1909 // CharSequence: java.lang.IllegalArgumentException: 1910 // not a single-method interface: java.lang.CharSequence 1911 // Serializable: java.lang.IllegalArgumentException: 1912 // not a single-method interface: java.io.Serializable 1913 // PrivateRunnable: java.lang.IllegalArgumentException: 1914 // not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable 1915 // Example: java.lang.IllegalArgumentException: 1916 // not a public interface: test.java.lang.invoke.MethodHandlesTest$Example 1917 } 1918 } 1919 // Test error checking on interfaces with the wrong method type: 1920 for (Class<?> intfc : new Class<?>[] { Runnable.class /*arity 0*/, 1921 Fooable.class /*arity 1 & 2*/ }) { 1922 int badArity = 1; // known to be incompatible 1923 if (verbosity > 2) System.out.println(intfc.getName()); 1924 try { 1925 countTest(false); 1926 MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity)); 1927 assertTrue("Failed to throw on "+intfc.getName(), false); 1928 } catch (WrongMethodTypeException ex) { 1929 if (verbosity > 2) System.out.println(intfc.getSimpleName()+": "+ex); 1930 // Runnable: java.lang.invoke.WrongMethodTypeException: 1931 // cannot convert MethodHandle(Object)Object[] to ()void 1932 // Fooable: java.lang.invoke.WrongMethodTypeException: 1933 // cannot convert MethodHandle(Object)Object[] to (Object,String)Object 1934 } 1935 } 1936 } 1937 1938 @Test 1939 public void testInterfaceCast() throws Throwable { 1940 CodeCacheOverflowProcessor.runMHTest(this::testInterfaceCast0); 1941 } 1942 1943 public void testInterfaceCast0() throws Throwable { 1944 if (CAN_SKIP_WORKING) return; 1945 startTest("interfaceCast"); 1946 assert( (((Object)"foo") instanceof CharSequence)); 1947 assert(!(((Object)"foo") instanceof Iterable)); 1948 for (MethodHandle mh : new MethodHandle[]{ 1949 MethodHandles.identity(String.class), 1950 MethodHandles.identity(CharSequence.class), 1951 MethodHandles.identity(Iterable.class) 1952 }) { 1953 if (verbosity > 0) System.out.println("-- mh = "+mh); 1954 for (Class<?> ctype : new Class<?>[]{ 1955 Object.class, String.class, CharSequence.class, 1956 Number.class, Iterable.class 1957 }) { 1958 if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName()); 1959 // doret docast 1960 testInterfaceCast(mh, ctype, false, false); 1961 testInterfaceCast(mh, ctype, true, false); 1962 testInterfaceCast(mh, ctype, false, true); 1963 testInterfaceCast(mh, ctype, true, true); 1964 } 1965 } 1966 } 1967 1968 private static Class<?> i2o(Class<?> c) { 1969 return (c.isInterface() ? Object.class : c); 1970 } 1971 1972 public void testInterfaceCast(MethodHandle mh, Class<?> ctype, 1973 boolean doret, boolean docast) throws Throwable { 1974 MethodHandle mh0 = mh; 1975 if (verbosity > 1) 1976 System.out.println("mh="+mh+", ctype="+ctype.getName()+", doret="+doret+", docast="+docast); 1977 String normalRetVal = "normal return value"; 1978 MethodType mt = mh.type(); 1979 MethodType mt0 = mt; 1980 if (doret) mt = mt.changeReturnType(ctype); 1981 else mt = mt.changeParameterType(0, ctype); 1982 if (docast) mh = MethodHandles.explicitCastArguments(mh, mt); 1983 else mh = mh.asType(mt); 1984 assertEquals(mt, mh.type()); 1985 MethodType mt1 = mt; 1986 // this bit is needed to make the interface types disappear for invokeWithArguments: 1987 mh = MethodHandles.explicitCastArguments(mh, mt.generic()); 1988 Class<?>[] step = { 1989 mt1.parameterType(0), // param as passed to mh at first 1990 mt0.parameterType(0), // param after incoming cast 1991 mt0.returnType(), // return value before cast 1992 mt1.returnType(), // return value after outgoing cast 1993 }; 1994 // where might a checkCast occur? 1995 boolean[] checkCast = new boolean[step.length]; 1996 // the string value must pass each step without causing an exception 1997 if (!docast) { 1998 if (!doret) { 1999 if (step[0] != step[1]) 2000 checkCast[1] = true; // incoming value is cast 2001 } else { 2002 if (step[2] != step[3]) 2003 checkCast[3] = true; // outgoing value is cast 2004 } 2005 } 2006 boolean expectFail = false; 2007 for (int i = 0; i < step.length; i++) { 2008 Class<?> c = step[i]; 2009 if (!checkCast[i]) c = i2o(c); 2010 if (!c.isInstance(normalRetVal)) { 2011 if (verbosity > 3) 2012 System.out.println("expect failure at step "+i+" in "+Arrays.toString(step)+Arrays.toString(checkCast)); 2013 expectFail = true; 2014 break; 2015 } 2016 } 2017 countTest(!expectFail); 2018 if (verbosity > 2) 2019 System.out.println("expectFail="+expectFail+", mt="+mt); 2020 Object res; 2021 try { 2022 res = mh.invokeWithArguments(normalRetVal); 2023 } catch (Exception ex) { 2024 res = ex; 2025 } 2026 boolean sawFail = !(res instanceof String); 2027 if (sawFail != expectFail) { 2028 System.out.println("*** testInterfaceCast: mh0 = "+mh0); 2029 System.out.println(" retype using "+(docast ? "explicitCastArguments" : "asType")+" to "+mt+" => "+mh); 2030 System.out.println(" call returned "+res); 2031 System.out.println(" expected "+(expectFail ? "an exception" : normalRetVal)); 2032 } 2033 if (!expectFail) { 2034 assertFalse(res.toString(), sawFail); 2035 assertEquals(normalRetVal, res); 2036 } else { 2037 assertTrue(res.toString(), sawFail); 2038 } 2039 } 2040 2041 static Example userMethod(Object o, String s, int i) { 2042 called("userMethod", o, s, i); 2043 return null; 2044 } 2045 2046 @Test 2047 public void testUserClassInSignature() throws Throwable { 2048 CodeCacheOverflowProcessor.runMHTest(this::testUserClassInSignature0); 2049 } 2050 2051 public void testUserClassInSignature0() throws Throwable { 2052 if (CAN_SKIP_WORKING) return; 2053 startTest("testUserClassInSignature"); 2054 Lookup lookup = MethodHandles.lookup(); 2055 String name; MethodType mt; MethodHandle mh; 2056 Object[] args; 2057 2058 // Try a static method. 2059 name = "userMethod"; 2060 mt = MethodType.methodType(Example.class, Object.class, String.class, int.class); 2061 mh = lookup.findStatic(lookup.lookupClass(), name, mt); 2062 assertEquals(mt, mh.type()); 2063 assertEquals(Example.class, mh.type().returnType()); 2064 args = randomArgs(mh.type().parameterArray()); 2065 mh.invokeWithArguments(args); 2066 assertCalled(name, args); 2067 2068 // Try a virtual method. 2069 name = "v2"; 2070 mt = MethodType.methodType(Object.class, Object.class, int.class); 2071 mh = lookup.findVirtual(Example.class, name, mt); 2072 assertEquals(mt, mh.type().dropParameterTypes(0,1)); 2073 assertTrue(mh.type().parameterList().contains(Example.class)); 2074 args = randomArgs(mh.type().parameterArray()); 2075 mh.invokeWithArguments(args); 2076 assertCalled(name, args); 2077 } 2078 2079 static void runForRunnable() { 2080 called("runForRunnable"); 2081 } 2082 2083 public interface Fooable { 2084 // overloads: 2085 Object foo(Object x, String y); 2086 List<?> foo(String x, int y); 2087 Object foo(String x); 2088 } 2089 2090 static Object fooForFooable(String x, Object... y) { 2091 return called("fooForFooable/"+x, y); 2092 } 2093 2094 @SuppressWarnings("serial") // not really a public API, just a test case 2095 public static class MyCheckedException extends Exception { 2096 } 2097 2098 public interface WillThrow { 2099 void willThrow() throws MyCheckedException; 2100 } 2101 2102 /*non-public*/ interface PrivateRunnable { 2103 public void run(); 2104 } 2105 2106 @Test 2107 public void testRunnableProxy() throws Throwable { 2108 CodeCacheOverflowProcessor.runMHTest(this::testRunnableProxy0); 2109 } 2110 2111 public void testRunnableProxy0() throws Throwable { 2112 if (CAN_SKIP_WORKING) return; 2113 startTest("testRunnableProxy"); 2114 MethodHandles.Lookup lookup = MethodHandles.lookup(); 2115 MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class)); 2116 Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run); 2117 testRunnableProxy(r); 2118 assertCalled("runForRunnable"); 2119 } 2120 2121 private static void testRunnableProxy(Runnable r) { 2122 //7058630: JSR 292 method handle proxy violates contract for Object methods 2123 r.run(); 2124 Object o = r; 2125 r = null; 2126 boolean eq = (o == o); 2127 int hc = System.identityHashCode(o); 2128 String st = o.getClass().getName() + "@" + Integer.toHexString(hc); 2129 Object expect = Arrays.asList(st, eq, hc); 2130 if (verbosity >= 2) System.out.println("expect st/eq/hc = "+expect); 2131 Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode()); 2132 if (verbosity >= 2) System.out.println("actual st/eq/hc = "+actual); 2133 assertEquals(expect, actual); 2134 } 2135 }