1 /* 2 * Copyright (c) 2017, 2025, 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.inlinetypes; 25 26 import compiler.lib.ir_framework.*; 27 import jdk.test.lib.Asserts; 28 import jdk.test.whitebox.WhiteBox; 29 30 import java.lang.invoke.MethodHandle; 31 import java.lang.invoke.MethodHandles; 32 import java.lang.invoke.MethodType; 33 import java.lang.reflect.Method; 34 35 import static compiler.valhalla.inlinetypes.InlineTypeIRNode.*; 36 import static compiler.valhalla.inlinetypes.InlineTypes.*; 37 38 import jdk.internal.value.ValueClass; 39 import jdk.internal.vm.annotation.LooselyConsistentValue; 40 import jdk.internal.vm.annotation.NullRestricted; 41 import jdk.internal.vm.annotation.Strict; 42 43 /* 44 * @test 45 * @key randomness 46 * @summary Test value class calling convention optimizations. 47 * @library /test/lib / 48 * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64") 49 * @build jdk.test.whitebox.WhiteBox 50 * @enablePreview 51 * @modules java.base/jdk.internal.value 52 * java.base/jdk.internal.vm.annotation 53 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 54 * @run main/othervm/timeout=450 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI compiler.valhalla.inlinetypes.TestCallingConvention 55 */ 56 57 @ForceCompileClassInitializer 58 public class TestCallingConvention { 59 60 private final static WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 61 62 static { 63 try { 64 Class<?> clazz = TestCallingConvention.class; 65 MethodHandles.Lookup lookup = MethodHandles.lookup(); 66 67 MethodType mt = MethodType.methodType(MyValue2.class, boolean.class); 68 test32_mh = lookup.findVirtual(clazz, "test32_interp", mt); 69 70 mt = MethodType.methodType(Object.class, boolean.class); 71 test33_mh = lookup.findVirtual(clazz, "test33_interp", mt); 72 73 mt = MethodType.methodType(int.class); 74 test37_mh = lookup.findVirtual(Test37Value.class, "test", mt); 75 76 mt = MethodType.methodType(MyValue2.class); 77 test54_mh = lookup.findVirtual(clazz, "test54_callee", mt); 78 79 mt = MethodType.methodType(MyValue2.class, boolean.class); 80 test56_mh = lookup.findVirtual(clazz, "test56_callee", mt); 81 } catch (NoSuchMethodException | IllegalAccessException e) { 82 e.printStackTrace(); 83 throw new RuntimeException("Method handle lookup failed"); 84 } 85 } 86 87 public static void main(String[] args) { 88 89 Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; 90 // Don't generate bytecodes but call through runtime for reflective calls 91 scenarios[0].addFlags("-Dsun.reflect.inflationThreshold=10000"); 92 scenarios[1].addFlags("-Dsun.reflect.inflationThreshold=10000"); 93 scenarios[3].addFlags("-XX:-UseArrayFlattening"); 94 scenarios[4].addFlags("-XX:-UseTLAB"); 95 96 InlineTypes.getFramework() 97 .addScenarios(scenarios) 98 .addHelperClasses(MyValue1.class, 99 MyValue2.class, 100 MyValue2Inline.class, 101 MyValue3.class, 102 MyValue3Inline.class, 103 MyValue4.class) 104 .start(); 105 } 106 107 // Helper methods and classes 108 109 private void deoptimize(String name, Class<?>... params) { 110 try { 111 TestFramework.deoptimize(getClass().getDeclaredMethod(name, params)); 112 } catch (NoSuchMethodException e) { 113 throw new RuntimeException(e); 114 } 115 } 116 117 // Test interpreter to compiled code with various signatures 118 @Test 119 @IR(failOn = {ALLOC, STORE, TRAP}) 120 public long test1(MyValue2 v) { 121 return v.hash(); 122 } 123 124 @Run(test = "test1") 125 public void test1_verifier() { 126 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 127 long result = test1(v); 128 Asserts.assertEQ(result, v.hashInterpreted()); 129 } 130 131 @Test 132 @IR(failOn = {ALLOC, STORE, TRAP}) 133 public long test2(int i1, MyValue2 v, int i2) { 134 return v.hash() + i1 - i2; 135 } 136 137 @Run(test = "test2") 138 public void test2_verifier() { 139 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 140 long result = test2(rI, v, 2*rI); 141 Asserts.assertEQ(result, v.hashInterpreted() - rI); 142 } 143 144 @Test 145 @IR(failOn = {ALLOC, STORE, TRAP}) 146 public long test3(long l1, MyValue2 v, long l2) { 147 return v.hash() + l1 - l2; 148 } 149 150 @Run(test = "test3") 151 public void test3_verifier() { 152 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 153 long result = test3(rL, v, 2*rL); 154 Asserts.assertEQ(result, v.hashInterpreted() - rL); 155 } 156 157 @Test 158 @IR(failOn = {ALLOC, STORE, TRAP}) 159 public long test4(int i, MyValue2 v, long l) { 160 return v.hash() + i + l; 161 } 162 163 @Run(test = "test4") 164 public void test4_verifier() { 165 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 166 long result = test4(rI, v, rL); 167 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 168 } 169 170 @Test 171 @IR(failOn = {ALLOC, STORE, TRAP}) 172 public long test5(long l, MyValue2 v, int i) { 173 return v.hash() + i + l; 174 } 175 176 @Run(test = "test5") 177 public void test5_verifier() { 178 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 179 long result = test5(rL, v, rI); 180 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 181 } 182 183 @Test 184 @IR(failOn = {ALLOC, STORE, TRAP}) 185 public long test6(long l, MyValue1 v1, int i, MyValue2 v2) { 186 return v1.hash() + i + l + v2.hash(); 187 } 188 189 @Run(test = "test6") 190 public void test6_verifier() { 191 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 192 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, rD); 193 long result = test6(rL, v1, rI, v2); 194 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 195 } 196 197 // Test compiled code to interpreter with various signatures 198 @DontCompile 199 public long test7_interp(MyValue2 v) { 200 return v.hash(); 201 } 202 203 @Test 204 @IR(failOn = {ALLOC, STORE, TRAP}) 205 public long test7(MyValue2 v) { 206 return test7_interp(v); 207 } 208 209 @Run(test = "test7") 210 public void test7_verifier() { 211 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 212 long result = test7(v); 213 Asserts.assertEQ(result, v.hashInterpreted()); 214 } 215 216 @DontCompile 217 public long test8_interp(int i1, MyValue2 v, int i2) { 218 return v.hash() + i1 - i2; 219 } 220 221 @Test 222 @IR(failOn = {ALLOC, STORE, TRAP}) 223 public long test8(int i1, MyValue2 v, int i2) { 224 return test8_interp(i1, v, i2); 225 } 226 227 @Run(test = "test8") 228 public void test8_verifier() { 229 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 230 long result = test8(rI, v, 2*rI); 231 Asserts.assertEQ(result, v.hashInterpreted() - rI); 232 } 233 234 @DontCompile 235 public long test9_interp(long l1, MyValue2 v, long l2) { 236 return v.hash() + l1 - l2; 237 } 238 239 @Test 240 @IR(failOn = {ALLOC, STORE, TRAP}) 241 public long test9(long l1, MyValue2 v, long l2) { 242 return test9_interp(l1, v, l2); 243 } 244 245 @Run(test = "test9") 246 public void test9_verifier() { 247 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 248 long result = test9(rL, v, 2*rL); 249 Asserts.assertEQ(result, v.hashInterpreted() - rL); 250 } 251 252 @DontCompile 253 public long test10_interp(int i, MyValue2 v, long l) { 254 return v.hash() + i + l; 255 } 256 257 @Test 258 @IR(failOn = {ALLOC, STORE, TRAP}) 259 public long test10(int i, MyValue2 v, long l) { 260 return test10_interp(i, v, l); 261 } 262 263 @Run(test = "test10") 264 public void test10_verifier() { 265 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 266 long result = test10(rI, v, rL); 267 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 268 } 269 270 @DontCompile 271 public long test11_interp(long l, MyValue2 v, int i) { 272 return v.hash() + i + l; 273 } 274 275 @Test 276 @IR(failOn = {ALLOC, STORE, TRAP}) 277 public long test11(long l, MyValue2 v, int i) { 278 return test11_interp(l, v, i); 279 } 280 281 @Run(test = "test11") 282 public void test11_verifier() { 283 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 284 long result = test11(rL, v, rI); 285 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 286 } 287 288 @DontCompile 289 public long test12_interp(long l, MyValue1 v1, int i, MyValue2 v2) { 290 return v1.hash() + i + l + v2.hash(); 291 } 292 293 @Test 294 @IR(failOn = {ALLOC, STORE, TRAP}) 295 public long test12(long l, MyValue1 v1, int i, MyValue2 v2) { 296 return test12_interp(l, v1, i, v2); 297 } 298 299 @Run(test = "test12") 300 public void test12_verifier() { 301 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 302 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, rD); 303 long result = test12(rL, v1, rI, v2); 304 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 305 } 306 307 // Test that debug info at a call is correct 308 @DontCompile 309 public long test13_interp(MyValue2 v, MyValue1[] va, boolean deopt) { 310 if (deopt) { 311 // uncommon trap 312 deoptimize("test13", MyValue2.class, MyValue1[].class, boolean.class, long.class); 313 } 314 return v.hash() + va[0].hash() + va[1].hash(); 315 } 316 317 @Test 318 @IR(failOn = {ALLOC, STORE, TRAP}) 319 public long test13(MyValue2 v, MyValue1[] va, boolean flag, long l) { 320 return test13_interp(v, va, flag) + l; 321 } 322 323 @Run(test = "test13") 324 public void test13_verifier(RunInfo info) { 325 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 326 MyValue1[] va = (MyValue1[])ValueClass.newNullRestrictedNonAtomicArray(MyValue1.class, 2, MyValue1.DEFAULT); 327 va[0] = MyValue1.createWithFieldsDontInline(rI, rL); 328 va[1] = MyValue1.createWithFieldsDontInline(rI, rL); 329 long result = test13(v, va, !info.isWarmUp(), rL); 330 Asserts.assertEQ(result, v.hashInterpreted() + va[0].hash() + va[1].hash() + rL); 331 } 332 333 // Test deoptimization at call return with value object returned in registers 334 @DontCompile 335 public MyValue2 test14_interp(boolean deopt) { 336 if (deopt) { 337 // uncommon trap 338 deoptimize("test14", boolean.class); 339 } 340 return MyValue2.createWithFieldsInline(rI, rD); 341 } 342 343 @Test 344 public MyValue2 test14(boolean flag) { 345 return test14_interp(flag); 346 } 347 348 @Run(test = "test14") 349 public void test14_verifier(RunInfo info) { 350 MyValue2 result = test14(!info.isWarmUp()); 351 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 352 Asserts.assertEQ(result.hash(), v.hash()); 353 } 354 355 // Return value objects in registers from interpreter -> compiled 356 @Strict 357 @NullRestricted 358 final MyValue3 test15_vt = MyValue3.create(); 359 360 @DontCompile 361 public MyValue3 test15_interp() { 362 return test15_vt; 363 } 364 365 @Test 366 @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, 367 failOn = {ALLOC, TRAP}) 368 public MyValue3 test15() { 369 return test15_interp(); 370 } 371 372 @Run(test = "test15") 373 public void test15_verifier() { 374 test15_vt.verify(test15()); 375 } 376 377 // Return value objects in registers from compiled -> interpreter 378 @Strict 379 @NullRestricted 380 final MyValue3 test16_vt = MyValue3.create(); 381 382 @Test 383 @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, 384 failOn = {ALLOC, STORE, TRAP}) 385 public MyValue3 test16() { 386 return test16_vt; 387 } 388 389 @Run(test = "test16") 390 public void test16_verifier() { 391 MyValue3 vt = test16(); 392 test16_vt.verify(vt); 393 } 394 395 // Return value objects in registers from compiled -> compiled 396 @Strict 397 @NullRestricted 398 final MyValue3 test17_vt = MyValue3.create(); 399 400 @DontInline 401 public MyValue3 test17_comp() { 402 return test17_vt; 403 } 404 405 @Test 406 @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, 407 failOn = {ALLOC, TRAP}) 408 public MyValue3 test17() { 409 return test17_comp(); 410 } 411 412 @Run(test = "test17") 413 public void test17_verifier(RunInfo info) throws Exception { 414 Method helper_m = getClass().getDeclaredMethod("test17_comp"); 415 if (!info.isWarmUp() && TestFramework.isCompiled(helper_m)) { 416 TestFramework.compile(helper_m, CompLevel.C2); 417 TestFramework.assertCompiledByC2(helper_m); 418 } 419 420 test17_vt.verify(test17()); 421 } 422 423 // Same tests as above but with a value class that cannot be returned in registers 424 425 // Return value objects in registers from interpreter -> compiled 426 @Strict 427 @NullRestricted 428 final MyValue4 test18_vt = MyValue4.create(); 429 430 @DontCompile 431 public MyValue4 test18_interp() { 432 return test18_vt; 433 } 434 435 MyValue4 test18_vt2; 436 437 @Test 438 public void test18() { 439 test18_vt2 = test18_interp(); 440 } 441 442 @Run(test = "test18") 443 public void test18_verifier() { 444 test18(); 445 test18_vt.verify(test18_vt2); 446 } 447 448 // Return value objects in registers from compiled -> interpreter 449 @Strict 450 @NullRestricted 451 final MyValue4 test19_vt = MyValue4.create(); 452 453 @Test 454 public MyValue4 test19() { 455 return test19_vt; 456 } 457 458 @Run(test = "test19") 459 public void test19_verifier() { 460 MyValue4 vt = test19(); 461 test19_vt.verify(vt); 462 } 463 464 // Return value objects in registers from compiled -> compiled 465 @Strict 466 @NullRestricted 467 final MyValue4 test20_vt = MyValue4.create(); 468 469 @DontInline 470 public MyValue4 test20_comp() { 471 return test20_vt; 472 } 473 474 MyValue4 test20_vt2; 475 476 @Test 477 public void test20() { 478 test20_vt2 = test20_comp(); 479 } 480 481 @Run(test = "test20") 482 public void test20_verifier(RunInfo info) throws Exception { 483 Method helper_m = getClass().getDeclaredMethod("test20_comp"); 484 if (!info.isWarmUp() && TestFramework.isCompiled(helper_m)) { 485 TestFramework.compile(helper_m, CompLevel.C2); 486 TestFramework.assertCompiledByC2(helper_m); 487 } 488 test20(); 489 test20_vt.verify(test20_vt2); 490 } 491 492 // Test no result from inlined method for incremental inlining 493 @Strict 494 @NullRestricted 495 final MyValue3 test21_vt = MyValue3.create(); 496 497 public MyValue3 test21_inlined() { 498 throw new RuntimeException(); 499 } 500 501 @Test 502 public MyValue3 test21() { 503 try { 504 return test21_inlined(); 505 } catch (RuntimeException ex) { 506 return test21_vt; 507 } 508 } 509 510 @Run(test = "test21") 511 public void test21_verifier() { 512 MyValue3 vt = test21(); 513 test21_vt.verify(vt); 514 } 515 516 // Test returning a non-flattened value object as fields 517 MyValue3 test22_vt = MyValue3.create(); 518 519 @Test 520 public MyValue3 test22() { 521 return (MyValue3) test22_vt; 522 } 523 524 @Run(test = "test22") 525 public void test22_verifier() { 526 MyValue3 vt = test22(); 527 test22_vt.verify(vt); 528 } 529 530 // Test calling a method that has circular register/stack dependencies when unpacking value class arguments 531 @LooselyConsistentValue 532 static value class TestValue23 { 533 double f1; 534 535 TestValue23(double val) { 536 f1 = val; 537 } 538 } 539 540 static double test23Callee(int i1, int i2, int i3, int i4, int i5, int i6, 541 TestValue23 v1, TestValue23 v2, TestValue23 v3, TestValue23 v4, TestValue23 v5, TestValue23 v6, TestValue23 v7, TestValue23 v8, 542 double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8) { 543 return i1 + i2 + i3 + i4 + i5 + i6 + v1.f1 + v2.f1 + v3.f1 + v4.f1 + v5.f1 + v6.f1 + v7.f1 + v8.f1 + d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8; 544 } 545 546 @Test 547 public double test23(int i1, int i2, int i3, int i4, int i5, int i6, 548 TestValue23 v1, TestValue23 v2, TestValue23 v3, TestValue23 v4, TestValue23 v5, TestValue23 v6, TestValue23 v7, TestValue23 v8, 549 double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8) { 550 return test23Callee(i1, i2, i3, i4, i5, i6, 551 v1, v2, v3, v4, v5, v6, v7, v8, 552 d1, d2, d3, d4, d5, d6, d7, d8); 553 } 554 555 @Run(test = "test23") 556 public void test23_verifier() { 557 TestValue23 vt = new TestValue23(rI); 558 double res1 = test23(rI, rI, rI, rI, rI, rI, 559 vt, vt, vt, vt, vt, vt, vt, vt, 560 rI, rI, rI, rI, rI, rI, rI, rI); 561 double res2 = test23Callee(rI, rI, rI, rI, rI, rI, 562 vt, vt, vt, vt, vt, vt, vt, vt, 563 rI, rI, rI, rI, rI, rI, rI, rI); 564 double res3 = 6*rI + 8*rI + 8*rI; 565 Asserts.assertEQ(res1, res2); 566 Asserts.assertEQ(res2, res3); 567 } 568 569 // Should not return a nullable value object as fields 570 @Test 571 public MyValue2 test24() { 572 return null; 573 } 574 575 @Run(test = "test24") 576 public void test24_verifier() { 577 MyValue2 vt = test24(); 578 Asserts.assertEQ(vt, null); 579 } 580 581 // Same as test24 but with control flow and inlining 582 @ForceInline 583 public MyValue2 test26_callee(boolean b) { 584 if (b) { 585 return null; 586 } else { 587 return MyValue2.createWithFieldsInline(rI, rD); 588 } 589 } 590 591 @Test 592 public MyValue2 test26(boolean b) { 593 return test26_callee(b); 594 } 595 596 @Run(test = "test26") 597 public void test26_verifier() { 598 MyValue2 vt = test26(true); 599 Asserts.assertEQ(vt, null); 600 vt = test26(false); 601 Asserts.assertEQ(vt.hash(), MyValue2.createWithFieldsInline(rI, rD).hash()); 602 } 603 604 // Test calling convention with deep hierarchy of flattened fields 605 @LooselyConsistentValue 606 static value class Test27Value1 { 607 Test27Value2 valueField; 608 609 private Test27Value1(Test27Value2 val2) { 610 valueField = val2; 611 } 612 613 @DontInline 614 public int test(Test27Value1 val1) { 615 return valueField.test(valueField) + val1.valueField.test(valueField); 616 } 617 } 618 619 @LooselyConsistentValue 620 static value class Test27Value2 { 621 Test27Value3 valueField; 622 623 private Test27Value2(Test27Value3 val3) { 624 valueField = val3; 625 } 626 627 @DontInline 628 public int test(Test27Value2 val2) { 629 return valueField.test(valueField) + val2.valueField.test(valueField); 630 } 631 } 632 633 @LooselyConsistentValue 634 static value class Test27Value3 { 635 int x; 636 637 private Test27Value3(int x) { 638 this.x = x; 639 } 640 641 @DontInline 642 public int test(Test27Value3 val3) { 643 return x + val3.x; 644 } 645 } 646 647 @Test 648 public int test27(Test27Value1 val) { 649 return val.test(val); 650 } 651 652 @Run(test = "test27") 653 public void test27_verifier() { 654 Test27Value3 val3 = new Test27Value3(rI); 655 Test27Value2 val2 = new Test27Value2(val3); 656 Test27Value1 val1 = new Test27Value1(val2); 657 int result = test27(val1); 658 Asserts.assertEQ(result, 8*rI); 659 } 660 661 static final MyValue1 test28Val = MyValue1.createWithFieldsDontInline(rI, rL); 662 663 @Test 664 public String test28() { 665 return test28Val.toString(); 666 } 667 668 @Run(test = "test28") 669 @Warmup(0) 670 public void test28_verifier() { 671 String result = test28(); 672 } 673 674 // Test calling a method returning a value object as fields via reflection 675 @Strict 676 @NullRestricted 677 MyValue3 test29_vt = MyValue3.create(); 678 679 @Test 680 public MyValue3 test29() { 681 return test29_vt; 682 } 683 684 @Run(test = "test29") 685 public void test29_verifier() throws Exception { 686 MyValue3 vt = (MyValue3)TestCallingConvention.class.getDeclaredMethod("test29").invoke(this); 687 test29_vt.verify(vt); 688 } 689 690 @Test 691 public MyValue3 test30(MyValue3[] array) { 692 MyValue3 result = MyValue3.create(); 693 array[0] = result; 694 return result; 695 } 696 697 @Run(test = "test30") 698 public void test30_verifier() throws Exception { 699 MyValue3[] array = (MyValue3[])ValueClass.newNullRestrictedNonAtomicArray(MyValue3.class, 1, MyValue3.DEFAULT); 700 MyValue3 vt = (MyValue3)TestCallingConvention.class.getDeclaredMethod("test30", MyValue3[].class).invoke(this, (Object)array); 701 array[0].verify(vt); 702 } 703 704 MyValue3 test31_vt; 705 706 @Test 707 public MyValue3 test31() { 708 MyValue3 result = MyValue3.create(); 709 test31_vt = result; 710 return result; 711 } 712 713 @Run(test = "test31") 714 public void test31_verifier() throws Exception { 715 MyValue3 vt = (MyValue3)TestCallingConvention.class.getDeclaredMethod("test31").invoke(this); 716 test31_vt.verify(vt); 717 } 718 719 // Test deoptimization at call return with value object returned in registers. 720 // Same as test14, except the interpreted method is called via a MethodHandle. 721 static MethodHandle test32_mh; 722 723 @DontCompile 724 public MyValue2 test32_interp(boolean deopt) { 725 if (deopt) { 726 // uncommon trap 727 deoptimize("test32", boolean.class); 728 } 729 return MyValue2.createWithFieldsInline(rI+32, rD); 730 } 731 732 @Test 733 public MyValue2 test32(boolean flag) throws Throwable { 734 return (MyValue2)test32_mh.invokeExact(this, flag); 735 } 736 737 @Run(test = "test32") 738 public void test32_verifier(RunInfo info) throws Throwable { 739 MyValue2 result = test32(!info.isWarmUp()); 740 MyValue2 v = MyValue2.createWithFieldsInline(rI+32, rD); 741 Asserts.assertEQ(result.hash(), v.hash()); 742 } 743 744 // Same as test32, except the return type is not flattenable. 745 static MethodHandle test33_mh; 746 747 @DontCompile 748 public Object test33_interp(boolean deopt) { 749 if (deopt) { 750 // uncommon trap 751 deoptimize("test33", boolean.class); 752 } 753 return MyValue2.createWithFieldsInline(rI+33, rD); 754 } 755 756 @Test 757 public MyValue2 test33(boolean flag) throws Throwable { 758 Object o = test33_mh.invokeExact(this, flag); 759 return (MyValue2)o; 760 } 761 762 @Run(test = "test33") 763 public void test33_verifier(RunInfo info) throws Throwable { 764 MyValue2 result = test33(!info.isWarmUp()); 765 MyValue2 v = MyValue2.createWithFieldsInline(rI+33, rD); 766 Asserts.assertEQ(result.hash(), v.hash()); 767 } 768 769 // Test selection of correct entry point in SharedRuntime::handle_wrong_method 770 static boolean test34_deopt = false; 771 772 @DontInline 773 public static long test34_callee(MyValue2 vt, int i1, int i2, int i3, int i4) { 774 Asserts.assertEQ(i1, rI); 775 Asserts.assertEQ(i2, rI); 776 Asserts.assertEQ(i3, rI); 777 Asserts.assertEQ(i4, rI); 778 779 if (test34_deopt) { 780 // uncommon trap 781 int result = 0; 782 for (int i = 0; i < 10; ++i) { 783 result += rL; 784 } 785 return vt.hash() + i1 + i2 + i3 + i4 + result; 786 } 787 return vt.hash() + i1 + i2 + i3 + i4; 788 } 789 790 @Test 791 public static long test34(MyValue2 vt, int i1, int i2, int i3, int i4) { 792 return test34_callee(vt, i1, i2, i3, i4); 793 } 794 795 @Run(test = "test34") 796 @Warmup(10000) // Make sure test34_callee is compiled 797 public void test34_verifier(RunInfo info) { 798 MyValue2 vt = MyValue2.createWithFieldsInline(rI, rD); 799 long result = test34(vt, rI, rI, rI, rI); 800 Asserts.assertEQ(result, vt.hash()+4*rI); 801 if (!info.isWarmUp()) { 802 test34_deopt = true; 803 for (int i = 0; i < 100; ++i) { 804 result = test34(vt, rI, rI, rI, rI); 805 Asserts.assertEQ(result, vt.hash()+4*rI+10*rL); 806 } 807 } 808 } 809 810 // Test OSR compilation of method with scalarized argument 811 @Test 812 public static long test35(MyValue2 vt, int i1, int i2, int i3, int i4) { 813 int result = 0; 814 // Trigger OSR compilation 815 for (int i = 0; i < 10_000; ++i) { 816 result += i1; 817 } 818 return vt.hash() + i1 + i2 + i3 + i4 + result; 819 } 820 821 @Run(test = "test35") 822 public void test35_verifier() { 823 MyValue2 vt = MyValue2.createWithFieldsInline(rI, rD); 824 long result = test35(vt, rI, rI, rI, rI); 825 Asserts.assertEQ(result, vt.hash()+10004*rI); 826 } 827 828 // Same as test31 but with GC in callee to verify that the 829 // pre-allocated buffer for the returned value object remains valid. 830 MyValue3 test36_vt; 831 832 @Test 833 public MyValue3 test36() { 834 MyValue3 result = MyValue3.create(); 835 test36_vt = result; 836 System.gc(); 837 return result; 838 } 839 840 @Run(test = "test36") 841 public void test36_verifier() throws Exception { 842 MyValue3 vt = (MyValue3)TestCallingConvention.class.getDeclaredMethod("test36").invoke(this); 843 test36_vt.verify(vt); 844 } 845 846 // Test method resolution with scalarized value object receiver at invokespecial 847 static final MethodHandle test37_mh; 848 849 @LooselyConsistentValue 850 static value class Test37Value { 851 int x = rI; 852 853 @DontInline 854 public int test() { 855 return x; 856 } 857 } 858 859 @Test 860 public int test37(Test37Value vt) throws Throwable { 861 // Generates invokespecial call of Test37Value::test 862 return (int)test37_mh.invokeExact(vt); 863 } 864 865 @Run(test = "test37") 866 public void test37_verifier() throws Throwable { 867 Test37Value vt = new Test37Value(); 868 int res = test37(vt); 869 Asserts.assertEQ(res, rI); 870 } 871 872 // Test passing/returning an empty value object 873 @Test 874 @IR(failOn = {ALLOC, LOAD, STORE, TRAP}) 875 public MyValueEmpty test38(MyValueEmpty vt) { 876 return vt.copy(vt); 877 } 878 879 @Run(test = "test38") 880 public void test38_verifier() { 881 MyValueEmpty vt = new MyValueEmpty(); 882 MyValueEmpty res = test38(vt); 883 Asserts.assertEQ(res, vt); 884 } 885 886 @LooselyConsistentValue 887 static value class LargeValueWithOops { 888 // Use all 6 int registers + 50/2 on stack = 29 889 Object o1 = null; 890 Object o2 = null; 891 Object o3 = null; 892 Object o4 = null; 893 Object o5 = null; 894 Object o6 = null; 895 Object o7 = null; 896 Object o8 = null; 897 Object o9 = null; 898 Object o10 = null; 899 Object o11 = null; 900 Object o12 = null; 901 Object o13 = null; 902 Object o14 = null; 903 Object o15 = null; 904 Object o16 = null; 905 Object o17 = null; 906 Object o18 = null; 907 Object o19 = null; 908 Object o20 = null; 909 Object o21 = null; 910 Object o22 = null; 911 Object o23 = null; 912 Object o24 = null; 913 Object o25 = null; 914 Object o26 = null; 915 Object o27 = null; 916 Object o28 = null; 917 Object o29 = null; 918 } 919 920 @LooselyConsistentValue 921 static value class LargeValueWithoutOops { 922 // Use all 6 int registers + 50/2 on stack = 29 923 int i1 = 0; 924 int i2 = 0; 925 int i3 = 0; 926 int i4 = 0; 927 int i5 = 0; 928 int i6 = 0; 929 int i7 = 0; 930 int i8 = 0; 931 int i9 = 0; 932 int i10 = 0; 933 int i11 = 0; 934 int i12 = 0; 935 int i13 = 0; 936 int i14 = 0; 937 int i15 = 0; 938 int i16 = 0; 939 int i17 = 0; 940 int i18 = 0; 941 int i19 = 0; 942 int i20 = 0; 943 int i21 = 0; 944 int i22 = 0; 945 int i23 = 0; 946 int i24 = 0; 947 int i25 = 0; 948 int i26 = 0; 949 int i27 = 0; 950 int i28 = 0; 951 int i29 = 0; 952 // Use all 7 float registers 953 double d1 = 0; 954 double d2 = 0; 955 double d3 = 0; 956 double d4 = 0; 957 double d5 = 0; 958 double d6 = 0; 959 double d7 = 0; 960 double d8 = 0; 961 } 962 963 // Test passing/returning a large value object with oop fields 964 @Test 965 public static LargeValueWithOops test39(LargeValueWithOops vt) { 966 return vt; 967 } 968 969 @Run(test = "test39") 970 public void test39_verifier() { 971 LargeValueWithOops vt = new LargeValueWithOops(); 972 LargeValueWithOops res = test39(vt); 973 Asserts.assertEQ(res, vt); 974 } 975 976 // Test passing/returning a large value object with only int/float fields 977 @Test 978 public static LargeValueWithoutOops test40(LargeValueWithoutOops vt) { 979 return vt; 980 } 981 982 @Run(test = "test40") 983 public void test40_verifier() { 984 LargeValueWithoutOops vt = new LargeValueWithoutOops(); 985 LargeValueWithoutOops res = test40(vt); 986 Asserts.assertEQ(res, vt); 987 } 988 989 // Test passing/returning an empty value object together with non-empty 990 // value objects such that only some value class arguments are scalarized. 991 @Test 992 @IR(failOn = {ALLOC, LOAD, STORE, TRAP}) 993 public MyValueEmpty test41(MyValue1 vt1, MyValueEmpty vt2, MyValue1 vt3) { 994 return vt2.copy(vt2); 995 } 996 997 @Run(test = "test41") 998 public void test41_verifier() { 999 MyValueEmpty res = test41(MyValue1.createDefaultInline(), new MyValueEmpty(), MyValue1.createDefaultInline()); 1000 Asserts.assertEQ(res, new MyValueEmpty()); 1001 } 1002 1003 // More empty value class tests with containers 1004 1005 @LooselyConsistentValue 1006 static value class EmptyContainer { 1007 @Strict 1008 @NullRestricted 1009 private MyValueEmpty empty; 1010 1011 @ForceInline 1012 EmptyContainer(MyValueEmpty empty) { 1013 this.empty = empty; 1014 } 1015 1016 @ForceInline 1017 MyValueEmpty getInline() { return empty; } 1018 1019 @DontInline 1020 MyValueEmpty getNoInline() { return empty; } 1021 } 1022 1023 @LooselyConsistentValue 1024 static value class MixedContainer { 1025 public int val; 1026 @Strict 1027 @NullRestricted 1028 private EmptyContainer empty; 1029 1030 @ForceInline 1031 MixedContainer(int val, EmptyContainer empty) { 1032 this.val = val; 1033 this.empty = empty; 1034 } 1035 1036 @ForceInline 1037 EmptyContainer getInline() { return empty; } 1038 1039 @DontInline 1040 EmptyContainer getNoInline() { return empty; } 1041 } 1042 1043 // Empty value object return 1044 @Test 1045 @IR(failOn = {LOAD, STORE, TRAP}) 1046 @IR(applyIf = {"InlineTypeReturnedAsFields", "true"}, 1047 failOn = {ALLOC}) 1048 public MyValueEmpty test42() { 1049 EmptyContainer c = new EmptyContainer(new MyValueEmpty()); 1050 return c.getInline(); 1051 } 1052 1053 @Run(test = "test42") 1054 public void test42_verifier() { 1055 MyValueEmpty empty = test42(); 1056 Asserts.assertEquals(empty, new MyValueEmpty()); 1057 } 1058 1059 // Empty value class container return 1060 @Test 1061 @IR(failOn = {ALLOC, LOAD, STORE, TRAP}) 1062 public EmptyContainer test43(EmptyContainer c) { 1063 return c; 1064 } 1065 1066 @Run(test = "test43") 1067 public void test43_verifier() { 1068 EmptyContainer empty = new EmptyContainer(new MyValueEmpty()); 1069 EmptyContainer c = test43(empty); 1070 Asserts.assertEquals(c, empty); 1071 } 1072 1073 // Empty value class container (mixed) return 1074 @Test 1075 @IR(failOn = {ALLOC, LOAD, STORE, TRAP}) 1076 public MixedContainer test44() { 1077 MixedContainer c = new MixedContainer(rI, new EmptyContainer(new MyValueEmpty())); 1078 c = new MixedContainer(rI, c.getInline()); 1079 return c; 1080 } 1081 1082 @Run(test = "test44") 1083 public void test44_verifier() { 1084 MixedContainer c = test44(); 1085 Asserts.assertEquals(c, new MixedContainer(rI, new EmptyContainer(new MyValueEmpty()))); 1086 } 1087 1088 // Empty value class container argument 1089 @Test 1090 @IR(failOn = {ALLOC, LOAD, STORE, TRAP}) 1091 public EmptyContainer test45(EmptyContainer c) { 1092 return new EmptyContainer(c.getInline()); 1093 } 1094 1095 @Run(test = "test45") 1096 public void test45_verifier() { 1097 EmptyContainer empty = new EmptyContainer(new MyValueEmpty()); 1098 EmptyContainer c = test45(empty); 1099 Asserts.assertEquals(c, empty); 1100 } 1101 1102 // Empty value class container and mixed container arguments 1103 @Test 1104 @IR(failOn = {ALLOC, STORE, TRAP}) 1105 public MyValueEmpty test46(EmptyContainer c1, MixedContainer c2, MyValueEmpty empty) { 1106 c2 = new MixedContainer(c2.val, c1); 1107 return c2.getNoInline().getNoInline(); 1108 } 1109 1110 @Run(test = "test46") 1111 public void test46_verifier() { 1112 MyValueEmpty empty = test46(new EmptyContainer(new MyValueEmpty()), new MixedContainer(0, new EmptyContainer(new MyValueEmpty())), new MyValueEmpty()); 1113 Asserts.assertEquals(empty, new MyValueEmpty()); 1114 } 1115 1116 // No receiver and only empty argument 1117 @Test 1118 @IR(failOn = {ALLOC, LOAD, STORE, TRAP}) 1119 public static MyValueEmpty test47(MyValueEmpty empty) { 1120 return empty; 1121 } 1122 1123 @Run(test = "test47") 1124 public void test47_verifier() { 1125 MyValueEmpty empty = test47(new MyValueEmpty()); 1126 Asserts.assertEquals(empty,new MyValueEmpty()); 1127 } 1128 1129 // No receiver and only empty container argument 1130 @Test 1131 @IR(failOn = {ALLOC, LOAD, STORE, TRAP}) 1132 public static MyValueEmpty test48(EmptyContainer empty) { 1133 return empty.getNoInline(); 1134 } 1135 1136 @Run(test = "test48") 1137 public void test48_verifier() { 1138 MyValueEmpty empty = test48(new EmptyContainer(new MyValueEmpty())); 1139 Asserts.assertEquals(empty, new MyValueEmpty()); 1140 } 1141 1142 // Test conditional value class return with incremental inlining 1143 public MyValue3 test49_inlined1(boolean b) { 1144 if (b) { 1145 return MyValue3.create(); 1146 } else { 1147 return MyValue3.create(); 1148 } 1149 } 1150 1151 public MyValue3 test49_inlined2(boolean b) { 1152 return test49_inlined1(b); 1153 } 1154 1155 @Test 1156 public void test49(boolean b) { 1157 test49_inlined2(b); 1158 } 1159 1160 @Run(test = "test49") 1161 public void test49_verifier() { 1162 test49(true); 1163 test49(false); 1164 } 1165 1166 // Variant of test49 with result verification (triggered different failure mode) 1167 @Strict 1168 @NullRestricted 1169 final MyValue3 test50_vt = MyValue3.create(); 1170 @Strict 1171 @NullRestricted 1172 final MyValue3 test50_vt2 = MyValue3.create(); 1173 1174 public MyValue3 test50_inlined1(boolean b) { 1175 if (b) { 1176 return test50_vt; 1177 } else { 1178 return test50_vt2; 1179 } 1180 } 1181 1182 public MyValue3 test50_inlined2(boolean b) { 1183 return test50_inlined1(b); 1184 } 1185 1186 @Test 1187 public void test50(boolean b) { 1188 MyValue3 vt = test50_inlined2(b); 1189 vt.verify(b ? test50_vt : test50_vt2); 1190 } 1191 1192 @Run(test = "test50") 1193 public void test50_verifier() { 1194 test50(true); 1195 test50(false); 1196 } 1197 1198 // Test stack repair with stack slots reserved for monitors 1199 private static final Object lock1 = new Object(); 1200 private static final Object lock2 = new Object(); 1201 private static final Object lock3 = new Object(); 1202 1203 @DontInline 1204 static void test51_callee() { } 1205 1206 @Test 1207 public void test51(MyValue1 val) { 1208 synchronized (lock1) { 1209 test51_callee(); 1210 } 1211 } 1212 1213 @Run(test = "test51") 1214 public void test51_verifier() { 1215 MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL); 1216 test51(vt); 1217 } 1218 1219 @DontInline 1220 static void test52_callee() { } 1221 1222 @Test 1223 public void test52(MyValue1 val) { 1224 synchronized (lock1) { 1225 synchronized (lock2) { 1226 test52_callee(); 1227 } 1228 } 1229 } 1230 1231 @Run(test = "test52") 1232 public void test52_verifier() { 1233 MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL); 1234 test52(vt); 1235 } 1236 1237 @DontInline 1238 static void test53_callee() { } 1239 1240 @Test 1241 public void test53(MyValue1 val) { 1242 synchronized (lock1) { 1243 synchronized (lock2) { 1244 synchronized (lock3) { 1245 test53_callee(); 1246 } 1247 } 1248 } 1249 } 1250 1251 @Run(test = "test53") 1252 public void test53_verifier() { 1253 MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL); 1254 test53(vt); 1255 } 1256 1257 static MethodHandle test54_mh; 1258 1259 @DontInline 1260 public MyValue2 test54_callee() { 1261 return MyValue2.createWithFieldsInline(rI, rD); 1262 } 1263 1264 // Test that method handle invocation does not block scalarization of return value 1265 @Test 1266 @IR(failOn = {ALLOC_G, STORE}) 1267 public long test54(Method m, boolean b1, boolean b2) throws Throwable { 1268 MyInterface obj = MyValue2.createWithFieldsInline(rI, rD); 1269 if (b1) { 1270 obj = (MyValue2)test54_mh.invokeExact(this); 1271 } 1272 if (b2) { 1273 // Uncommon trap 1274 TestFramework.deoptimize(m); 1275 return obj.hash(); 1276 } 1277 return -1; 1278 } 1279 1280 @Run(test = "test54") 1281 @Warmup(10000) 1282 public void test54_verifier(RunInfo info) throws Throwable { 1283 Asserts.assertEQ(test54(info.getTest(), true, false), -1L); 1284 Asserts.assertEQ(test54(info.getTest(), false, false), -1L); 1285 if (!info.isWarmUp()) { 1286 MyValue2 v = MyValue2.createWithFieldsInline(rI, rD); 1287 Asserts.assertEQ(test54(info.getTest(), true, true), v.hash()); 1288 } 1289 } 1290 1291 @DontInline 1292 public MyValue2 test55_callee() { 1293 return MyValue2.createWithFieldsInline(rI, rD); 1294 } 1295 1296 // Test scalarization of nullable return value that is unused 1297 @Test 1298 public void test55() { 1299 test55_callee(); 1300 } 1301 1302 @Run(test = "test55") 1303 public void test55_verifier() { 1304 test55(); 1305 } 1306 1307 static MethodHandle test56_mh; 1308 1309 @DontInline 1310 public MyValue2 test56_callee(boolean b) { 1311 return b ? MyValue2.createWithFieldsInline(rI, rD) : null; 1312 } 1313 1314 // Test that scalarization of nullable return works properly for method handle calls 1315 @Test 1316 public MyValue2 test56(boolean b) throws Throwable { 1317 return (MyValue2)test56_mh.invokeExact(this, b); 1318 } 1319 1320 @Run(test = "test56") 1321 @Warmup(10000) 1322 public void test56_verifier(RunInfo info) throws Throwable { 1323 MyValue2 vt = MyValue2.createWithFieldsInline(rI, rD); 1324 Asserts.assertEQ(test56(true).hash(), vt.hash()); 1325 if (!info.isWarmUp()) { 1326 Asserts.assertEQ(test56(false), null); 1327 } 1328 } 1329 1330 static boolean expectedUseArrayFlattening = WHITE_BOX.getBooleanVMFlag("UseArrayFlattening"); 1331 1332 // Test value class return from native method 1333 @Test 1334 public boolean test57() { 1335 return WHITE_BOX.getBooleanVMFlag("UseArrayFlattening"); 1336 } 1337 1338 @Run(test = "test57") 1339 public void test57_verifier() { 1340 Asserts.assertEQ(test57(), expectedUseArrayFlattening); 1341 } 1342 1343 // Test abstract value class with flat fields 1344 @LooselyConsistentValue 1345 abstract value class MyAbstract58 { 1346 @Strict 1347 @NullRestricted 1348 MyValue58Inline nullfree = new MyValue58Inline(); 1349 1350 MyValue58Inline nullable = new MyValue58Inline(); 1351 } 1352 1353 @LooselyConsistentValue 1354 value class MyValue58Inline { 1355 int x = rI; 1356 } 1357 1358 @LooselyConsistentValue 1359 value class MyValue58_1 extends MyAbstract58 { 1360 } 1361 1362 @LooselyConsistentValue 1363 value class MyValue58_2 extends MyAbstract58 { 1364 int x = rI; 1365 } 1366 1367 @LooselyConsistentValue 1368 value class MyValue58_3 extends MyAbstract58 { 1369 int x = rI; 1370 1371 @Strict 1372 @NullRestricted 1373 MyValue1 nullfree = MyValue1.DEFAULT; 1374 1375 MyValue1 nullable = null; 1376 } 1377 1378 @Test 1379 public MyValue58_3 test58(MyValue58_1 arg1, MyValue58_2 arg2, MyValue58_3 arg3) { 1380 Asserts.assertEQ(arg1, new MyValue58_1()); 1381 Asserts.assertEQ(arg2, new MyValue58_2()); 1382 Asserts.assertEQ(arg3, new MyValue58_3()); 1383 return arg3; 1384 } 1385 1386 @Run(test = "test58") 1387 public void test58_verifier() { 1388 Asserts.assertEQ(test58(new MyValue58_1(), new MyValue58_2(), new MyValue58_3()), new MyValue58_3()); 1389 } 1390 }