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