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