1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package compiler.valhalla.valuetypes; 25 26 import java.lang.invoke.*; 27 import java.lang.reflect.Method; 28 29 import jdk.test.lib.Asserts; 30 31 /* 32 * @test 33 * @summary Test correct handling of nullable value types. 34 * @library /testlibrary /test/lib /compiler/whitebox / 35 * @requires os.simpleArch == "x64" 36 * @compile TestNullableValueTypes.java 37 * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform 38 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions 39 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla 40 * compiler.valhalla.valuetypes.ValueTypeTest 41 * compiler.valhalla.valuetypes.TestNullableValueTypes 42 */ 43 public class TestNullableValueTypes extends ValueTypeTest { 44 // Extra VM parameters for some test scenarios. See ValueTypeTest.getVMParameters() 45 @Override 46 public String[] getExtraVMParameters(int scenario) { 47 switch (scenario) { 48 case 1: return new String[] {"-XX:-UseOptoBiasInlining"}; 49 case 2: return new String[] {"-XX:-UseBiasedLocking"}; 50 case 3: return new String[] {"-XX:-MonomorphicArrayCheck", "-XX:-UseBiasedLocking", "-XX:ValueArrayElemMaxFlatSize=-1"}; 51 case 4: return new String[] {"-XX:-MonomorphicArrayCheck"}; 52 } 53 return null; 54 } 55 56 public static void main(String[] args) throws Throwable { 57 TestNullableValueTypes test = new TestNullableValueTypes(); 58 test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class, Test17Value.class, Test21Value.class); 59 } 60 61 static { 62 try { 63 Class<?> clazz = TestNullableValueTypes.class; 64 ClassLoader loader = clazz.getClassLoader(); 65 MethodHandles.Lookup lookup = MethodHandles.lookup(); 66 67 MethodType test18_mt = MethodType.methodType(void.class, MyValue1.class.asNullableType()); 68 test18_mh1 = lookup.findStatic(clazz, "test18_target1", test18_mt); 69 test18_mh2 = lookup.findStatic(clazz, "test18_target2", test18_mt); 70 71 MethodType test19_mt = MethodType.methodType(void.class, MyValue1.class.asNullableType()); 72 test19_mh1 = lookup.findStatic(clazz, "test19_target1", test19_mt); 73 test19_mh2 = lookup.findStatic(clazz, "test19_target2", test19_mt); 74 } catch (NoSuchMethodException | IllegalAccessException e) { 75 e.printStackTrace(); 76 throw new RuntimeException("Method handle lookup failed"); 77 } 78 } 79 80 private static final MyValue1 testValue1 = MyValue1.createWithFieldsInline(rI, rL); 81 private static final MyValue1[] testValue1Array = new MyValue1[] {testValue1, 82 testValue1, 83 testValue1}; 84 85 MyValue1? nullField; 86 MyValue1 valueField1 = testValue1; 87 88 @Test 89 public long test1(MyValue1? vt) { 90 long result = 0; 91 try { 92 result = vt.hash(); 93 throw new RuntimeException("NullPointerException expected"); 94 } catch (NullPointerException e) { 95 // Expected 96 } 97 return result; 98 } 99 100 @DontCompile 101 public void test1_verifier(boolean warmup) throws Throwable { 102 long result = test1(null); 103 Asserts.assertEquals(result, 0L); 104 } 105 106 @Test 107 public long test2(MyValue1? vt) { 108 long result = 0; 109 try { 110 result = vt.hashInterpreted(); 111 throw new RuntimeException("NullPointerException expected"); 112 } catch (NullPointerException e) { 113 // Expected 114 } 115 return result; 116 } 117 118 @DontCompile 119 public void test2_verifier(boolean warmup) { 120 long result = test2(nullField); 121 Asserts.assertEquals(result, 0L); 122 } 123 124 @Test 125 public long test3() { 126 long result = 0; 127 try { 128 if ((Object)nullField != null) { 129 throw new RuntimeException("nullField should be null"); 130 } 131 result = nullField.hash(); 132 throw new RuntimeException("NullPointerException expected"); 133 } catch (NullPointerException e) { 134 // Expected 135 } 136 return result; 137 } 138 139 @DontCompile 140 public void test3_verifier(boolean warmup) { 141 long result = test3(); 142 Asserts.assertEquals(result, 0L); 143 } 144 145 @Test 146 public void test4() { 147 try { 148 valueField1 = (MyValue1) nullField; 149 throw new RuntimeException("NullPointerException expected"); 150 } catch (NullPointerException e) { 151 // Expected 152 } 153 } 154 155 @DontCompile 156 public void test4_verifier(boolean warmup) { 157 test4(); 158 } 159 160 @Test 161 public MyValue1? test5(MyValue1? vt) { 162 try { 163 Object o = vt; 164 vt = (MyValue1)o; 165 throw new RuntimeException("NullPointerException expected"); 166 } catch (NullPointerException e) { 167 // Expected 168 } 169 170 // Should not throw 171 vt = test5_dontinline(vt); 172 vt = test5_inline(vt); 173 return vt; 174 } 175 176 @DontCompile 177 public void test5_verifier(boolean warmup) { 178 MyValue1? vt = test5(nullField); 179 Asserts.assertEquals((Object)vt, null); 180 } 181 182 @DontInline 183 public MyValue1? test5_dontinline(MyValue1? vt) { 184 return vt; 185 } 186 187 @ForceInline 188 public MyValue1? test5_inline(MyValue1? vt) { 189 return vt; 190 } 191 192 @Test 193 public MyValue1 test6(Object obj) { 194 MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL); 195 try { 196 vt = (MyValue1)obj; 197 throw new RuntimeException("NullPointerException expected"); 198 } catch (NullPointerException e) { 199 // Expected 200 } 201 return vt; 202 } 203 204 @DontCompile 205 public void test6_verifier(boolean warmup) { 206 MyValue1 vt = test6(null); 207 Asserts.assertEquals(vt.hash(), testValue1.hash()); 208 } 209 210 @ForceInline 211 public MyValue1? getNullInline() { 212 return null; 213 } 214 215 @DontInline 216 public MyValue1? getNullDontInline() { 217 return null; 218 } 219 220 @Test 221 public void test7() throws Throwable { 222 nullField = getNullInline(); // Should not throw 223 nullField = getNullDontInline(); // Should not throw 224 try { 225 valueField1 = (MyValue1) getNullInline(); 226 throw new RuntimeException("NullPointerException expected"); 227 } catch (NullPointerException e) { 228 // Expected 229 } 230 try { 231 valueField1 = (MyValue1) getNullDontInline(); 232 throw new RuntimeException("NullPointerException expected"); 233 } catch (NullPointerException e) { 234 // Expected 235 } 236 } 237 238 @DontCompile 239 public void test7_verifier(boolean warmup) throws Throwable { 240 test7(); 241 } 242 243 @Test 244 public void test8() throws Throwable { 245 try { 246 valueField1 = (MyValue1) nullField; 247 throw new RuntimeException("NullPointerException expected"); 248 } catch (NullPointerException e) { 249 // Expected 250 } 251 } 252 253 @DontCompile 254 public void test8_verifier(boolean warmup) throws Throwable { 255 test8(); 256 } 257 258 // merge of 2 values, one being null 259 @Test 260 public void test9(boolean flag1) { 261 MyValue1 v; 262 if (flag1) { 263 v = valueField1; 264 } else { 265 v = (MyValue1) nullField; 266 } 267 valueField1 = v; 268 } 269 270 @DontCompile 271 public void test9_verifier(boolean warmup) { 272 test9(true); 273 try { 274 test9(false); 275 throw new RuntimeException("NullPointerException expected"); 276 } catch (NullPointerException e) { 277 // Expected 278 } 279 } 280 281 // null constant 282 @Test 283 public void test10(boolean flag) throws Throwable { 284 MyValue1? val = flag ? valueField1 : null; 285 valueField1 = (MyValue1) val; 286 } 287 288 @DontCompile 289 public void test10_verifier(boolean warmup) throws Throwable { 290 test10(true); 291 try { 292 test10(false); 293 throw new RuntimeException("NullPointerException expected"); 294 } catch (NullPointerException e) { 295 // Expected 296 } 297 } 298 299 // null constant 300 @Test 301 public void test11(boolean flag) throws Throwable { 302 MyValue1? val = flag ? null : valueField1; 303 valueField1 = (MyValue1) val; 304 } 305 306 @DontCompile 307 public void test11_verifier(boolean warmup) throws Throwable { 308 test11(false); 309 try { 310 test11(true); 311 throw new RuntimeException("NullPointerException expected"); 312 } catch (NullPointerException e) { 313 // Expected 314 } 315 } 316 317 // null return 318 int test12_cnt; 319 320 @DontInline 321 public MyValue1? test12_helper() { 322 test12_cnt++; 323 return nullField; 324 } 325 326 @Test 327 public void test12() { 328 valueField1 = (MyValue1) test12_helper(); 329 } 330 331 @DontCompile 332 public void test12_verifier(boolean warmup) { 333 try { 334 test12_cnt = 0; 335 test12(); 336 throw new RuntimeException("NullPointerException expected"); 337 } catch (NullPointerException e) { 338 // Expected 339 } 340 if (test12_cnt != 1) { 341 throw new RuntimeException("call executed twice"); 342 } 343 } 344 345 // null return at virtual call 346 class A { 347 public MyValue1? test13_helper() { 348 return nullField; 349 } 350 } 351 352 class B extends A { 353 public MyValue1 test13_helper() { 354 return (MyValue1) nullField; 355 } 356 } 357 358 class C extends A { 359 public MyValue1? test13_helper() { 360 return nullField; 361 } 362 } 363 364 class D extends C { 365 public MyValue1 test13_helper() { 366 return (MyValue1) nullField; 367 } 368 } 369 370 @Test 371 public void test13(A a) { 372 valueField1 = (MyValue1) a.test13_helper(); 373 } 374 375 @DontCompile 376 public void test13_verifier(boolean warmup) { 377 A a = new A(); 378 A b = new B(); 379 A c = new C(); 380 A d = new D(); 381 try { 382 test13(a); 383 throw new RuntimeException("NullPointerException expected"); 384 } catch (NullPointerException e) { 385 // Expected 386 } 387 try { 388 test13(b); 389 throw new RuntimeException("NullPointerException expected"); 390 } catch (NullPointerException e) { 391 // Expected 392 } 393 try { 394 test13(c); 395 throw new RuntimeException("NullPointerException expected"); 396 } catch (NullPointerException e) { 397 // Expected 398 } 399 try { 400 test13(d); 401 throw new RuntimeException("NullPointerException expected"); 402 } catch (NullPointerException e) { 403 // Expected 404 } 405 } 406 407 // Test writing null to a (flattened) value type array 408 @ForceInline 409 public void test14_inline(Object[] oa, Object o, int index) { 410 oa[index] = o; 411 } 412 413 @Test() 414 public void test14(MyValue1[] va, int index) { 415 test14_inline(va, nullField, index); 416 } 417 418 @DontCompile 419 public void test14_verifier(boolean warmup) { 420 int index = Math.abs(rI) % 3; 421 try { 422 test14(testValue1Array, index); 423 throw new RuntimeException("No NPE thrown"); 424 } catch (NullPointerException e) { 425 // Expected 426 } 427 Asserts.assertEQ(testValue1Array[index].hash(), testValue1.hash()); 428 } 429 430 @DontInline 431 MyValue1? getNullField1() { 432 return nullField; 433 } 434 435 @DontInline 436 MyValue1 getNullField2() { 437 return (MyValue1) nullField; 438 } 439 440 @Test() 441 public void test15() { 442 nullField = getNullField1(); // should not throw 443 try { 444 valueField1 = (MyValue1) getNullField1(); 445 throw new RuntimeException("NullPointerException expected"); 446 } catch (NullPointerException e) { 447 // Expected 448 } 449 try { 450 valueField1 = getNullField2(); 451 throw new RuntimeException("NullPointerException expected"); 452 } catch (NullPointerException e) { 453 // Expected 454 } 455 } 456 457 @DontCompile 458 public void test15_verifier(boolean warmup) { 459 test15(); 460 } 461 462 @DontInline 463 public boolean test16_dontinline(MyValue1? vt) { 464 return (Object)vt == null; 465 } 466 467 // Test c2c call passing null for a value type 468 @Test 469 @Warmup(10000) // Warmup to make sure 'test17_dontinline' is compiled 470 public boolean test16(Object arg) throws Exception { 471 Method test16method = getClass().getMethod("test16_dontinline", MyValue1.class.asNullableType()); 472 return (boolean)test16method.invoke(this, arg); 473 } 474 475 @DontCompile 476 public void test16_verifier(boolean warmup) throws Exception { 477 boolean res = test16(null); 478 Asserts.assertTrue(res); 479 } 480 481 // Test scalarization of default value type with non-flattenable field 482 final inline class Test17Value { 483 public final MyValue1? valueField; 484 485 @ForceInline 486 public Test17Value(MyValue1? valueField) { 487 this.valueField = valueField; 488 } 489 } 490 491 @Test() 492 public Test17Value test17(boolean b) { 493 Test17Value vt1 = Test17Value.default; 494 if ((Object)vt1.valueField != null) { 495 throw new RuntimeException("Should be null"); 496 } 497 Test17Value vt2 = new Test17Value(testValue1); 498 return b ? vt1 : vt2; 499 } 500 501 @DontCompile 502 public void test17_verifier(boolean warmup) { 503 test17(true); 504 test17(false); 505 } 506 507 static final MethodHandle test18_mh1; 508 static final MethodHandle test18_mh2; 509 510 static MyValue1? nullValue; 511 512 @DontInline 513 static void test18_target1(MyValue1? vt) { 514 nullValue = vt; 515 } 516 517 @ForceInline 518 static void test18_target2(MyValue1? vt) { 519 nullValue = vt; 520 } 521 522 // Test passing null for a value type 523 @Test 524 @Warmup(11000) // Make sure lambda forms get compiled 525 public void test18() throws Throwable { 526 test18_mh1.invokeExact(nullValue); 527 test18_mh2.invokeExact(nullValue); 528 } 529 530 @DontCompile 531 public void test18_verifier(boolean warmup) { 532 try { 533 test18(); 534 } catch (Throwable t) { 535 throw new RuntimeException("test18 failed", t); 536 } 537 } 538 539 static MethodHandle test19_mh1; 540 static MethodHandle test19_mh2; 541 542 @DontInline 543 static void test19_target1(MyValue1? vt) { 544 nullValue = vt; 545 } 546 547 @ForceInline 548 static void test19_target2(MyValue1? vt) { 549 nullValue = vt; 550 } 551 552 // Same as test12 but with non-final mh 553 @Test 554 @Warmup(11000) // Make sure lambda forms get compiled 555 public void test19() throws Throwable { 556 test19_mh1.invokeExact(nullValue); 557 test19_mh2.invokeExact(nullValue); 558 } 559 560 @DontCompile 561 public void test19_verifier(boolean warmup) { 562 try { 563 test19(); 564 } catch (Throwable t) { 565 throw new RuntimeException("test19 failed", t); 566 } 567 } 568 569 // Same as test12/13 but with constant null 570 @Test 571 @Warmup(11000) // Make sure lambda forms get compiled 572 public void test20(MethodHandle mh) throws Throwable { 573 mh.invoke(null); 574 } 575 576 @DontCompile 577 public void test20_verifier(boolean warmup) { 578 try { 579 test20(test18_mh1); 580 test20(test18_mh2); 581 test20(test19_mh1); 582 test20(test19_mh2); 583 } catch (Throwable t) { 584 throw new RuntimeException("test20 failed", t); 585 } 586 } 587 588 // Test writing null to a flattenable/non-flattenable value type field in a value type 589 final inline class Test21Value { 590 final MyValue1? valueField1; 591 final MyValue1 valueField2; 592 final MyValue1? alwaysNull = null; 593 594 @ForceInline 595 public Test21Value(MyValue1? valueField1, MyValue1 valueField2) { 596 this.valueField1 = testValue1; 597 this.valueField2 = testValue1; 598 } 599 600 @ForceInline 601 public Test21Value test1() { 602 return new Test21Value(alwaysNull, this.valueField2); // Should not throw NPE 603 } 604 605 @ForceInline 606 public Test21Value test2() { 607 return new Test21Value(this.valueField1, (MyValue1) alwaysNull); // Should throw NPE 608 } 609 } 610 611 @Test 612 public Test21Value test21(Test21Value vt) { 613 vt = vt.test1(); 614 try { 615 vt = vt.test2(); 616 throw new RuntimeException("NullPointerException expected"); 617 } catch (NullPointerException e) { 618 // Expected 619 } 620 return vt; 621 } 622 623 @DontCompile 624 public void test21_verifier(boolean warmup) { 625 test21(Test21Value.default); 626 } 627 628 @DontInline 629 public MyValue1 test22_helper() { 630 return (MyValue1) nullField; 631 } 632 633 @Test 634 public void test22() { 635 valueField1 = test22_helper(); 636 } 637 638 @DontCompile 639 public void test22_verifier(boolean warmup) { 640 try { 641 test22(); 642 throw new RuntimeException("NullPointerException expected"); 643 } catch (NullPointerException e) { 644 // Expected 645 } 646 } 647 648 @Test 649 public void test23(MyValue1[] arr, MyValue1? b) { 650 arr[0] = (MyValue1) b; 651 } 652 653 @DontCompile 654 public void test23_verifier(boolean warmup) { 655 MyValue1[] arr = new MyValue1[2]; 656 MyValue1? b = null; 657 try { 658 test23(arr, b); 659 throw new RuntimeException("NullPointerException expected"); 660 } catch (NullPointerException e) { 661 // Expected 662 } 663 } 664 665 static MyValue1? nullBox; 666 667 @Test 668 public MyValue1 test24() { 669 return (MyValue1) nullBox; 670 } 671 672 @DontCompile 673 public void test24_verifier(boolean warmup) { 674 try { 675 test24(); 676 throw new RuntimeException("NullPointerException expected"); 677 } catch (NullPointerException e) { 678 // Expected 679 } 680 } 681 682 @DontInline 683 public void test25_callee(MyValue1 val) { } 684 685 // Test that when checkcasting from null-ok to null-free and back to null-ok we 686 // keep track of the information that the value can never be null. 687 @Test(failOn = ALLOC + STORE) 688 public int test25(boolean b, MyValue1? vt1, MyValue1 vt2) { 689 vt1 = (MyValue1)vt1; 690 Object obj = b ? vt1 : vt2; // We should not allocate here 691 test25_callee((MyValue1) vt1); 692 return ((MyValue1)obj).x; 693 } 694 695 @DontCompile 696 public void test25_verifier(boolean warmup) { 697 int res = test25(true, testValue1, testValue1); 698 Asserts.assertEquals(res, testValue1.x); 699 res = test25(false, testValue1, testValue1); 700 Asserts.assertEquals(res, testValue1.x); 701 } 702 703 // Test that chains of casts are folded and don't trigger an allocation 704 @Test(failOn = ALLOC + STORE) 705 public MyValue3 test26(MyValue3 vt) { 706 return ((MyValue3)((Object)((MyValue3?)(MyValue3)((MyValue3?)((Object)vt))))); 707 } 708 709 @DontCompile 710 public void test26_verifier(boolean warmup) { 711 MyValue3 vt = MyValue3.create(); 712 MyValue3 result = test26(vt); 713 Asserts.assertEquals(result, vt); 714 } 715 716 @Test(failOn = ALLOC + STORE) 717 public MyValue3? test27(MyValue3? vt) { 718 return ((MyValue3?)((Object)((MyValue3)(MyValue3?)((MyValue3)((Object)vt))))); 719 } 720 721 @DontCompile 722 public void test27_verifier(boolean warmup) { 723 MyValue3 vt = MyValue3.create(); 724 MyValue3 result = (MyValue3) test27(vt); 725 Asserts.assertEquals(result, vt); 726 } 727 728 // Some more casting tests 729 @Test() 730 public MyValue1? test28(MyValue1 vt, MyValue1? vtBox, int i) { 731 MyValue1? result = null; 732 if (i == 0) { 733 result = (MyValue1?)vt; 734 result = null; 735 } else if (i == 1) { 736 result = (MyValue1?)vt; 737 } else if (i == 2) { 738 result = vtBox; 739 } 740 return result; 741 } 742 743 @DontCompile 744 public void test28_verifier(boolean warmup) { 745 MyValue1? result = test28(testValue1, null, 0); 746 Asserts.assertEquals(result, null); 747 result = test28(testValue1, testValue1, 1); 748 Asserts.assertEquals(result, testValue1); 749 result = test28(testValue1, null, 2); 750 Asserts.assertEquals(result, null); 751 result = test28(testValue1, testValue1, 2); 752 Asserts.assertEquals(result, testValue1); 753 } 754 755 @Test() 756 public long test29(MyValue1 vt, MyValue1? vtBox) { 757 long result = 0; 758 for (int i = 0; i < 100; ++i) { 759 MyValue1? box; 760 if (i == 0) { 761 box = (MyValue1?)vt; 762 box = null; 763 } else if (i < 99) { 764 box = (MyValue1?)vt; 765 } else { 766 box = vtBox; 767 } 768 if (box != null) { 769 result += box.hash(); 770 } 771 } 772 return result; 773 } 774 775 @DontCompile 776 public void test29_verifier(boolean warmup) { 777 long result = test29(testValue1, null); 778 Asserts.assertEquals(result, testValue1.hash()*98); 779 result = test29(testValue1, testValue1); 780 Asserts.assertEquals(result, testValue1.hash()*99); 781 } 782 783 // Test null check of value type receiver with incremental inlining 784 public long test30_callee(MyValue1? vt) { 785 long result = 0; 786 try { 787 result = vt.hashInterpreted(); 788 throw new RuntimeException("NullPointerException expected"); 789 } catch (NullPointerException e) { 790 // Expected 791 } 792 return result; 793 } 794 795 @Test 796 public long test30() { 797 return test30_callee(nullField); 798 } 799 800 @DontCompile 801 public void test30_verifier(boolean warmup) { 802 long result = test30(); 803 Asserts.assertEquals(result, 0L); 804 } 805 }