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 * @compile -XDallowWithFieldOperator TestNullableValueTypes.java 36 * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform 37 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions 38 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla 39 * compiler.valhalla.valuetypes.ValueTypeTest 40 * compiler.valhalla.valuetypes.TestNullableValueTypes 41 */ 42 public class TestNullableValueTypes extends ValueTypeTest { 43 // Extra VM parameters for some test scenarios. See ValueTypeTest.getVMParameters() 44 @Override 45 public String[] getExtraVMParameters(int scenario) { 46 switch (scenario) { 47 case 1: return new String[] {"-XX:-UseOptoBiasInlining"}; 48 case 2: return new String[] {"-XX:-UseBiasedLocking"}; 49 case 3: return new String[] {"-XX:-MonomorphicArrayCheck", "-XX:-UseBiasedLocking", "-XX:ValueArrayElemMaxFlatSize=-1"}; 50 case 4: return new String[] {"-XX:-MonomorphicArrayCheck"}; 51 } 52 return null; 53 } 54 55 public static void main(String[] args) throws Throwable { 56 TestNullableValueTypes test = new TestNullableValueTypes(); 57 test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class, Test17Value.class, Test21Value.class); 58 } 59 60 static { 61 try { 62 Class<?> clazz = TestNullableValueTypes.class; 63 ClassLoader loader = clazz.getClassLoader(); 64 MethodHandles.Lookup lookup = MethodHandles.lookup(); 65 66 MethodType test18_mt = MethodType.methodType(void.class, MyValue1.class.asBoxType()); 67 test18_mh1 = lookup.findStatic(clazz, "test18_target1", test18_mt); 68 test18_mh2 = lookup.findStatic(clazz, "test18_target2", test18_mt); 69 70 MethodType test19_mt = MethodType.methodType(void.class, MyValue1.class.asBoxType()); 71 test19_mh1 = lookup.findStatic(clazz, "test19_target1", test19_mt); 72 test19_mh2 = lookup.findStatic(clazz, "test19_target2", test19_mt); 73 } catch (NoSuchMethodException | IllegalAccessException e) { 74 e.printStackTrace(); 75 throw new RuntimeException("Method handle lookup failed"); 76 } 77 } 78 79 private static final MyValue1 testValue1 = MyValue1.createWithFieldsInline(rI, rL); 80 private static final MyValue1[] testValue1Array = new MyValue1[] {testValue1, 81 testValue1, 82 testValue1}; 83 84 MyValue1.box nullField; 85 MyValue1.val valueField1 = testValue1; 86 87 @Test 88 public long test1(MyValue1.box vt) { 89 long result = 0; 90 try { 91 result = vt.hash(); 92 throw new RuntimeException("NullPointerException expected"); 93 } catch (NullPointerException e) { 94 // Expected 95 } 96 return result; 97 } 98 99 @DontCompile 100 public void test1_verifier(boolean warmup) throws Throwable { 101 long result = test1(null); 102 Asserts.assertEquals(result, 0L); 103 } 104 105 @Test 106 public long test2(MyValue1.box vt) { 107 long result = 0; 108 try { 109 result = vt.hashInterpreted(); 110 throw new RuntimeException("NullPointerException expected"); 111 } catch (NullPointerException e) { 112 // Expected 113 } 114 return result; 115 } 116 117 @DontCompile 118 public void test2_verifier(boolean warmup) { 119 long result = test2(nullField); 120 Asserts.assertEquals(result, 0L); 121 } 122 123 @Test 124 public long test3() { 125 long result = 0; 126 try { 127 if ((Object)nullField != null) { 128 throw new RuntimeException("nullField should be null"); 129 } 130 result = nullField.hash(); 131 throw new RuntimeException("NullPointerException expected"); 132 } catch (NullPointerException e) { 133 // Expected 134 } 135 return result; 136 } 137 138 @DontCompile 139 public void test3_verifier(boolean warmup) { 140 long result = test3(); 141 Asserts.assertEquals(result, 0L); 142 } 143 144 @Test 145 public void test4() { 146 try { 147 valueField1 = nullField; 148 throw new RuntimeException("NullPointerException expected"); 149 } catch (NullPointerException e) { 150 // Expected 151 } 152 } 153 154 @DontCompile 155 public void test4_verifier(boolean warmup) { 156 test4(); 157 } 158 159 @Test 160 public MyValue1.box test5(MyValue1.box vt) { 161 try { 162 Object o = vt; 163 vt = (MyValue1)o; 164 throw new RuntimeException("NullPointerException expected"); 165 } catch (NullPointerException e) { 166 // Expected 167 } 168 169 // Should not throw 170 vt = test5_dontinline(vt); 171 vt = test5_inline(vt); 172 return vt; 173 } 174 175 @DontCompile 176 public void test5_verifier(boolean warmup) { 177 MyValue1.box vt = test5(nullField); 178 Asserts.assertEquals((Object)vt, null); 179 } 180 181 @DontInline 182 public MyValue1.box test5_dontinline(MyValue1.box vt) { 183 return vt; 184 } 185 186 @ForceInline 187 public MyValue1.box test5_inline(MyValue1.box vt) { 188 return vt; 189 } 190 191 @Test 192 public MyValue1 test6(Object obj) { 193 MyValue1 vt = MyValue1.createWithFieldsInline(rI, rL); 194 try { 195 vt = (MyValue1)obj; 196 throw new RuntimeException("NullPointerException expected"); 197 } catch (NullPointerException e) { 198 // Expected 199 } 200 return vt; 201 } 202 203 @DontCompile 204 public void test6_verifier(boolean warmup) { 205 MyValue1 vt = test6(null); 206 Asserts.assertEquals(vt.hash(), testValue1.hash()); 207 } 208 209 @ForceInline 210 public MyValue1.box getNullInline() { 211 return null; 212 } 213 214 @DontInline 215 public MyValue1.box getNullDontInline() { 216 return null; 217 } 218 219 @Test 220 public void test7() throws Throwable { 221 nullField = getNullInline(); // Should not throw 222 nullField = getNullDontInline(); // Should not throw 223 try { 224 valueField1 = getNullInline(); 225 throw new RuntimeException("NullPointerException expected"); 226 } catch (NullPointerException e) { 227 // Expected 228 } 229 try { 230 valueField1 = getNullDontInline(); 231 throw new RuntimeException("NullPointerException expected"); 232 } catch (NullPointerException e) { 233 // Expected 234 } 235 } 236 237 @DontCompile 238 public void test7_verifier(boolean warmup) throws Throwable { 239 test7(); 240 } 241 242 @Test 243 public void test8() throws Throwable { 244 try { 245 valueField1 = nullField; 246 throw new RuntimeException("NullPointerException expected"); 247 } catch (NullPointerException e) { 248 // Expected 249 } 250 } 251 252 @DontCompile 253 public void test8_verifier(boolean warmup) throws Throwable { 254 test8(); 255 } 256 257 // merge of 2 values, one being null 258 @Test 259 public void test9(boolean flag1) { 260 MyValue1 v; 261 if (flag1) { 262 v = valueField1; 263 } else { 264 v = nullField; 265 } 266 valueField1 = v; 267 } 268 269 @DontCompile 270 public void test9_verifier(boolean warmup) { 271 test9(true); 272 try { 273 test9(false); 274 throw new RuntimeException("NullPointerException expected"); 275 } catch (NullPointerException e) { 276 // Expected 277 } 278 } 279 280 // null constant 281 @Test 282 public void test10(boolean flag) throws Throwable { 283 MyValue1.box val = flag ? valueField1 : null; 284 valueField1 = val; 285 } 286 287 @DontCompile 288 public void test10_verifier(boolean warmup) throws Throwable { 289 test10(true); 290 try { 291 test10(false); 292 throw new RuntimeException("NullPointerException expected"); 293 } catch (NullPointerException e) { 294 // Expected 295 } 296 } 297 298 // null constant 299 @Test 300 public void test11(boolean flag) throws Throwable { 301 MyValue1.box val = flag ? null : valueField1; 302 valueField1 = val; 303 } 304 305 @DontCompile 306 public void test11_verifier(boolean warmup) throws Throwable { 307 test11(false); 308 try { 309 test11(true); 310 throw new RuntimeException("NullPointerException expected"); 311 } catch (NullPointerException e) { 312 // Expected 313 } 314 } 315 316 // null return 317 int test12_cnt; 318 319 @DontInline 320 public MyValue1.box test12_helper() { 321 test12_cnt++; 322 return nullField; 323 } 324 325 @Test 326 public void test12() { 327 valueField1 = test12_helper(); 328 } 329 330 @DontCompile 331 public void test12_verifier(boolean warmup) { 332 try { 333 test12_cnt = 0; 334 test12(); 335 throw new RuntimeException("NullPointerException expected"); 336 } catch (NullPointerException e) { 337 // Expected 338 } 339 if (test12_cnt != 1) { 340 throw new RuntimeException("call executed twice"); 341 } 342 } 343 344 // null return at virtual call 345 class A { 346 public MyValue1.box test13_helper() { 347 return nullField; 348 } 349 } 350 351 class B extends A { 352 public MyValue1.val test13_helper() { 353 return nullField; 354 } 355 } 356 357 class C extends A { 358 public MyValue1.box test13_helper() { 359 return nullField; 360 } 361 } 362 363 class D extends B { 364 public MyValue1.box test13_helper() { 365 return nullField; 366 } 367 } 368 369 @Test 370 public void test13(A a) { 371 valueField1 = a.test13_helper(); 372 } 373 374 @DontCompile 375 public void test13_verifier(boolean warmup) { 376 A b = new B(); 377 A c = new C(); 378 A d = new D(); 379 try { 380 test13(b); 381 throw new RuntimeException("NullPointerException expected"); 382 } catch (NullPointerException e) { 383 // Expected 384 } 385 try { 386 test13(c); 387 throw new RuntimeException("NullPointerException expected"); 388 } catch (NullPointerException e) { 389 // Expected 390 } 391 try { 392 test13(d); 393 throw new RuntimeException("NullPointerException expected"); 394 } catch (NullPointerException e) { 395 // Expected 396 } 397 } 398 399 // Test writing null to a (flattened) value type array 400 @ForceInline 401 public void test14_inline(Object[] oa, Object o, int index) { 402 oa[index] = o; 403 } 404 405 @Test() 406 public void test14(MyValue1[] va, int index) { 407 test14_inline(va, nullField, index); 408 } 409 410 @DontCompile 411 public void test14_verifier(boolean warmup) { 412 int index = Math.abs(rI) % 3; 413 try { 414 test14(testValue1Array, index); 415 throw new RuntimeException("No NPE thrown"); 416 } catch (NullPointerException e) { 417 // Expected 418 } 419 Asserts.assertEQ(testValue1Array[index].hash(), testValue1.hash()); 420 } 421 422 @DontInline 423 MyValue1.box getNullField1() { 424 return nullField; 425 } 426 427 @DontInline 428 MyValue1.val getNullField2() { 429 return nullField; 430 } 431 432 @Test() 433 public void test15() { 434 nullField = getNullField1(); // should not throw 435 try { 436 valueField1 = getNullField1(); 437 throw new RuntimeException("NullPointerException expected"); 438 } catch (NullPointerException e) { 439 // Expected 440 } 441 try { 442 valueField1 = getNullField2(); 443 throw new RuntimeException("NullPointerException expected"); 444 } catch (NullPointerException e) { 445 // Expected 446 } 447 } 448 449 @DontCompile 450 public void test15_verifier(boolean warmup) { 451 test15(); 452 } 453 454 @DontInline 455 public boolean test16_dontinline(MyValue1.box vt) { 456 return (Object)vt == null; 457 } 458 459 // Test c2c call passing null for a value type 460 @Test 461 @Warmup(10000) // Warmup to make sure 'test17_dontinline' is compiled 462 public boolean test16(Object arg) throws Exception { 463 Method test16method = getClass().getMethod("test16_dontinline", MyValue1.class.asBoxType()); 464 return (boolean)test16method.invoke(this, arg); 465 } 466 467 @DontCompile 468 public void test16_verifier(boolean warmup) throws Exception { 469 boolean res = test16(null); 470 Asserts.assertTrue(res); 471 } 472 473 // Test scalarization of default value type with non-flattenable field 474 value final class Test17Value { 475 public final MyValue1.box valueField; 476 477 public Test17Value() { 478 valueField = MyValue1.createDefaultDontInline(); 479 } 480 481 @ForceInline 482 public Test17Value setValueField(MyValue1 valueField) { 483 return __WithField(this.valueField, valueField); 484 } 485 } 486 487 @Test() 488 public Test17Value test17(boolean b) { 489 Test17Value vt1 = Test17Value.default; 490 if ((Object)vt1.valueField != null) { 491 throw new RuntimeException("Should be null"); 492 } 493 Test17Value vt2 = vt1.setValueField(testValue1); 494 return b ? vt1 : vt2; 495 } 496 497 @DontCompile 498 public void test17_verifier(boolean warmup) { 499 test17(true); 500 test17(false); 501 } 502 503 static final MethodHandle test18_mh1; 504 static final MethodHandle test18_mh2; 505 506 static MyValue1.box nullValue; 507 508 @DontInline 509 static void test18_target1(MyValue1.box vt) { 510 nullValue = vt; 511 } 512 513 @ForceInline 514 static void test18_target2(MyValue1.box vt) { 515 nullValue = vt; 516 } 517 518 // Test passing null for a value type 519 @Test 520 @Warmup(11000) // Make sure lambda forms get compiled 521 public void test18() throws Throwable { 522 test18_mh1.invokeExact(nullValue); 523 test18_mh2.invokeExact(nullValue); 524 } 525 526 @DontCompile 527 public void test18_verifier(boolean warmup) { 528 try { 529 test18(); 530 } catch (Throwable t) { 531 throw new RuntimeException("test18 failed", t); 532 } 533 } 534 535 static MethodHandle test19_mh1; 536 static MethodHandle test19_mh2; 537 538 @DontInline 539 static void test19_target1(MyValue1.box vt) { 540 nullValue = vt; 541 } 542 543 @ForceInline 544 static void test19_target2(MyValue1.box vt) { 545 nullValue = vt; 546 } 547 548 // Same as test12 but with non-final mh 549 @Test 550 @Warmup(11000) // Make sure lambda forms get compiled 551 public void test19() throws Throwable { 552 test19_mh1.invokeExact(nullValue); 553 test19_mh2.invokeExact(nullValue); 554 } 555 556 @DontCompile 557 public void test19_verifier(boolean warmup) { 558 try { 559 test19(); 560 } catch (Throwable t) { 561 throw new RuntimeException("test19 failed", t); 562 } 563 } 564 565 // Same as test12/13 but with constant null 566 @Test 567 @Warmup(11000) // Make sure lambda forms get compiled 568 public void test20(MethodHandle mh) throws Throwable { 569 mh.invoke(null); 570 } 571 572 @DontCompile 573 public void test20_verifier(boolean warmup) { 574 try { 575 test20(test18_mh1); 576 test20(test18_mh2); 577 test20(test19_mh1); 578 test20(test19_mh2); 579 } catch (Throwable t) { 580 throw new RuntimeException("test20 failed", t); 581 } 582 } 583 584 // Test writing null to a flattenable/non-flattenable value type field in a value type 585 value final class Test21Value { 586 final MyValue1.box valueField1; 587 final MyValue1.val valueField2; 588 final MyValue1.box alwaysNull; 589 590 private Test21Value() { 591 valueField1 = testValue1; 592 valueField2 = testValue1; 593 alwaysNull = testValue1; 594 } 595 596 @ForceInline 597 public Test21Value test1() { 598 return __WithField(this.valueField1, alwaysNull); // Should not throw NPE 599 } 600 601 @ForceInline 602 public Test21Value test2() { 603 return __WithField(this.valueField2, alwaysNull); // Should throw NPE 604 } 605 } 606 607 @Test 608 public Test21Value test21(Test21Value vt) { 609 vt = vt.test1(); 610 try { 611 vt = vt.test2(); 612 throw new RuntimeException("NullPointerException expected"); 613 } catch (NullPointerException e) { 614 // Expected 615 } 616 return vt; 617 } 618 619 @DontCompile 620 public void test21_verifier(boolean warmup) { 621 test21(Test21Value.default); 622 } 623 624 @DontInline 625 public MyValue1.val test22_helper() { 626 return nullField; 627 } 628 629 @Test 630 public void test22() { 631 valueField1 = test22_helper(); 632 } 633 634 @DontCompile 635 public void test22_verifier(boolean warmup) { 636 try { 637 test22(); 638 throw new RuntimeException("NullPointerException expected"); 639 } catch (NullPointerException e) { 640 // Expected 641 } 642 } 643 644 @Test 645 public void test23(MyValue1[] arr, MyValue1.box b) { 646 arr[0] = b; 647 } 648 649 @DontCompile 650 public void test23_verifier(boolean warmup) { 651 MyValue1[] arr = new MyValue1[2]; 652 MyValue1.box b = null; 653 try { 654 test23(arr, b); 655 throw new RuntimeException("NullPointerException expected"); 656 } catch (NullPointerException e) { 657 // Expected 658 } 659 } 660 661 static MyValue1.box nullBox; 662 663 @Test 664 public MyValue1 test24() { 665 return nullBox; 666 } 667 668 @DontCompile 669 public void test24_verifier(boolean warmup) { 670 try { 671 test24(); 672 throw new RuntimeException("NullPointerException expected"); 673 } catch (NullPointerException e) { 674 // Expected 675 } 676 } 677 678 @DontInline 679 public void test25_callee(MyValue1 val) { } 680 681 // Test that when checkcasting from .box to .val and back to .box we 682 // keep track of the information that the value can never be null. 683 @Test(failOn = ALLOC + STORE) 684 public int test25(boolean b, MyValue1.box vt1, MyValue1.val vt2) { 685 vt1 = (MyValue1.val)vt1; 686 Object obj = b ? vt1 : vt2; // We should not allocate here 687 test25_callee(vt1); 688 return ((MyValue1)obj).x; 689 } 690 691 @DontCompile 692 public void test25_verifier(boolean warmup) { 693 int res = test25(true, testValue1, testValue1); 694 Asserts.assertEquals(res, testValue1.x); 695 res = test25(false, testValue1, testValue1); 696 Asserts.assertEquals(res, testValue1.x); 697 } 698 }