1 /* 2 * Copyright (c) 2018, 2019, 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.testCasesFor(testMode)) { 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 isStatic; 669 Class<?> fclass; 670 String fname; 671 Class<?> ftype; 672 Field f = (fieldRef instanceof Field ? (Field)fieldRef : null); 673 if (f != null) { 674 isStatic = Modifier.isStatic(f.getModifiers()); 675 fclass = f.getDeclaringClass(); 676 fname = f.getName(); 677 ftype = f.getType(); 678 } else { 679 Object[] scnt = (Object[]) fieldRef; 680 isStatic = (Boolean) scnt[0]; 681 fclass = (Class<?>) scnt[1]; 682 fname = (String) scnt[2]; 683 ftype = (Class<?>) scnt[3]; 684 try { 685 f = fclass.getDeclaredField(fname); 686 } catch (ReflectiveOperationException ex) { 687 f = null; 688 } 689 } 690 if (!testModeMatches(testMode, isStatic)) return; 691 if (f == null && testMode == TEST_UNREFLECT) return; 692 if (testNPE && isStatic) return; 693 countTest(positive); 694 MethodType expType; 695 if (isGetter) 696 expType = MethodType.methodType(ftype, HasFields.class); 697 else 698 expType = MethodType.methodType(void.class, HasFields.class, ftype); 699 if (isStatic) expType = expType.dropParameterTypes(0, 1); 700 Exception noAccess = null; 701 MethodHandle mh; 702 try { 703 switch (testMode0 & ~(TEST_BOUND | TEST_NPE)) { 704 case TEST_UNREFLECT: mh = lookup.unreflectGetter(f); break; 705 case TEST_FIND_FIELD: mh = lookup.findGetter(fclass, fname, ftype); break; 706 case TEST_FIND_STATIC: mh = lookup.findStaticGetter(fclass, fname, ftype); break; 707 case TEST_SETTER| 708 TEST_UNREFLECT: mh = lookup.unreflectSetter(f); break; 709 case TEST_SETTER| 710 TEST_FIND_FIELD: mh = lookup.findSetter(fclass, fname, ftype); break; 711 case TEST_SETTER| 712 TEST_FIND_STATIC: mh = lookup.findStaticSetter(fclass, fname, ftype); break; 713 default: 714 throw new InternalError("testMode="+testMode); 715 } 716 } catch (ReflectiveOperationException ex) { 717 mh = null; 718 noAccess = ex; 719 assertExceptionClass( 720 (fname.contains("bogus")) 721 ? NoSuchFieldException.class 722 : IllegalAccessException.class, 723 noAccess); 724 if (verbosity >= 5) ex.printStackTrace(System.out); 725 } 726 if (verbosity >= 3) 727 System.out.format("%s%s %s.%s/%s => %s %s%n", 728 (testMode0 & TEST_UNREFLECT) != 0 729 ? "unreflect" 730 : "find" + ((testMode0 & TEST_FIND_STATIC) != 0 ? "Static" : ""), 731 (isGetter ? "Getter" : "Setter"), 732 fclass.getName(), fname, ftype, mh, 733 (noAccess == null ? "" : " !! "+noAccess)); 734 // negative test case and expected noAccess, then done. 735 if (!positive && noAccess != null) return; 736 // positive test case but found noAccess, then error 737 if (positive && !testNPE && noAccess != null) throw new RuntimeException(noAccess); 738 assertEquals(positive0 ? "positive test" : "negative test erroneously passed", positive0, mh != null); 739 if (!positive && !testNPE) return; // negative access test failed as expected 740 assertEquals((isStatic ? 0 : 1)+(isGetter ? 0 : 1), mh.type().parameterCount()); 741 assertSame(mh.type(), expType); 742 //assertNameStringContains(mh, fname); // This does not hold anymore with LFs 743 HasFields fields = new HasFields(); 744 HasFields fieldsForMH = fields; 745 if (testNPE) fieldsForMH = null; // perturb MH argument to elicit expected error 746 if (doBound) 747 mh = mh.bindTo(fieldsForMH); 748 Object sawValue; 749 Class<?> vtype = ftype; 750 if (ftype != int.class) vtype = Object.class; 751 if (isGetter) { 752 mh = mh.asType(mh.type().generic() 753 .changeReturnType(vtype)); 754 } else { 755 int last = mh.type().parameterCount() - 1; 756 mh = mh.asType(mh.type().generic() 757 .changeReturnType(void.class) 758 .changeParameterType(last, vtype)); 759 } 760 if (f != null && f.getDeclaringClass() == HasFields.class) { 761 assertEquals(f.get(fields), value); // clean to start with 762 } 763 Throwable caughtEx = null; 764 // non-final field and setAccessible(true) on instance field will have write access 765 boolean writeAccess = !Modifier.isFinal(f.getModifiers()) || 766 (!Modifier.isStatic(f.getModifiers()) && f.isAccessible()); 767 if (isGetter) { 768 Object expValue = value; 769 for (int i = 0; i <= 1; i++) { 770 sawValue = null; // make DA rules happy under try/catch 771 try { 772 if (isStatic || doBound) { 773 if (ftype == int.class) 774 sawValue = (int) mh.invokeExact(); // do these exactly 775 else 776 sawValue = mh.invokeExact(); 777 } else { 778 if (ftype == int.class) 779 sawValue = (int) mh.invokeExact((Object) fieldsForMH); 780 else 781 sawValue = mh.invokeExact((Object) fieldsForMH); 782 } 783 } catch (RuntimeException ex) { 784 if (ex instanceof NullPointerException && testNPE) { 785 caughtEx = ex; 786 break; 787 } 788 } 789 assertEquals(sawValue, expValue); 790 if (f != null && f.getDeclaringClass() == HasFields.class && writeAccess) { 791 Object random = randomArg(ftype); 792 f.set(fields, random); 793 expValue = random; 794 } else { 795 break; 796 } 797 } 798 } else { 799 for (int i = 0; i <= 1; i++) { 800 Object putValue = randomArg(ftype); 801 try { 802 if (isStatic || doBound) { 803 if (ftype == int.class) 804 mh.invokeExact((int)putValue); // do these exactly 805 else 806 mh.invokeExact(putValue); 807 } else { 808 if (ftype == int.class) 809 mh.invokeExact((Object) fieldsForMH, (int)putValue); 810 else 811 mh.invokeExact((Object) fieldsForMH, putValue); 812 } 813 } catch (RuntimeException ex) { 814 if (ex instanceof NullPointerException && testNPE) { 815 caughtEx = ex; 816 break; 817 } 818 } 819 if (f != null && f.getDeclaringClass() == HasFields.class) { 820 assertEquals(f.get(fields), putValue); 821 } 822 } 823 } 824 if (f != null && f.getDeclaringClass() == HasFields.class && writeAccess) { 825 f.set(fields, value); // put it back if it has write access 826 } 827 if (testNPE) { 828 if (caughtEx == null || !(caughtEx instanceof NullPointerException)) 829 throw new RuntimeException("failed to catch NPE exception"+(caughtEx == null ? " (caughtEx=null)" : ""), caughtEx); 830 caughtEx = null; // nullify expected exception 831 } 832 if (caughtEx != null) { 833 throw new RuntimeException("unexpected exception", caughtEx); 834 } 835 } 836 837 @Test 838 public void testUnreflectSetter() throws Throwable { 839 CodeCacheOverflowProcessor.runMHTest(this::testUnreflectSetter0); 840 } 841 842 public void testUnreflectSetter0() throws Throwable { 843 if (CAN_SKIP_WORKING) return; 844 startTest("unreflectSetter"); 845 testSetter(TEST_UNREFLECT); 846 } 847 848 @Test 849 public void testFindSetter() throws Throwable { 850 CodeCacheOverflowProcessor.runMHTest(this::testFindSetter0); 851 } 852 853 public void testFindSetter0() throws Throwable { 854 if (CAN_SKIP_WORKING) return; 855 startTest("findSetter"); 856 testSetter(TEST_FIND_FIELD); 857 testSetter(TEST_FIND_FIELD | TEST_BOUND); 858 } 859 860 @Test 861 public void testFindStaticSetter() throws Throwable { 862 CodeCacheOverflowProcessor.runMHTest(this::testFindStaticSetter0); 863 } 864 865 public void testFindStaticSetter0() throws Throwable { 866 if (CAN_SKIP_WORKING) return; 867 startTest("findStaticSetter"); 868 testSetter(TEST_FIND_STATIC); 869 } 870 871 public void testSetter(int testMode) throws Throwable { 872 Lookup lookup = PRIVATE; // FIXME: test more lookups than this one 873 startTest("testSetter"); 874 for (Object[] c : HasFields.testCasesFor(testMode|TEST_SETTER)) { 875 boolean positive = (c[1] != Error.class); 876 testSetter(positive, lookup, c[0], c[1], testMode); 877 if (positive) 878 testSetter(positive, lookup, c[0], c[1], testMode | TEST_NPE); 879 } 880 for (int isStaticN = 0; isStaticN <= 1; isStaticN++) { 881 testSetter(false, lookup, 882 new Object[]{ (isStaticN != 0), System.class, "bogus", char.class }, 883 null, testMode); 884 } 885 } 886 887 public void testSetter(boolean positive, MethodHandles.Lookup lookup, 888 Object fieldRef, Object value, int testMode) throws Throwable { 889 testAccessor(positive, lookup, fieldRef, value, testMode | TEST_SETTER); 890 } 891 892 @Test 893 public void testArrayElementGetter() throws Throwable { 894 CodeCacheOverflowProcessor.runMHTest(this::testArrayElementGetter0); 895 } 896 897 public void testArrayElementGetter0() throws Throwable { 898 if (CAN_SKIP_WORKING) return; 899 startTest("arrayElementGetter"); 900 testArrayElementGetterSetter(false); 901 } 902 903 @Test 904 public void testArrayElementSetter() throws Throwable { 905 CodeCacheOverflowProcessor.runMHTest(this::testArrayElementSetter0); 906 } 907 908 public void testArrayElementSetter0() throws Throwable { 909 if (CAN_SKIP_WORKING) return; 910 startTest("arrayElementSetter"); 911 testArrayElementGetterSetter(true); 912 } 913 914 private static final int TEST_ARRAY_NONE = 0, TEST_ARRAY_NPE = 1, TEST_ARRAY_OOB = 2, TEST_ARRAY_ASE = 3; 915 916 public void testArrayElementGetterSetter(boolean testSetter) throws Throwable { 917 testArrayElementGetterSetter(testSetter, TEST_ARRAY_NONE); 918 } 919 920 @Test 921 public void testArrayElementErrors() throws Throwable { 922 CodeCacheOverflowProcessor.runMHTest(this::testArrayElementErrors0); 923 } 924 925 public void testArrayElementErrors0() throws Throwable { 926 if (CAN_SKIP_WORKING) return; 927 startTest("arrayElementErrors"); 928 testArrayElementGetterSetter(false, TEST_ARRAY_NPE); 929 testArrayElementGetterSetter(true, TEST_ARRAY_NPE); 930 testArrayElementGetterSetter(false, TEST_ARRAY_OOB); 931 testArrayElementGetterSetter(true, TEST_ARRAY_OOB); 932 testArrayElementGetterSetter(new Object[10], true, TEST_ARRAY_ASE); 933 testArrayElementGetterSetter(new Example[10], true, TEST_ARRAY_ASE); 934 testArrayElementGetterSetter(new IntExample[10], true, TEST_ARRAY_ASE); 935 } 936 937 public void testArrayElementGetterSetter(boolean testSetter, int negTest) throws Throwable { 938 testArrayElementGetterSetter(new String[10], testSetter, negTest); 939 testArrayElementGetterSetter(new Iterable<?>[10], testSetter, negTest); 940 testArrayElementGetterSetter(new Example[10], testSetter, negTest); 941 testArrayElementGetterSetter(new IntExample[10], testSetter, negTest); 942 testArrayElementGetterSetter(new Object[10], testSetter, negTest); 943 testArrayElementGetterSetter(new boolean[10], testSetter, negTest); 944 testArrayElementGetterSetter(new byte[10], testSetter, negTest); 945 testArrayElementGetterSetter(new char[10], testSetter, negTest); 946 testArrayElementGetterSetter(new short[10], testSetter, negTest); 947 testArrayElementGetterSetter(new int[10], testSetter, negTest); 948 testArrayElementGetterSetter(new float[10], testSetter, negTest); 949 testArrayElementGetterSetter(new long[10], testSetter, negTest); 950 testArrayElementGetterSetter(new double[10], testSetter, negTest); 951 } 952 953 public void testArrayElementGetterSetter(Object array, boolean testSetter, int negTest) throws Throwable { 954 boolean positive = (negTest == TEST_ARRAY_NONE); 955 int length = Array.getLength(array); 956 Class<?> arrayType = array.getClass(); 957 Class<?> elemType = arrayType.getComponentType(); 958 Object arrayToMH = array; 959 // this stanza allows negative tests to make argument perturbations: 960 switch (negTest) { 961 case TEST_ARRAY_NPE: 962 arrayToMH = null; 963 break; 964 case TEST_ARRAY_OOB: 965 assert(length > 0); 966 arrayToMH = Array.newInstance(elemType, 0); 967 break; 968 case TEST_ARRAY_ASE: 969 assert(testSetter && !elemType.isPrimitive()); 970 if (elemType == Object.class) 971 arrayToMH = new StringBuffer[length]; // very random subclass of Object! 972 else if (elemType == Example.class) 973 arrayToMH = new SubExample[length]; 974 else if (elemType == IntExample.class) 975 arrayToMH = new SubIntExample[length]; 976 else 977 return; // can't make an ArrayStoreException test 978 assert(arrayType.isInstance(arrayToMH)) 979 : Arrays.asList(arrayType, arrayToMH.getClass(), testSetter, negTest); 980 break; 981 } 982 countTest(positive); 983 if (verbosity > 2) System.out.println("array type = "+array.getClass().getComponentType().getName()+"["+length+"]"+(positive ? "" : " negative test #"+negTest+" using "+Arrays.deepToString(new Object[]{arrayToMH}))); 984 MethodType expType = !testSetter 985 ? MethodType.methodType(elemType, arrayType, int.class) 986 : MethodType.methodType(void.class, arrayType, int.class, elemType); 987 MethodHandle mh = !testSetter 988 ? MethodHandles.arrayElementGetter(arrayType) 989 : MethodHandles.arrayElementSetter(arrayType); 990 assertSame(mh.type(), expType); 991 if (elemType != int.class && elemType != boolean.class) { 992 MethodType gtype = mh.type().generic().changeParameterType(1, int.class); 993 if (testSetter) gtype = gtype.changeReturnType(void.class); 994 mh = mh.asType(gtype); 995 } 996 Object sawValue, expValue; 997 List<Object> model = array2list(array); 998 Throwable caughtEx = null; 999 for (int i = 0; i < length; i++) { 1000 // update array element 1001 Object random = randomArg(elemType); 1002 model.set(i, random); 1003 if (testSetter) { 1004 try { 1005 if (elemType == int.class) 1006 mh.invokeExact((int[]) arrayToMH, i, (int)random); 1007 else if (elemType == boolean.class) 1008 mh.invokeExact((boolean[]) arrayToMH, i, (boolean)random); 1009 else 1010 mh.invokeExact(arrayToMH, i, random); 1011 } catch (RuntimeException ex) { 1012 caughtEx = ex; 1013 break; 1014 } 1015 assertEquals(model, array2list(array)); 1016 } else { 1017 Array.set(array, i, random); 1018 } 1019 if (verbosity >= 5) { 1020 List<Object> array2list = array2list(array); 1021 System.out.println("a["+i+"]="+random+" => "+array2list); 1022 if (!array2list.equals(model)) 1023 System.out.println("*** != "+model); 1024 } 1025 // observe array element 1026 sawValue = Array.get(array, i); 1027 if (!testSetter) { 1028 expValue = sawValue; 1029 try { 1030 if (elemType == int.class) 1031 sawValue = (int) mh.invokeExact((int[]) arrayToMH, i); 1032 else if (elemType == boolean.class) 1033 sawValue = (boolean) mh.invokeExact((boolean[]) arrayToMH, i); 1034 else 1035 sawValue = mh.invokeExact(arrayToMH, i); 1036 } catch (RuntimeException ex) { 1037 caughtEx = ex; 1038 break; 1039 } 1040 assertEquals(sawValue, expValue); 1041 assertEquals(model, array2list(array)); 1042 } 1043 } 1044 if (!positive) { 1045 if (caughtEx == null) 1046 throw new RuntimeException("failed to catch exception for negTest="+negTest); 1047 // test the kind of exception 1048 Class<?> reqType = null; 1049 switch (negTest) { 1050 case TEST_ARRAY_ASE: reqType = ArrayStoreException.class; break; 1051 case TEST_ARRAY_OOB: reqType = ArrayIndexOutOfBoundsException.class; break; 1052 case TEST_ARRAY_NPE: reqType = NullPointerException.class; break; 1053 default: assert(false); 1054 } 1055 if (reqType.isInstance(caughtEx)) { 1056 caughtEx = null; // nullify expected exception 1057 } 1058 } 1059 if (caughtEx != null) { 1060 throw new RuntimeException("unexpected exception", caughtEx); 1061 } 1062 } 1063 1064 List<Object> array2list(Object array) { 1065 int length = Array.getLength(array); 1066 ArrayList<Object> model = new ArrayList<>(length); 1067 for (int i = 0; i < length; i++) 1068 model.add(Array.get(array, i)); 1069 return model; 1070 } 1071 1072 @Test 1073 public void testConvertArguments() throws Throwable { 1074 CodeCacheOverflowProcessor.runMHTest(this::testConvertArguments0); 1075 } 1076 1077 public void testConvertArguments0() throws Throwable { 1078 if (CAN_SKIP_WORKING) return; 1079 startTest("convertArguments"); 1080 testConvert(Callee.ofType(1), null, "id", int.class); 1081 testConvert(Callee.ofType(1), null, "id", String.class); 1082 testConvert(Callee.ofType(1), null, "id", Integer.class); 1083 testConvert(Callee.ofType(1), null, "id", short.class); 1084 testConvert(Callee.ofType(1), null, "id", char.class); 1085 testConvert(Callee.ofType(1), null, "id", byte.class); 1086 } 1087 1088 void testConvert(MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1089 testConvert(true, id, rtype, name, params); 1090 } 1091 1092 void testConvert(boolean positive, 1093 MethodHandle id, Class<?> rtype, String name, Class<?>... params) throws Throwable { 1094 countTest(positive); 1095 MethodType idType = id.type(); 1096 if (rtype == null) rtype = idType.returnType(); 1097 for (int i = 0; i < params.length; i++) { 1098 if (params[i] == null) params[i] = idType.parameterType(i); 1099 } 1100 // simulate the pairwise conversion 1101 MethodType newType = MethodType.methodType(rtype, params); 1102 Object[] args = randomArgs(newType.parameterArray()); 1103 Object[] convArgs = args.clone(); 1104 for (int i = 0; i < args.length; i++) { 1105 Class<?> src = newType.parameterType(i); 1106 Class<?> dst = idType.parameterType(i); 1107 if (src != dst) 1108 convArgs[i] = castToWrapper(convArgs[i], dst); 1109 } 1110 Object convResult = id.invokeWithArguments(convArgs); 1111 { 1112 Class<?> dst = newType.returnType(); 1113 Class<?> src = idType.returnType(); 1114 if (src != dst) 1115 convResult = castToWrapper(convResult, dst); 1116 } 1117 MethodHandle target = null; 1118 RuntimeException error = null; 1119 try { 1120 target = id.asType(newType); 1121 } catch (WrongMethodTypeException ex) { 1122 error = ex; 1123 } 1124 if (verbosity >= 3) 1125 System.out.println("convert "+id+ " to "+newType+" => "+target 1126 +(error == null ? "" : " !! "+error)); 1127 if (positive && error != null) throw error; 1128 assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null); 1129 if (!positive) return; // negative test failed as expected 1130 assertEquals(newType, target.type()); 1131 printCalled(target, id.toString(), args); 1132 Object result = target.invokeWithArguments(args); 1133 assertCalled(name, convArgs); 1134 assertEquals(convResult, result); 1135 if (verbosity >= 1) 1136 System.out.print(':'); 1137 } 1138 1139 @Test 1140 public void testVarargsCollector() throws Throwable { 1141 CodeCacheOverflowProcessor.runMHTest(this::testVarargsCollector0); 1142 } 1143 1144 public void testVarargsCollector0() throws Throwable { 1145 if (CAN_SKIP_WORKING) return; 1146 startTest("varargsCollector"); 1147 MethodHandle vac0 = PRIVATE.findStatic(MethodHandlesTest.class, "called", 1148 MethodType.methodType(Object.class, String.class, Object[].class)); 1149 vac0 = vac0.bindTo("vac"); 1150 MethodHandle vac = vac0.asVarargsCollector(Object[].class); 1151 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1152 testConvert(true, vac.asType(MethodType.genericMethodType(0)), null, "vac"); 1153 for (Class<?> at : new Class<?>[] { Object.class, String.class, Integer.class }) { 1154 testConvert(true, vac.asType(MethodType.genericMethodType(1)), null, "vac", at); 1155 testConvert(true, vac.asType(MethodType.genericMethodType(2)), null, "vac", at, at); 1156 } 1157 } 1158 1159 @Test 1160 public void testFilterReturnValue() throws Throwable { 1161 CodeCacheOverflowProcessor.runMHTest(this::testFilterReturnValue0); 1162 } 1163 1164 public void testFilterReturnValue0() throws Throwable { 1165 if (CAN_SKIP_WORKING) return; 1166 startTest("filterReturnValue"); 1167 Class<?> classOfVCList = varargsList(1).invokeWithArguments(0).getClass(); 1168 assertTrue(List.class.isAssignableFrom(classOfVCList)); 1169 for (int nargs = 0; nargs <= 3; nargs++) { 1170 for (Class<?> rtype : new Class<?>[] { Object.class, 1171 List.class, 1172 int.class, 1173 byte.class, 1174 long.class, 1175 CharSequence.class, 1176 String.class }) { 1177 testFilterReturnValue(nargs, rtype); 1178 } 1179 } 1180 } 1181 1182 void testFilterReturnValue(int nargs, Class<?> rtype) throws Throwable { 1183 countTest(); 1184 MethodHandle target = varargsList(nargs, rtype); 1185 MethodHandle filter; 1186 if (List.class.isAssignableFrom(rtype) || rtype.isAssignableFrom(List.class)) 1187 filter = varargsList(1); // add another layer of list-ness 1188 else 1189 filter = MethodHandles.identity(rtype); 1190 filter = filter.asType(MethodType.methodType(target.type().returnType(), rtype)); 1191 Object[] argsToPass = randomArgs(nargs, Object.class); 1192 if (verbosity >= 3) 1193 System.out.println("filter "+target+" to "+rtype.getSimpleName()+" with "+filter); 1194 MethodHandle target2 = MethodHandles.filterReturnValue(target, filter); 1195 if (verbosity >= 4) 1196 System.out.println("filtered target: "+target2); 1197 // Simulate expected effect of filter on return value: 1198 Object unfiltered = target.invokeWithArguments(argsToPass); 1199 Object expected = filter.invokeWithArguments(unfiltered); 1200 if (verbosity >= 4) 1201 System.out.println("unfiltered: "+unfiltered+" : "+unfiltered.getClass().getSimpleName()); 1202 if (verbosity >= 4) 1203 System.out.println("expected: "+expected+" : "+expected.getClass().getSimpleName()); 1204 Object result = target2.invokeWithArguments(argsToPass); 1205 if (verbosity >= 3) 1206 System.out.println("result: "+result+" : "+result.getClass().getSimpleName()); 1207 if (!expected.equals(result)) 1208 System.out.println("*** fail at n/rt = "+nargs+"/"+rtype.getSimpleName()+": "+ 1209 Arrays.asList(argsToPass)+" => "+result+" != "+expected); 1210 assertEquals(expected, result); 1211 } 1212 1213 @Test 1214 public void testFilterArguments() throws Throwable { 1215 CodeCacheOverflowProcessor.runMHTest(this::testFilterArguments0); 1216 } 1217 1218 public void testFilterArguments0() throws Throwable { 1219 if (CAN_SKIP_WORKING) return; 1220 startTest("filterArguments"); 1221 for (int nargs = 1; nargs <= 6; nargs++) { 1222 for (int pos = 0; pos < nargs; pos++) { 1223 testFilterArguments(nargs, pos); 1224 } 1225 } 1226 } 1227 1228 void testFilterArguments(int nargs, int pos) throws Throwable { 1229 countTest(); 1230 MethodHandle target = varargsList(nargs); 1231 MethodHandle filter = varargsList(1); 1232 filter = filter.asType(filter.type().generic()); 1233 Object[] argsToPass = randomArgs(nargs, Object.class); 1234 if (verbosity >= 3) 1235 System.out.println("filter "+target+" at "+pos+" with "+filter); 1236 MethodHandle target2 = MethodHandles.filterArguments(target, pos, filter); 1237 // Simulate expected effect of filter on arglist: 1238 Object[] filteredArgs = argsToPass.clone(); 1239 filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]); 1240 List<Object> expected = Arrays.asList(filteredArgs); 1241 Object result = target2.invokeWithArguments(argsToPass); 1242 if (verbosity >= 3) 1243 System.out.println("result: "+result); 1244 if (!expected.equals(result)) 1245 System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected); 1246 assertEquals(expected, result); 1247 } 1248 1249 @Test 1250 public void testCollectArguments() throws Throwable { 1251 CodeCacheOverflowProcessor.runMHTest(this::testCollectArguments0); 1252 } 1253 1254 public void testCollectArguments0() throws Throwable { 1255 if (CAN_SKIP_WORKING) return; 1256 startTest("collectArguments"); 1257 testFoldOrCollectArguments(true, false); 1258 } 1259 1260 @Test 1261 public void testFoldArguments() throws Throwable { 1262 CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments0); 1263 CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments1); 1264 } 1265 1266 public void testFoldArguments0() throws Throwable { 1267 if (CAN_SKIP_WORKING) return; 1268 startTest("foldArguments"); 1269 testFoldOrCollectArguments(false, false); 1270 } 1271 1272 public void testFoldArguments1() throws Throwable { 1273 if (CAN_SKIP_WORKING) return; 1274 startTest("foldArguments/pos"); 1275 testFoldOrCollectArguments(false, true); 1276 } 1277 1278 void testFoldOrCollectArguments(boolean isCollect, boolean withFoldPos) throws Throwable { 1279 assert !(isCollect && withFoldPos); // exclude illegal argument combination 1280 for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) { 1281 for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) { 1282 int maxArity = 10; 1283 if (collectType != String.class) maxArity = 5; 1284 if (lastType != Object.class) maxArity = 4; 1285 for (int nargs = 0; nargs <= maxArity; nargs++) { 1286 ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class)); 1287 int maxMix = 20; 1288 if (collectType != Object.class) maxMix = 0; 1289 Map<Object,Integer> argTypesSeen = new HashMap<>(); 1290 for (int mix = 0; mix <= maxMix; mix++) { 1291 if (!mixArgs(argTypes, mix, argTypesSeen)) continue; 1292 for (int collect = 0; collect <= nargs; collect++) { 1293 for (int pos = 0; pos <= nargs - collect; pos++) { 1294 testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect, withFoldPos); 1295 } 1296 } 1297 } 1298 } 1299 } 1300 } 1301 } 1302 1303 boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) { 1304 assert(mix >= 0); 1305 if (mix == 0) return true; // no change 1306 if ((mix >>> argTypes.size()) != 0) return false; 1307 for (int i = 0; i < argTypes.size(); i++) { 1308 if (i >= 31) break; 1309 boolean bit = (mix & (1 << i)) != 0; 1310 if (bit) { 1311 Class<?> type = argTypes.get(i); 1312 if (type == Object.class) 1313 type = String.class; 1314 else if (type == String.class) 1315 type = int.class; 1316 else 1317 type = Object.class; 1318 argTypes.set(i, type); 1319 } 1320 } 1321 Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix); 1322 if (prev != null) { 1323 if (verbosity >= 4) System.out.println("mix "+prev+" repeated "+mix+": "+argTypes); 1324 return false; 1325 } 1326 if (verbosity >= 3) System.out.println("mix "+mix+" = "+argTypes); 1327 return true; 1328 } 1329 1330 void testFoldOrCollectArguments(List<Class<?>> argTypes, // argument types minus the inserted combineType 1331 int pos, int fold, // position and length of the folded arguments 1332 Class<?> combineType, // type returned from the combiner 1333 Class<?> lastType, // type returned from the target 1334 boolean isCollect, 1335 boolean withFoldPos) throws Throwable { 1336 int nargs = argTypes.size(); 1337 if (pos != 0 && !isCollect && !withFoldPos) return; // test MethodHandles.foldArguments(MH,MH) only for pos=0 1338 countTest(); 1339 List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold); 1340 List<Class<?>> targetArgTypes = new ArrayList<>(argTypes); 1341 if (isCollect) // does target see arg[pos..pos+cc-1]? 1342 targetArgTypes.subList(pos, pos + fold).clear(); 1343 if (combineType != void.class) 1344 targetArgTypes.add(pos, combineType); 1345 MethodHandle target = varargsList(targetArgTypes, lastType); 1346 MethodHandle combine = varargsList(combineArgTypes, combineType); 1347 List<Object> argsToPass = Arrays.asList(randomArgs(argTypes)); 1348 if (verbosity >= 3) 1349 System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine); 1350 MethodHandle target2; 1351 if (isCollect) 1352 target2 = MethodHandles.collectArguments(target, pos, combine); 1353 else 1354 target2 = withFoldPos ? MethodHandles.foldArguments(target, pos, combine) : MethodHandles.foldArguments(target, combine); 1355 // Simulate expected effect of combiner on arglist: 1356 List<Object> expectedList = new ArrayList<>(argsToPass); 1357 List<Object> argsToFold = expectedList.subList(pos, pos + fold); 1358 if (verbosity >= 3) 1359 System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2); 1360 Object foldedArgs = combine.invokeWithArguments(argsToFold); 1361 if (isCollect) 1362 argsToFold.clear(); 1363 if (combineType != void.class) 1364 argsToFold.add(0, foldedArgs); 1365 Object result = target2.invokeWithArguments(argsToPass); 1366 if (verbosity >= 3) 1367 System.out.println("result: "+result); 1368 Object expected = target.invokeWithArguments(expectedList); 1369 if (!expected.equals(result)) 1370 System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected); 1371 assertEquals(expected, result); 1372 } 1373 1374 @Test 1375 public void testDropArguments() throws Throwable { 1376 CodeCacheOverflowProcessor.runMHTest(this::testDropArguments0); 1377 } 1378 1379 public void testDropArguments0() throws Throwable { 1380 if (CAN_SKIP_WORKING) return; 1381 startTest("dropArguments"); 1382 for (int nargs = 0; nargs <= 4; nargs++) { 1383 for (int drop = 1; drop <= 4; drop++) { 1384 for (int pos = 0; pos <= nargs; pos++) { 1385 testDropArguments(nargs, pos, drop); 1386 } 1387 } 1388 } 1389 } 1390 1391 void testDropArguments(int nargs, int pos, int drop) throws Throwable { 1392 countTest(); 1393 MethodHandle target = varargsArray(nargs); 1394 Object[] args = randomArgs(target.type().parameterArray()); 1395 MethodHandle target2 = MethodHandles.dropArguments(target, pos, 1396 Collections.nCopies(drop, Object.class).toArray(new Class<?>[0])); 1397 List<Object> resList = Arrays.asList(args); 1398 List<Object> argsToDrop = new ArrayList<>(resList); 1399 for (int i = drop; i > 0; i--) { 1400 argsToDrop.add(pos, "blort#"+i); 1401 } 1402 Object res2 = target2.invokeWithArguments(argsToDrop); 1403 Object res2List = Arrays.asList((Object[])res2); 1404 //if (!resList.equals(res2List)) 1405 // System.out.println("*** fail at n/p/d = "+nargs+"/"+pos+"/"+drop+": "+argsToDrop+" => "+res2List); 1406 assertEquals(resList, res2List); 1407 } 1408 1409 @Test 1410 public void testGuardWithTest() throws Throwable { 1411 CodeCacheOverflowProcessor.runMHTest(this::testGuardWithTest0); 1412 } 1413 1414 public void testGuardWithTest0() throws Throwable { 1415 if (CAN_SKIP_WORKING) return; 1416 startTest("guardWithTest"); 1417 for (int nargs = 0; nargs <= 50; nargs++) { 1418 if (CAN_TEST_LIGHTLY && nargs > 7) break; 1419 testGuardWithTest(nargs, Object.class); 1420 testGuardWithTest(nargs, String.class); 1421 } 1422 } 1423 1424 void testGuardWithTest(int nargs, Class<?> argClass) throws Throwable { 1425 testGuardWithTest(nargs, 0, argClass); 1426 if (nargs <= 5 || nargs % 10 == 3) { 1427 for (int testDrops = 1; testDrops <= nargs; testDrops++) 1428 testGuardWithTest(nargs, testDrops, argClass); 1429 } 1430 } 1431 1432 void testGuardWithTest(int nargs, int testDrops, Class<?> argClass) throws Throwable { 1433 countTest(); 1434 int nargs1 = Math.min(3, nargs); 1435 MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.methodType(boolean.class, Object.class)); 1436 MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.genericMethodType(nargs1)); 1437 MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.genericMethodType(nargs1)); 1438 while (test.type().parameterCount() > nargs) 1439 // 0: test = constant(MISSING_ARG.equals(MISSING_ARG)) 1440 // 1: test = lambda (_) MISSING_ARG.equals(_) 1441 test = MethodHandles.insertArguments(test, 0, MISSING_ARG); 1442 if (argClass != Object.class) { 1443 test = changeArgTypes(test, argClass); 1444 target = changeArgTypes(target, argClass); 1445 fallback = changeArgTypes(fallback, argClass); 1446 } 1447 int testArgs = nargs - testDrops; 1448 assert(testArgs >= 0); 1449 test = addTrailingArgs(test, Math.min(testArgs, nargs), argClass); 1450 target = addTrailingArgs(target, nargs, argClass); 1451 fallback = addTrailingArgs(fallback, nargs, argClass); 1452 Object[][] argLists = { 1453 { }, 1454 { "foo" }, { MethodHandlesTest.MISSING_ARG }, 1455 { "foo", "foo" }, { "foo", "bar" }, 1456 { "foo", "foo", "baz" }, { "foo", "bar", "baz" } 1457 }; 1458 for (Object[] argList : argLists) { 1459 Object[] argList1 = argList; 1460 if (argList.length != nargs) { 1461 if (argList.length != nargs1) continue; 1462 argList1 = Arrays.copyOf(argList, nargs); 1463 Arrays.fill(argList1, nargs1, nargs, MethodHandlesTest.MISSING_ARG_2); 1464 } 1465 MethodHandle test1 = test; 1466 if (test1.type().parameterCount() > testArgs) { 1467 int pc = test1.type().parameterCount(); 1468 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc)); 1469 } 1470 MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback); 1471 assertEquals(target.type(), mh.type()); 1472 boolean equals; 1473 switch (nargs) { 1474 case 0: equals = true; break; 1475 case 1: equals = MethodHandlesTest.MISSING_ARG.equals(argList[0]); break; 1476 default: equals = argList[0].equals(argList[1]); break; 1477 } 1478 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals"); 1479 if (verbosity >= 3) 1480 System.out.println(logEntry(willCall, argList)); 1481 Object result = mh.invokeWithArguments(argList1); 1482 assertCalled(willCall, argList); 1483 } 1484 } 1485 1486 @Test 1487 public void testGenericLoopCombinator() throws Throwable { 1488 CodeCacheOverflowProcessor.runMHTest(this::testGenericLoopCombinator0); 1489 } 1490 1491 public void testGenericLoopCombinator0() throws Throwable { 1492 if (CAN_SKIP_WORKING) return; 1493 startTest("loop"); 1494 // Test as follows: 1495 // * Have an increasing number of loop-local state. Local state type diversity grows with the number. 1496 // * Initializers set the starting value of loop-local state from the corresponding loop argument. 1497 // * For each local state element, there is a predicate - for all state combinations, exercise all predicates. 1498 // * Steps modify each local state element in each iteration. 1499 // * Finalizers group all local state elements into a resulting array. Verify end values. 1500 // * Exercise both pre- and post-checked loops. 1501 // Local state types, start values, predicates, and steps: 1502 // * int a, 0, a < 7, a = a + 1 1503 // * double b, 7.0, b > 0.5, b = b / 2.0 1504 // * String c, "start", c.length <= 9, c = c + a 1505 final Class<?>[] argTypes = new Class<?>[] {int.class, double.class, String.class}; 1506 final Object[][] args = new Object[][] { 1507 new Object[]{0 }, 1508 new Object[]{0, 7.0 }, 1509 new Object[]{0, 7.0, "start"} 1510 }; 1511 // These are the expected final state tuples for argument type tuple / predicate combinations, for pre- and 1512 // post-checked loops: 1513 final Object[][] preCheckedResults = new Object[][] { 1514 new Object[]{7 }, // (int) / int 1515 new Object[]{7, 0.0546875 }, // (int,double) / int 1516 new Object[]{5, 0.4375 }, // (int,double) / double 1517 new Object[]{7, 0.0546875, "start1234567"}, // (int,double,String) / int 1518 new Object[]{5, 0.4375, "start1234" }, // (int,double,String) / double 1519 new Object[]{6, 0.109375, "start12345" } // (int,double,String) / String 1520 }; 1521 final Object[][] postCheckedResults = new Object[][] { 1522 new Object[]{7 }, // (int) / int 1523 new Object[]{7, 0.109375 }, // (int,double) / int 1524 new Object[]{4, 0.4375 }, // (int,double) / double 1525 new Object[]{7, 0.109375, "start123456"}, // (int,double,String) / int 1526 new Object[]{4, 0.4375, "start123" }, // (int,double,String) / double 1527 new Object[]{5, 0.21875, "start12345" } // (int,double,String) / String 1528 }; 1529 final Lookup l = MethodHandles.lookup(); 1530 final Class<?> MHT = MethodHandlesTest.class; 1531 final Class<?> B = boolean.class; 1532 final Class<?> I = int.class; 1533 final Class<?> D = double.class; 1534 final Class<?> S = String.class; 1535 final MethodHandle hip = l.findStatic(MHT, "loopIntPred", methodType(B, I)); 1536 final MethodHandle hdp = l.findStatic(MHT, "loopDoublePred", methodType(B, I, D)); 1537 final MethodHandle hsp = l.findStatic(MHT, "loopStringPred", methodType(B, I, D, S)); 1538 final MethodHandle his = l.findStatic(MHT, "loopIntStep", methodType(I, I)); 1539 final MethodHandle hds = l.findStatic(MHT, "loopDoubleStep", methodType(D, I, D)); 1540 final MethodHandle hss = l.findStatic(MHT, "loopStringStep", methodType(S, I, D, S)); 1541 final MethodHandle[] preds = new MethodHandle[] {hip, hdp, hsp}; 1542 final MethodHandle[] steps = new MethodHandle[] {his, hds, hss}; 1543 for (int nargs = 1, useResultsStart = 0; nargs <= argTypes.length; useResultsStart += nargs++) { 1544 Class<?>[] useArgTypes = Arrays.copyOf(argTypes, nargs, Class[].class); 1545 MethodHandle[] usePreds = Arrays.copyOf(preds, nargs, MethodHandle[].class); 1546 MethodHandle[] useSteps = Arrays.copyOf(steps, nargs, MethodHandle[].class); 1547 Object[] useArgs = args[nargs - 1]; 1548 Object[][] usePreCheckedResults = new Object[nargs][]; 1549 Object[][] usePostCheckedResults = new Object[nargs][]; 1550 System.arraycopy(preCheckedResults, useResultsStart, usePreCheckedResults, 0, nargs); 1551 System.arraycopy(postCheckedResults, useResultsStart, usePostCheckedResults, 0, nargs); 1552 testGenericLoopCombinator(nargs, useArgTypes, usePreds, useSteps, useArgs, usePreCheckedResults, 1553 usePostCheckedResults); 1554 } 1555 } 1556 1557 void testGenericLoopCombinator(int nargs, Class<?>[] argTypes, MethodHandle[] preds, MethodHandle[] steps, 1558 Object[] args, Object[][] preCheckedResults, Object[][] postCheckedResults) 1559 throws Throwable { 1560 List<Class<?>> lArgTypes = Arrays.asList(argTypes); 1561 // Predicate and step handles are passed in as arguments, initializer and finalizer handles are constructed here 1562 // from the available information. 1563 MethodHandle[] inits = new MethodHandle[nargs]; 1564 for (int i = 0; i < nargs; ++i) { 1565 MethodHandle h; 1566 // Initializers are meant to return whatever they are passed at a given argument position. This means that 1567 // additional arguments may have to be appended and prepended. 1568 h = MethodHandles.identity(argTypes[i]); 1569 if (i < nargs - 1) { 1570 h = MethodHandles.dropArguments(h, 1, lArgTypes.subList(i + 1, nargs)); 1571 } 1572 if (i > 0) { 1573 h = MethodHandles.dropArguments(h, 0, lArgTypes.subList(0, i)); 1574 } 1575 inits[i] = h; 1576 } 1577 // Finalizers are all meant to collect all of the loop-local state in a single array and return that. Local 1578 // state is passed before the loop args. Construct such a finalizer by first taking a varargsArray collector for 1579 // the number of local state arguments, and then appending the loop args as to-be-dropped arguments. 1580 MethodHandle[] finis = new MethodHandle[nargs]; 1581 MethodHandle genericFini = MethodHandles.dropArguments( 1582 varargsArray(nargs).asType(methodType(Object[].class, lArgTypes)), nargs, lArgTypes); 1583 Arrays.fill(finis, genericFini); 1584 // The predicate and step handles' signatures need to be extended. They currently just accept local state args; 1585 // append possibly missing local state args and loop args using dropArguments. 1586 for (int i = 0; i < nargs; ++i) { 1587 List<Class<?>> additionalLocalStateArgTypes = lArgTypes.subList(i + 1, nargs); 1588 preds[i] = MethodHandles.dropArguments( 1589 MethodHandles.dropArguments(preds[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes); 1590 steps[i] = MethodHandles.dropArguments( 1591 MethodHandles.dropArguments(steps[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes); 1592 } 1593 // Iterate over all of the predicates, using only one of them at a time. 1594 for (int i = 0; i < nargs; ++i) { 1595 MethodHandle[] usePreds; 1596 if (nargs == 1) { 1597 usePreds = preds; 1598 } else { 1599 // Create an all-null preds array, and only use one predicate in this iteration. The null entries will 1600 // be substituted with true predicates by the loop combinator. 1601 usePreds = new MethodHandle[nargs]; 1602 usePreds[i] = preds[i]; 1603 } 1604 // Go for it. 1605 if (verbosity >= 3) { 1606 System.out.println("calling loop for argument types " + lArgTypes + " with predicate at index " + i); 1607 if (verbosity >= 5) { 1608 System.out.println("predicates: " + Arrays.asList(usePreds)); 1609 } 1610 } 1611 MethodHandle[] preInits = new MethodHandle[nargs + 1]; 1612 MethodHandle[] prePreds = new MethodHandle[nargs + 1]; 1613 MethodHandle[] preSteps = new MethodHandle[nargs + 1]; 1614 MethodHandle[] preFinis = new MethodHandle[nargs + 1]; 1615 System.arraycopy(inits, 0, preInits, 1, nargs); 1616 System.arraycopy(usePreds, 0, prePreds, 0, nargs); // preds are offset by 1 for pre-checked loops 1617 System.arraycopy(steps, 0, preSteps, 1, nargs); 1618 System.arraycopy(finis, 0, preFinis, 0, nargs); // finis are also offset by 1 for pre-checked loops 1619 // Convert to clause-major form. 1620 MethodHandle[][] preClauses = new MethodHandle[nargs + 1][4]; 1621 MethodHandle[][] postClauses = new MethodHandle[nargs][4]; 1622 toClauseMajor(preClauses, preInits, preSteps, prePreds, preFinis); 1623 toClauseMajor(postClauses, inits, steps, usePreds, finis); 1624 MethodHandle pre = MethodHandles.loop(preClauses); 1625 MethodHandle post = MethodHandles.loop(postClauses); 1626 if (verbosity >= 6) { 1627 System.out.println("pre-handle: " + pre); 1628 } 1629 Object[] preResults = (Object[]) pre.invokeWithArguments(args); 1630 if (verbosity >= 4) { 1631 System.out.println("pre-checked: expected " + Arrays.asList(preCheckedResults[i]) + ", actual " + 1632 Arrays.asList(preResults)); 1633 } 1634 if (verbosity >= 6) { 1635 System.out.println("post-handle: " + post); 1636 } 1637 Object[] postResults = (Object[]) post.invokeWithArguments(args); 1638 if (verbosity >= 4) { 1639 System.out.println("post-checked: expected " + Arrays.asList(postCheckedResults[i]) + ", actual " + 1640 Arrays.asList(postResults)); 1641 } 1642 assertArrayEquals(preCheckedResults[i], preResults); 1643 assertArrayEquals(postCheckedResults[i], postResults); 1644 } 1645 } 1646 1647 static void toClauseMajor(MethodHandle[][] clauses, MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini) { 1648 for (int i = 0; i < clauses.length; ++i) { 1649 clauses[i][0] = init[i]; 1650 clauses[i][1] = step[i]; 1651 clauses[i][2] = pred[i]; 1652 clauses[i][3] = fini[i]; 1653 } 1654 } 1655 1656 @Test 1657 public void testThrowException() throws Throwable { 1658 CodeCacheOverflowProcessor.runMHTest(this::testThrowException0); 1659 } 1660 1661 public void testThrowException0() throws Throwable { 1662 if (CAN_SKIP_WORKING) return; 1663 startTest("throwException"); 1664 testThrowException(int.class, new ClassCastException("testing")); 1665 testThrowException(void.class, new java.io.IOException("testing")); 1666 testThrowException(String.class, new LinkageError("testing")); 1667 } 1668 1669 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable { 1670 countTest(); 1671 Class<? extends Throwable> exType = thrown.getClass(); 1672 MethodHandle target = MethodHandles.throwException(returnType, exType); 1673 //System.out.println("throwing with "+target+" : "+thrown); 1674 MethodType expectedType = MethodType.methodType(returnType, exType); 1675 assertEquals(expectedType, target.type()); 1676 target = target.asType(target.type().generic()); 1677 Throwable caught = null; 1678 try { 1679 Object res = target.invokeExact((Object) thrown); 1680 fail("got "+res+" instead of throwing "+thrown); 1681 } catch (Throwable ex) { 1682 if (ex != thrown) { 1683 if (ex instanceof Error) throw (Error)ex; 1684 if (ex instanceof RuntimeException) throw (RuntimeException)ex; 1685 } 1686 caught = ex; 1687 } 1688 assertSame(thrown, caught); 1689 } 1690 1691 @Test 1692 public void testTryFinally() throws Throwable { 1693 CodeCacheOverflowProcessor.runMHTest(this::testTryFinally0); 1694 } 1695 1696 public void testTryFinally0() throws Throwable { 1697 if (CAN_SKIP_WORKING) return; 1698 startTest("tryFinally"); 1699 String inputMessage = "returned"; 1700 String augmentedMessage = "augmented"; 1701 String thrownMessage = "thrown"; 1702 String rethrownMessage = "rethrown"; 1703 // Test these cases: 1704 // * target returns, cleanup passes through 1705 // * target returns, cleanup augments 1706 // * target throws, cleanup augments and returns 1707 // * target throws, cleanup augments and rethrows 1708 MethodHandle target = MethodHandles.identity(String.class); 1709 MethodHandle targetThrow = MethodHandles.dropArguments( 1710 MethodHandles.throwException(String.class, Exception.class).bindTo(new Exception(thrownMessage)), 0, String.class); 1711 MethodHandle cleanupPassThrough = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, 1712 Throwable.class, String.class); 1713 MethodHandle cleanupAugment = MethodHandles.dropArguments(MethodHandles.constant(String.class, augmentedMessage), 1714 0, Throwable.class, String.class, String.class); 1715 MethodHandle cleanupCatch = MethodHandles.dropArguments(MethodHandles.constant(String.class, thrownMessage), 0, 1716 Throwable.class, String.class, String.class); 1717 MethodHandle cleanupThrow = MethodHandles.dropArguments(MethodHandles.throwException(String.class, Exception.class). 1718 bindTo(new Exception(rethrownMessage)), 0, Throwable.class, String.class, String.class); 1719 testTryFinally(target, cleanupPassThrough, inputMessage, inputMessage, false); 1720 testTryFinally(target, cleanupAugment, inputMessage, augmentedMessage, false); 1721 testTryFinally(targetThrow, cleanupCatch, inputMessage, thrownMessage, true); 1722 testTryFinally(targetThrow, cleanupThrow, inputMessage, rethrownMessage, true); 1723 // Test the same cases as above for void targets and cleanups. 1724 MethodHandles.Lookup lookup = MethodHandles.lookup(); 1725 Class<?> C = this.getClass(); 1726 MethodType targetType = methodType(void.class, String[].class); 1727 MethodType cleanupType = methodType(void.class, Throwable.class, String[].class); 1728 MethodHandle vtarget = lookup.findStatic(C, "vtarget", targetType); 1729 MethodHandle vtargetThrow = lookup.findStatic(C, "vtargetThrow", targetType); 1730 MethodHandle vcleanupPassThrough = lookup.findStatic(C, "vcleanupPassThrough", cleanupType); 1731 MethodHandle vcleanupAugment = lookup.findStatic(C, "vcleanupAugment", cleanupType); 1732 MethodHandle vcleanupCatch = lookup.findStatic(C, "vcleanupCatch", cleanupType); 1733 MethodHandle vcleanupThrow = lookup.findStatic(C, "vcleanupThrow", cleanupType); 1734 testTryFinally(vtarget, vcleanupPassThrough, inputMessage, inputMessage, false); 1735 testTryFinally(vtarget, vcleanupAugment, inputMessage, augmentedMessage, false); 1736 testTryFinally(vtargetThrow, vcleanupCatch, inputMessage, thrownMessage, true); 1737 testTryFinally(vtargetThrow, vcleanupThrow, inputMessage, rethrownMessage, true); 1738 } 1739 1740 void testTryFinally(MethodHandle target, MethodHandle cleanup, String input, String msg, boolean mustCatch) 1741 throws Throwable { 1742 countTest(); 1743 MethodHandle tf = MethodHandles.tryFinally(target, cleanup); 1744 String result = null; 1745 boolean isVoid = target.type().returnType() == void.class; 1746 String[] argArray = new String[]{input}; 1747 try { 1748 if (isVoid) { 1749 tf.invoke(argArray); 1750 } else { 1751 result = (String) tf.invoke(input); 1752 } 1753 } catch (Throwable t) { 1754 assertTrue(mustCatch); 1755 assertEquals(msg, t.getMessage()); 1756 return; 1757 } 1758 assertFalse(mustCatch); 1759 if (isVoid) { 1760 assertEquals(msg, argArray[0]); 1761 } else { 1762 assertEquals(msg, result); 1763 } 1764 } 1765 1766 @Test 1767 public void testAsInterfaceInstance() throws Throwable { 1768 CodeCacheOverflowProcessor.runMHTest(this::testAsInterfaceInstance0); 1769 } 1770 1771 public void testAsInterfaceInstance0() throws Throwable { 1772 if (CAN_SKIP_WORKING) return; 1773 startTest("asInterfaceInstance"); 1774 Lookup lookup = MethodHandles.lookup(); 1775 // test typical case: Runnable.run 1776 { 1777 countTest(); 1778 if (verbosity >= 2) System.out.println("Runnable"); 1779 MethodType mt = MethodType.methodType(void.class); 1780 MethodHandle mh = lookup.findStatic(MethodHandlesGeneralTest.class, "runForRunnable", mt); 1781 Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh); 1782 proxy.run(); 1783 assertCalled("runForRunnable"); 1784 } 1785 // well known single-name overloaded interface: Appendable.append 1786 { 1787 countTest(); 1788 if (verbosity >= 2) System.out.println("Appendable"); 1789 ArrayList<List<?>> appendResults = new ArrayList<>(); 1790 MethodHandle append = lookup.bind(appendResults, "add", MethodType.methodType(boolean.class, Object.class)); 1791 append = append.asType(MethodType.methodType(void.class, List.class)); // specialize the type 1792 MethodHandle asList = lookup.findStatic(Arrays.class, "asList", MethodType.methodType(List.class, Object[].class)); 1793 MethodHandle mh = MethodHandles.filterReturnValue(asList, append).asVarargsCollector(Object[].class); 1794 Appendable proxy = MethodHandleProxies.asInterfaceInstance(Appendable.class, mh); 1795 proxy.append("one"); 1796 proxy.append("two", 3, 4); 1797 proxy.append('5'); 1798 assertEquals(Arrays.asList(Arrays.asList("one"), 1799 Arrays.asList("two", 3, 4), 1800 Arrays.asList('5')), 1801 appendResults); 1802 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 1803 appendResults.clear(); 1804 Formatter formatter = new Formatter(proxy); 1805 String fmt = "foo str=%s char='%c' num=%d"; 1806 Object[] fmtArgs = { "str!", 'C', 42 }; 1807 String expect = String.format(fmt, fmtArgs); 1808 formatter.format(fmt, fmtArgs); 1809 String actual = ""; 1810 if (verbosity >= 3) System.out.println("appendResults="+appendResults); 1811 for (List<?> l : appendResults) { 1812 Object x = l.get(0); 1813 switch (l.size()) { 1814 case 1: actual += x; continue; 1815 case 3: actual += ((String)x).substring((int)(Object)l.get(1), (int)(Object)l.get(2)); continue; 1816 } 1817 actual += l; 1818 } 1819 if (verbosity >= 3) System.out.println("expect="+expect); 1820 if (verbosity >= 3) System.out.println("actual="+actual); 1821 assertEquals(expect, actual); 1822 } 1823 // test case of an single name which is overloaded: Fooable.foo(...) 1824 { 1825 if (verbosity >= 2) System.out.println("Fooable"); 1826 MethodHandle mh = lookup.findStatic(MethodHandlesGeneralTest.class, "fooForFooable", 1827 MethodType.methodType(Object.class, String.class, Object[].class)); 1828 Fooable proxy = MethodHandleProxies.asInterfaceInstance(Fooable.class, mh); 1829 for (Method m : Fooable.class.getDeclaredMethods()) { 1830 countTest(); 1831 assertSame("foo", m.getName()); 1832 if (verbosity > 3) 1833 System.out.println("calling "+m); 1834 MethodHandle invoker = lookup.unreflect(m); 1835 MethodType mt = invoker.type(); 1836 Class<?>[] types = mt.parameterArray(); 1837 types[0] = int.class; // placeholder 1838 Object[] args = randomArgs(types); 1839 args[0] = proxy; 1840 if (verbosity > 3) 1841 System.out.println("calling "+m+" on "+Arrays.asList(args)); 1842 Object result = invoker.invokeWithArguments(args); 1843 if (verbosity > 4) 1844 System.out.println("result = "+result); 1845 String name = "fooForFooable/"+args[1]; 1846 Object[] argTail = Arrays.copyOfRange(args, 2, args.length); 1847 assertCalled(name, argTail); 1848 assertEquals(result, logEntry(name, argTail)); 1849 } 1850 } 1851 // test processing of thrown exceptions: 1852 for (Throwable ex : new Throwable[] { new NullPointerException("ok"), 1853 new InternalError("ok"), 1854 new Throwable("fail"), 1855 new Exception("fail"), 1856 new MyCheckedException() 1857 }) { 1858 MethodHandle mh = MethodHandles.throwException(void.class, Throwable.class); 1859 mh = MethodHandles.insertArguments(mh, 0, ex); 1860 WillThrow proxy = MethodHandleProxies.asInterfaceInstance(WillThrow.class, mh); 1861 try { 1862 countTest(); 1863 proxy.willThrow(); 1864 System.out.println("Failed to throw: "+ex); 1865 assertTrue(false); 1866 } catch (Throwable ex1) { 1867 if (verbosity > 3) { 1868 System.out.println("throw "+ex); 1869 System.out.println("catch "+(ex == ex1 ? "UNWRAPPED" : ex1)); 1870 } 1871 if (ex instanceof RuntimeException || 1872 ex instanceof Error) { 1873 assertSame("must pass unchecked exception out without wrapping", ex, ex1); 1874 } else if (ex instanceof MyCheckedException) { 1875 assertSame("must pass declared exception out without wrapping", ex, ex1); 1876 } else { 1877 assertNotSame("must pass undeclared checked exception with wrapping", ex, ex1); 1878 if (!(ex1 instanceof UndeclaredThrowableException) || ex1.getCause() != ex) { 1879 ex1.printStackTrace(System.out); 1880 } 1881 assertSame(ex, ex1.getCause()); 1882 UndeclaredThrowableException utex = (UndeclaredThrowableException) ex1; 1883 } 1884 } 1885 } 1886 // Test error checking on bad interfaces: 1887 for (Class<?> nonSMI : new Class<?>[] { Object.class, 1888 String.class, 1889 CharSequence.class, 1890 java.io.Serializable.class, 1891 PrivateRunnable.class, 1892 Example.class }) { 1893 if (verbosity > 2) System.out.println(nonSMI.getName()); 1894 try { 1895 countTest(false); 1896 MethodHandleProxies.asInterfaceInstance(nonSMI, varargsArray(0)); 1897 assertTrue("Failed to throw on "+nonSMI.getName(), false); 1898 } catch (IllegalArgumentException ex) { 1899 if (verbosity > 2) System.out.println(nonSMI.getSimpleName()+": "+ex); 1900 // Object: java.lang.IllegalArgumentException: 1901 // not a public interface: java.lang.Object 1902 // String: java.lang.IllegalArgumentException: 1903 // not a public interface: java.lang.String 1904 // CharSequence: java.lang.IllegalArgumentException: 1905 // not a single-method interface: java.lang.CharSequence 1906 // Serializable: java.lang.IllegalArgumentException: 1907 // not a single-method interface: java.io.Serializable 1908 // PrivateRunnable: java.lang.IllegalArgumentException: 1909 // not a public interface: test.java.lang.invoke.MethodHandlesTest$PrivateRunnable 1910 // Example: java.lang.IllegalArgumentException: 1911 // not a public interface: test.java.lang.invoke.MethodHandlesTest$Example 1912 } 1913 } 1914 // Test error checking on interfaces with the wrong method type: 1915 for (Class<?> intfc : new Class<?>[] { Runnable.class /*arity 0*/, 1916 Fooable.class /*arity 1 & 2*/ }) { 1917 int badArity = 1; // known to be incompatible 1918 if (verbosity > 2) System.out.println(intfc.getName()); 1919 try { 1920 countTest(false); 1921 MethodHandleProxies.asInterfaceInstance(intfc, varargsArray(badArity)); 1922 assertTrue("Failed to throw on "+intfc.getName(), false); 1923 } catch (WrongMethodTypeException ex) { 1924 if (verbosity > 2) System.out.println(intfc.getSimpleName()+": "+ex); 1925 // Runnable: java.lang.invoke.WrongMethodTypeException: 1926 // cannot convert MethodHandle(Object)Object[] to ()void 1927 // Fooable: java.lang.invoke.WrongMethodTypeException: 1928 // cannot convert MethodHandle(Object)Object[] to (Object,String)Object 1929 } 1930 } 1931 } 1932 1933 @Test 1934 public void testInterfaceCast() throws Throwable { 1935 CodeCacheOverflowProcessor.runMHTest(this::testInterfaceCast0); 1936 } 1937 1938 public void testInterfaceCast0() throws Throwable { 1939 if (CAN_SKIP_WORKING) return; 1940 startTest("interfaceCast"); 1941 assert( (((Object)"foo") instanceof CharSequence)); 1942 assert(!(((Object)"foo") instanceof Iterable)); 1943 for (MethodHandle mh : new MethodHandle[]{ 1944 MethodHandles.identity(String.class), 1945 MethodHandles.identity(CharSequence.class), 1946 MethodHandles.identity(Iterable.class) 1947 }) { 1948 if (verbosity > 0) System.out.println("-- mh = "+mh); 1949 for (Class<?> ctype : new Class<?>[]{ 1950 Object.class, String.class, CharSequence.class, 1951 Number.class, Iterable.class 1952 }) { 1953 if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName()); 1954 // doret docast 1955 testInterfaceCast(mh, ctype, false, false); 1956 testInterfaceCast(mh, ctype, true, false); 1957 testInterfaceCast(mh, ctype, false, true); 1958 testInterfaceCast(mh, ctype, true, true); 1959 } 1960 } 1961 } 1962 1963 private static Class<?> i2o(Class<?> c) { 1964 return (c.isInterface() ? Object.class : c); 1965 } 1966 1967 public void testInterfaceCast(MethodHandle mh, Class<?> ctype, 1968 boolean doret, boolean docast) throws Throwable { 1969 MethodHandle mh0 = mh; 1970 if (verbosity > 1) 1971 System.out.println("mh="+mh+", ctype="+ctype.getName()+", doret="+doret+", docast="+docast); 1972 String normalRetVal = "normal return value"; 1973 MethodType mt = mh.type(); 1974 MethodType mt0 = mt; 1975 if (doret) mt = mt.changeReturnType(ctype); 1976 else mt = mt.changeParameterType(0, ctype); 1977 if (docast) mh = MethodHandles.explicitCastArguments(mh, mt); 1978 else mh = mh.asType(mt); 1979 assertEquals(mt, mh.type()); 1980 MethodType mt1 = mt; 1981 // this bit is needed to make the interface types disappear for invokeWithArguments: 1982 mh = MethodHandles.explicitCastArguments(mh, mt.generic()); 1983 Class<?>[] step = { 1984 mt1.parameterType(0), // param as passed to mh at first 1985 mt0.parameterType(0), // param after incoming cast 1986 mt0.returnType(), // return value before cast 1987 mt1.returnType(), // return value after outgoing cast 1988 }; 1989 // where might a checkCast occur? 1990 boolean[] checkCast = new boolean[step.length]; 1991 // the string value must pass each step without causing an exception 1992 if (!docast) { 1993 if (!doret) { 1994 if (step[0] != step[1]) 1995 checkCast[1] = true; // incoming value is cast 1996 } else { 1997 if (step[2] != step[3]) 1998 checkCast[3] = true; // outgoing value is cast 1999 } 2000 } 2001 boolean expectFail = false; 2002 for (int i = 0; i < step.length; i++) { 2003 Class<?> c = step[i]; 2004 if (!checkCast[i]) c = i2o(c); 2005 if (!c.isInstance(normalRetVal)) { 2006 if (verbosity > 3) 2007 System.out.println("expect failure at step "+i+" in "+Arrays.toString(step)+Arrays.toString(checkCast)); 2008 expectFail = true; 2009 break; 2010 } 2011 } 2012 countTest(!expectFail); 2013 if (verbosity > 2) 2014 System.out.println("expectFail="+expectFail+", mt="+mt); 2015 Object res; 2016 try { 2017 res = mh.invokeWithArguments(normalRetVal); 2018 } catch (Exception ex) { 2019 res = ex; 2020 } 2021 boolean sawFail = !(res instanceof String); 2022 if (sawFail != expectFail) { 2023 System.out.println("*** testInterfaceCast: mh0 = "+mh0); 2024 System.out.println(" retype using "+(docast ? "explicitCastArguments" : "asType")+" to "+mt+" => "+mh); 2025 System.out.println(" call returned "+res); 2026 System.out.println(" expected "+(expectFail ? "an exception" : normalRetVal)); 2027 } 2028 if (!expectFail) { 2029 assertFalse(res.toString(), sawFail); 2030 assertEquals(normalRetVal, res); 2031 } else { 2032 assertTrue(res.toString(), sawFail); 2033 } 2034 } 2035 2036 static Example userMethod(Object o, String s, int i) { 2037 called("userMethod", o, s, i); 2038 return null; 2039 } 2040 2041 @Test 2042 public void testUserClassInSignature() throws Throwable { 2043 CodeCacheOverflowProcessor.runMHTest(this::testUserClassInSignature0); 2044 } 2045 2046 public void testUserClassInSignature0() throws Throwable { 2047 if (CAN_SKIP_WORKING) return; 2048 startTest("testUserClassInSignature"); 2049 Lookup lookup = MethodHandles.lookup(); 2050 String name; MethodType mt; MethodHandle mh; 2051 Object[] args; 2052 2053 // Try a static method. 2054 name = "userMethod"; 2055 mt = MethodType.methodType(Example.class, Object.class, String.class, int.class); 2056 mh = lookup.findStatic(lookup.lookupClass(), name, mt); 2057 assertEquals(mt, mh.type()); 2058 assertEquals(Example.class, mh.type().returnType()); 2059 args = randomArgs(mh.type().parameterArray()); 2060 mh.invokeWithArguments(args); 2061 assertCalled(name, args); 2062 2063 // Try a virtual method. 2064 name = "v2"; 2065 mt = MethodType.methodType(Object.class, Object.class, int.class); 2066 mh = lookup.findVirtual(Example.class, name, mt); 2067 assertEquals(mt, mh.type().dropParameterTypes(0,1)); 2068 assertTrue(mh.type().parameterList().contains(Example.class)); 2069 args = randomArgs(mh.type().parameterArray()); 2070 mh.invokeWithArguments(args); 2071 assertCalled(name, args); 2072 } 2073 2074 static void runForRunnable() { 2075 called("runForRunnable"); 2076 } 2077 2078 public interface Fooable { 2079 // overloads: 2080 Object foo(Object x, String y); 2081 List<?> foo(String x, int y); 2082 Object foo(String x); 2083 } 2084 2085 static Object fooForFooable(String x, Object... y) { 2086 return called("fooForFooable/"+x, y); 2087 } 2088 2089 @SuppressWarnings("serial") // not really a public API, just a test case 2090 public static class MyCheckedException extends Exception { 2091 } 2092 2093 public interface WillThrow { 2094 void willThrow() throws MyCheckedException; 2095 } 2096 2097 /*non-public*/ interface PrivateRunnable { 2098 public void run(); 2099 } 2100 2101 @Test 2102 public void testRunnableProxy() throws Throwable { 2103 CodeCacheOverflowProcessor.runMHTest(this::testRunnableProxy0); 2104 } 2105 2106 public void testRunnableProxy0() throws Throwable { 2107 if (CAN_SKIP_WORKING) return; 2108 startTest("testRunnableProxy"); 2109 MethodHandles.Lookup lookup = MethodHandles.lookup(); 2110 MethodHandle run = lookup.findStatic(lookup.lookupClass(), "runForRunnable", MethodType.methodType(void.class)); 2111 Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run); 2112 testRunnableProxy(r); 2113 assertCalled("runForRunnable"); 2114 } 2115 2116 private static void testRunnableProxy(Runnable r) { 2117 //7058630: JSR 292 method handle proxy violates contract for Object methods 2118 r.run(); 2119 Object o = r; 2120 r = null; 2121 boolean eq = (o == o); 2122 int hc = System.identityHashCode(o); 2123 String st = o.getClass().getName() + "@" + Integer.toHexString(hc); 2124 Object expect = Arrays.asList(st, eq, hc); 2125 if (verbosity >= 2) System.out.println("expect st/eq/hc = "+expect); 2126 Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode()); 2127 if (verbosity >= 2) System.out.println("actual st/eq/hc = "+actual); 2128 assertEquals(expect, actual); 2129 } 2130 }