1 /* 2 * Copyright (c) 2017, 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 package compiler.valhalla.valuetypes; 25 26 import java.lang.invoke.*; 27 import java.lang.reflect.Method; 28 29 import jdk.test.lib.Asserts; 30 31 /* 32 * @test 33 * @summary Test method handle support for value types 34 * @library /testlibrary /test/lib /compiler/whitebox / 35 * @requires os.simpleArch == "x64" 36 * @compile TestMethodHandles.java 37 * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform 38 * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions 39 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI 40 * compiler.valhalla.valuetypes.ValueTypeTest 41 * compiler.valhalla.valuetypes.TestMethodHandles 42 */ 43 public class TestMethodHandles extends ValueTypeTest { 44 // Extra VM parameters for some test scenarios. See ValueTypeTest.getVMParameters() 45 @Override 46 public String[] getExtraVMParameters(int scenario) { 47 switch (scenario) { 48 // Prevent inlining through MethodHandle linkTo adapters to stress the calling convention 49 case 2: return new String[] {"-DVerifyIR=false", "-XX:CompileCommand=dontinline,java.lang.invoke.DirectMethodHandle::internalMemberName"}; 50 case 4: return new String[] {"-XX:CompileCommand=dontinline,java.lang.invoke.DirectMethodHandle::internalMemberName"}; 51 } 52 return null; 53 } 54 55 static { 56 try { 57 Class<?> clazz = TestMethodHandles.class; 58 ClassLoader loader = clazz.getClassLoader(); 59 MethodHandles.Lookup lookup = MethodHandles.lookup(); 60 61 MethodType mt = MethodType.methodType(MyValue3.class); 62 test1_mh = lookup.findVirtual(clazz, "test1_target", mt); 63 test2_mh = lookup.findVirtual(clazz, "test2_target", mt); 64 test3_mh = lookup.findVirtual(clazz, "test3_target", mt); 65 66 MethodType test4_mt1 = MethodType.methodType(int.class, MyValue1.class); 67 MethodType test4_mt2 = MethodType.methodType(MyValue1.class); 68 MethodHandle test4_mh1 = lookup.findStatic(clazz, "test4_helper1", test4_mt1); 69 MethodHandle test4_mh2 = lookup.findStatic(clazz, "test4_helper2", test4_mt2); 70 test4_mh = MethodHandles.filterReturnValue(test4_mh2, test4_mh1); 71 72 MethodType test5_mt = MethodType.methodType(int.class, MyValue1.class); 73 test5_mh = lookup.findVirtual(clazz, "test5_target", test5_mt); 74 75 MethodType test6_mt = MethodType.methodType(MyValue3.class); 76 MethodHandle test6_mh1 = lookup.findVirtual(clazz, "test6_target1", test6_mt); 77 MethodHandle test6_mh2 = lookup.findVirtual(clazz, "test6_target2", test6_mt); 78 MethodType boolean_mt = MethodType.methodType(boolean.class); 79 MethodHandle test6_mh_test = lookup.findVirtual(clazz, "test6_test", boolean_mt); 80 test6_mh = MethodHandles.guardWithTest(test6_mh_test, test6_mh1, test6_mh2); 81 82 MethodType myvalue2_mt = MethodType.methodType(MyValue2.class); 83 test7_mh1 = lookup.findStatic(clazz, "test7_target1", myvalue2_mt); 84 MethodHandle test7_mh2 = lookup.findStatic(clazz, "test7_target2", myvalue2_mt); 85 MethodHandle test7_mh_test = lookup.findStatic(clazz, "test7_test", boolean_mt); 86 test7_mh = MethodHandles.guardWithTest(test7_mh_test, 87 MethodHandles.invoker(myvalue2_mt), 88 MethodHandles.dropArguments(test7_mh2, 0, MethodHandle.class)); 89 90 MethodHandle test8_mh1 = lookup.findStatic(clazz, "test8_target1", myvalue2_mt); 91 test8_mh2 = lookup.findStatic(clazz, "test8_target2", myvalue2_mt); 92 MethodHandle test8_mh_test = lookup.findStatic(clazz, "test8_test", boolean_mt); 93 test8_mh = MethodHandles.guardWithTest(test8_mh_test, 94 MethodHandles.dropArguments(test8_mh1, 0, MethodHandle.class), 95 MethodHandles.invoker(myvalue2_mt)); 96 97 MethodType test9_mt = MethodType.methodType(MyValue3.class); 98 MethodHandle test9_mh1 = lookup.findVirtual(clazz, "test9_target1", test9_mt); 99 MethodHandle test9_mh2 = lookup.findVirtual(clazz, "test9_target2", test9_mt); 100 MethodHandle test9_mh3 = lookup.findVirtual(clazz, "test9_target3", test9_mt); 101 MethodType test9_mt2 = MethodType.methodType(boolean.class); 102 MethodHandle test9_mh_test1 = lookup.findVirtual(clazz, "test9_test1", test9_mt2); 103 MethodHandle test9_mh_test2 = lookup.findVirtual(clazz, "test9_test2", test9_mt2); 104 test9_mh = MethodHandles.guardWithTest(test9_mh_test1, 105 test9_mh1, 106 MethodHandles.guardWithTest(test9_mh_test2, test9_mh2, test9_mh3)); 107 108 MethodType test10_mt = MethodType.methodType(MyValue2.class); 109 MethodHandle test10_mh1 = lookup.findStatic(clazz, "test10_target1", test10_mt); 110 test10_mh2 = lookup.findStatic(clazz, "test10_target2", test10_mt); 111 test10_mh3 = lookup.findStatic(clazz, "test10_target3", test10_mt); 112 MethodType test10_mt2 = MethodType.methodType(boolean.class); 113 MethodType test10_mt3 = MethodType.methodType(MyValue2.class); 114 MethodHandle test10_mh_test1 = lookup.findStatic(clazz, "test10_test1", test10_mt2); 115 MethodHandle test10_mh_test2 = lookup.findStatic(clazz, "test10_test2", test10_mt2); 116 test10_mh = MethodHandles.guardWithTest(test10_mh_test1, 117 MethodHandles.dropArguments(test10_mh1, 0, MethodHandle.class, MethodHandle.class), 118 MethodHandles.guardWithTest(test10_mh_test2, 119 MethodHandles.dropArguments(MethodHandles.invoker(test10_mt3), 1, MethodHandle.class), 120 MethodHandles.dropArguments(MethodHandles.invoker(test10_mt3), 0, MethodHandle.class)) 121 ); 122 123 MethodHandle test11_mh1 = lookup.findStatic(clazz, "test11_target1", myvalue2_mt); 124 test11_mh2 = lookup.findStatic(clazz, "test11_target2", myvalue2_mt); 125 MethodHandle test11_mh_test = lookup.findStatic(clazz, "test11_test", boolean_mt); 126 test11_mh = MethodHandles.guardWithTest(test11_mh_test, 127 MethodHandles.dropArguments(test11_mh1, 0, MethodHandle.class), 128 MethodHandles.invoker(myvalue2_mt)); 129 } catch (NoSuchMethodException | IllegalAccessException e) { 130 e.printStackTrace(); 131 throw new RuntimeException("Method handle lookup failed"); 132 } 133 } 134 135 public static void main(String[] args) throws Throwable { 136 TestMethodHandles test = new TestMethodHandles(); 137 test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class, MyValue3.class, MyValue3Inline.class); 138 } 139 140 // Everything inlined 141 final MyValue3 test1_vt = MyValue3.create(); 142 143 @ForceInline 144 MyValue3 test1_target() { 145 return test1_vt; 146 } 147 148 static final MethodHandle test1_mh; 149 150 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + CALL) 151 @Test(valid = ValueTypeReturnedAsFieldsOff, match = { ALLOC, STORE }, matchCount = { 1, 14 }) 152 public MyValue3 test1() throws Throwable { 153 return (MyValue3)test1_mh.invokeExact(this); 154 } 155 156 @DontCompile 157 public void test1_verifier(boolean warmup) throws Throwable { 158 MyValue3 vt = test1(); 159 test1_vt.verify(vt); 160 } 161 162 // Leaf method not inlined but returned type is known 163 final MyValue3 test2_vt = MyValue3.create(); 164 @DontInline 165 MyValue3 test2_target() { 166 return test2_vt; 167 } 168 169 static final MethodHandle test2_mh; 170 171 @Test 172 public MyValue3 test2() throws Throwable { 173 return (MyValue3)test2_mh.invokeExact(this); 174 } 175 176 @DontCompile 177 public void test2_verifier(boolean warmup) throws Throwable { 178 Method helper_m = getClass().getDeclaredMethod("test2_target"); 179 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) { 180 enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION); 181 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test2_target not compiled"); 182 } 183 MyValue3 vt = test2(); 184 test2_vt.verify(vt); 185 } 186 187 // Leaf method not inlined and returned type not known 188 final MyValue3 test3_vt = MyValue3.create(); 189 @DontInline 190 MyValue3 test3_target() { 191 return test3_vt; 192 } 193 194 static final MethodHandle test3_mh; 195 196 @Test 197 public MyValue3 test3() throws Throwable { 198 return (MyValue3)test3_mh.invokeExact(this); 199 } 200 201 @DontCompile 202 public void test3_verifier(boolean warmup) throws Throwable { 203 // hack so C2 doesn't know the target of the invoke call 204 Class c = Class.forName("java.lang.invoke.DirectMethodHandle"); 205 Method m = c.getDeclaredMethod("internalMemberName", Object.class); 206 WHITE_BOX.testSetDontInlineMethod(m, warmup); 207 MyValue3 vt = test3(); 208 test3_vt.verify(vt); 209 } 210 211 // When test75_helper1 is inlined in test75, the method handle 212 // linker that called it is passed a pointer to a copy of vt 213 // stored in memory. The method handle linker needs to load the 214 // fields from memory before it inlines test75_helper1. 215 static public int test4_helper1(MyValue1 vt) { 216 return vt.x; 217 } 218 219 static MyValue1 test4_vt = MyValue1.createWithFieldsInline(rI, rL); 220 static public MyValue1 test4_helper2() { 221 return test4_vt; 222 } 223 224 static final MethodHandle test4_mh; 225 226 @Test 227 public int test4() throws Throwable { 228 return (int)test4_mh.invokeExact(); 229 } 230 231 @DontCompile 232 public void test4_verifier(boolean warmup) throws Throwable { 233 int i = test4(); 234 Asserts.assertEQ(i, test4_vt.x); 235 } 236 237 // Test method handle call with value type argument 238 public int test5_target(MyValue1 vt) { 239 return vt.x; 240 } 241 242 static final MethodHandle test5_mh; 243 MyValue1 test5_vt = MyValue1.createWithFieldsInline(rI, rL); 244 245 @Test 246 public int test5() throws Throwable { 247 return (int)test5_mh.invokeExact(this, test5_vt); 248 } 249 250 @DontCompile 251 public void test5_verifier(boolean warmup) throws Throwable { 252 int i = test5(); 253 Asserts.assertEQ(i, test5_vt.x); 254 } 255 256 // Return of target1 and target2 merged in a Lambda Form as an 257 // Object. Shouldn't cause any allocation 258 final MyValue3 test6_vt1 = MyValue3.create(); 259 @ForceInline 260 MyValue3 test6_target1() { 261 return test6_vt1; 262 } 263 264 final MyValue3 test6_vt2 = MyValue3.create(); 265 @ForceInline 266 MyValue3 test6_target2() { 267 return test6_vt2; 268 } 269 270 boolean test6_bool = true; 271 @ForceInline 272 boolean test6_test() { 273 return test6_bool; 274 } 275 276 static final MethodHandle test6_mh; 277 278 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS) 279 @Test(valid = ValueTypeReturnedAsFieldsOff) 280 public MyValue3 test6() throws Throwable { 281 return (MyValue3)test6_mh.invokeExact(this); 282 } 283 284 @DontCompile 285 public void test6_verifier(boolean warmup) throws Throwable { 286 test6_bool = !test6_bool; 287 MyValue3 vt = test6(); 288 vt.verify(test6_bool ? test6_vt1 : test6_vt2); 289 } 290 291 // Similar as above but with the method handle for target1 not 292 // constant. Shouldn't cause any allocation. 293 @ForceInline 294 static MyValue2 test7_target1() { 295 return MyValue2.createWithFieldsInline(rI, true); 296 } 297 298 @ForceInline 299 static MyValue2 test7_target2() { 300 return MyValue2.createWithFieldsInline(rI+1, false); 301 } 302 303 static boolean test7_bool = true; 304 @ForceInline 305 static boolean test7_test() { 306 return test7_bool; 307 } 308 309 static final MethodHandle test7_mh; 310 static MethodHandle test7_mh1; 311 312 @Test 313 public long test7() throws Throwable { 314 return ((MyValue2)test7_mh.invokeExact(test7_mh1)).hash(); 315 } 316 317 @DontCompile 318 public void test7_verifier(boolean warmup) throws Throwable { 319 test7_bool = !test7_bool; 320 long hash = test7(); 321 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+(test7_bool ? 0 : 1), test7_bool).hash()); 322 } 323 324 // Same as above but with the method handle for target2 not 325 // constant. Shouldn't cause any allocation. 326 @ForceInline 327 static MyValue2 test8_target1() { 328 return MyValue2.createWithFieldsInline(rI, true); 329 } 330 331 @ForceInline 332 static MyValue2 test8_target2() { 333 return MyValue2.createWithFieldsInline(rI+1, false); 334 } 335 336 static boolean test8_bool = true; 337 @ForceInline 338 static boolean test8_test() { 339 return test8_bool; 340 } 341 342 static final MethodHandle test8_mh; 343 static MethodHandle test8_mh2; 344 345 @Test 346 public long test8() throws Throwable { 347 return ((MyValue2)test8_mh.invokeExact(test8_mh2)).hash(); 348 } 349 350 @DontCompile 351 public void test8_verifier(boolean warmup) throws Throwable { 352 test8_bool = !test8_bool; 353 long hash = test8(); 354 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+(test8_bool ? 0 : 1), test8_bool).hash()); 355 } 356 357 // Return of target1, target2 and target3 merged in Lambda Forms 358 // as an Object. Shouldn't cause any allocation 359 final MyValue3 test9_vt1 = MyValue3.create(); 360 @ForceInline 361 MyValue3 test9_target1() { 362 return test9_vt1; 363 } 364 365 final MyValue3 test9_vt2 = MyValue3.create(); 366 @ForceInline 367 MyValue3 test9_target2() { 368 return test9_vt2; 369 } 370 371 final MyValue3 test9_vt3 = MyValue3.create(); 372 @ForceInline 373 MyValue3 test9_target3() { 374 return test9_vt3; 375 } 376 377 boolean test9_bool1 = true; 378 @ForceInline 379 boolean test9_test1() { 380 return test9_bool1; 381 } 382 383 boolean test9_bool2 = true; 384 @ForceInline 385 boolean test9_test2() { 386 return test9_bool2; 387 } 388 389 static final MethodHandle test9_mh; 390 391 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS) 392 @Test(valid = ValueTypeReturnedAsFieldsOff) 393 public MyValue3 test9() throws Throwable { 394 return (MyValue3)test9_mh.invokeExact(this); 395 } 396 397 static int test9_i = 0; 398 @DontCompile 399 public void test9_verifier(boolean warmup) throws Throwable { 400 test9_i++; 401 test9_bool1 = (test9_i % 2) == 0; 402 test9_bool2 = (test9_i % 3) == 0; 403 MyValue3 vt = test9(); 404 vt.verify(test9_bool1 ? test9_vt1 : (test9_bool2 ? test9_vt2 : test9_vt3)); 405 } 406 407 // Same as above but with non constant target2 and target3 408 @ForceInline 409 static MyValue2 test10_target1() { 410 return MyValue2.createWithFieldsInline(rI, true); 411 } 412 413 @ForceInline 414 static MyValue2 test10_target2() { 415 return MyValue2.createWithFieldsInline(rI+1, false); 416 } 417 418 @ForceInline 419 static MyValue2 test10_target3() { 420 return MyValue2.createWithFieldsInline(rI+2, true); 421 } 422 423 static boolean test10_bool1 = true; 424 @ForceInline 425 static boolean test10_test1() { 426 return test10_bool1; 427 } 428 429 static boolean test10_bool2 = true; 430 @ForceInline 431 static boolean test10_test2() { 432 return test10_bool2; 433 } 434 435 static final MethodHandle test10_mh; 436 static MethodHandle test10_mh2; 437 static MethodHandle test10_mh3; 438 439 @Test 440 public long test10() throws Throwable { 441 return ((MyValue2)test10_mh.invokeExact(test10_mh2, test10_mh3)).hash(); 442 } 443 444 static int test10_i = 0; 445 446 @DontCompile 447 public void test10_verifier(boolean warmup) throws Throwable { 448 test10_i++; 449 test10_bool1 = (test10_i % 2) == 0; 450 test10_bool2 = (test10_i % 3) == 0; 451 long hash = test10(); 452 int i = rI+(test10_bool1 ? 0 : (test10_bool2 ? 1 : 2)); 453 boolean b = test10_bool1 ? true : (test10_bool2 ? false : true); 454 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(i, b).hash()); 455 } 456 457 static int test11_i = 0; 458 459 @ForceInline 460 static MyValue2 test11_target1() { 461 return MyValue2.createWithFieldsInline(rI+test11_i, true); 462 } 463 464 @ForceInline 465 static MyValue2 test11_target2() { 466 return MyValue2.createWithFieldsInline(rI-test11_i, false); 467 } 468 469 @ForceInline 470 static boolean test11_test() { 471 return (test11_i % 100) == 0; 472 } 473 474 static final MethodHandle test11_mh; 475 static MethodHandle test11_mh2; 476 477 // Check that a buffered value returned by a compiled lambda form 478 // is properly handled by the caller. 479 @Test 480 @Warmup(11000) 481 public long test11() throws Throwable { 482 return ((MyValue2)test11_mh.invokeExact(test11_mh2)).hash(); 483 } 484 485 @DontCompile 486 public void test11_verifier(boolean warmup) throws Throwable { 487 test11_i++; 488 long hash = test11(); 489 boolean b = (test11_i % 100) == 0; 490 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+test11_i * (b ? 1 : -1), b).hash()); 491 } 492 }