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