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