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