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 -XDallowWithFieldOperator 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:+ValueArrayFlatten"}; 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.asBoxType()); 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.asBoxType()); 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.box nullField; 86 MyValue1.val valueField1 = testValue1; 87 88 @Test 89 public long test1(MyValue1.box 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.box 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 = 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.box test5(MyValue1.box 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.box vt = test5(nullField); 179 Asserts.assertEquals((Object)vt, null); 180 } 181 182 @DontInline 183 public MyValue1.box test5_dontinline(MyValue1.box vt) { 184 return vt; 185 } 186 187 @ForceInline 188 public MyValue1.box test5_inline(MyValue1.box 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.box getNullInline() { 212 return null; 213 } 214 215 @DontInline 216 public MyValue1.box 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 = getNullInline(); 226 throw new RuntimeException("NullPointerException expected"); 227 } catch (NullPointerException e) { 228 // Expected 229 } 230 try { 231 valueField1 = 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 = 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 = 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.box val = flag ? valueField1 : null; 285 valueField1 = 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.box val = flag ? null : valueField1; 303 valueField1 = 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.box test12_helper() { 322 test12_cnt++; 323 return nullField; 324 } 325 326 @Test 327 public void test12() { 328 valueField1 = 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.box test13_helper() { 348 return nullField; 349 } 350 } 351 352 class B extends A { 353 public MyValue1.val test13_helper() { 354 return nullField; 355 } 356 } 357 358 class C extends A { 359 public MyValue1.box test13_helper() { 360 return nullField; 361 } 362 } 363 364 class D extends B { 365 public MyValue1.box test13_helper() { 366 return nullField; 367 } 368 } 369 370 @Test 371 public void test13(A a) { 372 valueField1 = a.test13_helper(); 373 } 374 375 @DontCompile 376 public void test13_verifier(boolean warmup) { 377 A b = new B(); 378 A c = new C(); 379 A d = new D(); 380 try { 381 test13(b); 382 throw new RuntimeException("NullPointerException expected"); 383 } catch (NullPointerException e) { 384 // Expected 385 } 386 try { 387 test13(c); 388 throw new RuntimeException("NullPointerException expected"); 389 } catch (NullPointerException e) { 390 // Expected 391 } 392 try { 393 test13(d); 394 throw new RuntimeException("NullPointerException expected"); 395 } catch (NullPointerException e) { 396 // Expected 397 } 398 } 399 400 // Test writing null to a (flattened) value type array 401 @ForceInline 402 public void test14_inline(Object[] oa, Object o, int index) { 403 oa[index] = o; 404 } 405 406 @Test() 407 public void test14(MyValue1[] va, int index) { 408 test14_inline(va, nullField, index); 409 } 410 411 @DontCompile 412 public void test14_verifier(boolean warmup) { 413 int index = Math.abs(rI) % 3; 414 try { 415 test14(testValue1Array, index); 416 throw new RuntimeException("No NPE thrown"); 417 } catch (NullPointerException e) { 418 // Expected 419 } 420 Asserts.assertEQ(testValue1Array[index].hash(), testValue1.hash()); 421 } 422 423 @DontInline 424 MyValue1.box getNullField1() { 425 return nullField; 426 } 427 428 @DontInline 429 MyValue1.val getNullField2() { 430 return nullField; 431 } 432 433 @Test() 434 public void test15() { 435 nullField = getNullField1(); // should not throw 436 try { 437 valueField1 = getNullField1(); 438 throw new RuntimeException("NullPointerException expected"); 439 } catch (NullPointerException e) { 440 // Expected 441 } 442 try { 443 valueField1 = getNullField2(); 444 throw new RuntimeException("NullPointerException expected"); 445 } catch (NullPointerException e) { 446 // Expected 447 } 448 } 449 450 @DontCompile 451 public void test15_verifier(boolean warmup) { 452 test15(); 453 } 454 455 @DontInline 456 public boolean test16_dontinline(MyValue1.box vt) { 457 return (Object)vt == null; 458 } 459 460 // Test c2c call passing null for a value type 461 @Test 462 @Warmup(10000) // Warmup to make sure 'test17_dontinline' is compiled 463 public boolean test16(Object arg) throws Exception { 464 Method test16method = getClass().getMethod("test16_dontinline", MyValue1.class.asBoxType()); 465 return (boolean)test16method.invoke(this, arg); 466 } 467 468 @DontCompile 469 public void test16_verifier(boolean warmup) throws Exception { 470 boolean res = test16(null); 471 Asserts.assertTrue(res); 472 } 473 474 // Test scalarization of default value type with non-flattenable field 475 value final class Test17Value { 476 public final MyValue1.box valueField; 477 478 public Test17Value() { 479 valueField = MyValue1.createDefaultDontInline(); 480 } 481 482 @ForceInline 483 public Test17Value setValueField(MyValue1 valueField) { 484 return __WithField(this.valueField, valueField); 485 } 486 } 487 488 @Test() 489 public Test17Value test17(boolean b) { 490 Test17Value vt1 = Test17Value.default; 491 if ((Object)vt1.valueField != null) { 492 throw new RuntimeException("Should be null"); 493 } 494 Test17Value vt2 = vt1.setValueField(testValue1); 495 return b ? vt1 : vt2; 496 } 497 498 @DontCompile 499 public void test17_verifier(boolean warmup) { 500 test17(true); 501 test17(false); 502 } 503 504 static final MethodHandle test18_mh1; 505 static final MethodHandle test18_mh2; 506 507 static MyValue1.box nullValue; 508 509 @DontInline 510 static void test18_target1(MyValue1.box vt) { 511 nullValue = vt; 512 } 513 514 @ForceInline 515 static void test18_target2(MyValue1.box vt) { 516 nullValue = vt; 517 } 518 519 // Test passing null for a value type 520 @Test 521 @Warmup(11000) // Make sure lambda forms get compiled 522 public void test18() throws Throwable { 523 test18_mh1.invokeExact(nullValue); 524 test18_mh2.invokeExact(nullValue); 525 } 526 527 @DontCompile 528 public void test18_verifier(boolean warmup) { 529 try { 530 test18(); 531 } catch (Throwable t) { 532 throw new RuntimeException("test18 failed", t); 533 } 534 } 535 536 static MethodHandle test19_mh1; 537 static MethodHandle test19_mh2; 538 539 @DontInline 540 static void test19_target1(MyValue1.box vt) { 541 nullValue = vt; 542 } 543 544 @ForceInline 545 static void test19_target2(MyValue1.box vt) { 546 nullValue = vt; 547 } 548 549 // Same as test12 but with non-final mh 550 @Test 551 @Warmup(11000) // Make sure lambda forms get compiled 552 public void test19() throws Throwable { 553 test19_mh1.invokeExact(nullValue); 554 test19_mh2.invokeExact(nullValue); 555 } 556 557 @DontCompile 558 public void test19_verifier(boolean warmup) { 559 try { 560 test19(); 561 } catch (Throwable t) { 562 throw new RuntimeException("test19 failed", t); 563 } 564 } 565 566 // Same as test12/13 but with constant null 567 @Test 568 @Warmup(11000) // Make sure lambda forms get compiled 569 public void test20(MethodHandle mh) throws Throwable { 570 mh.invoke(null); 571 } 572 573 @DontCompile 574 public void test20_verifier(boolean warmup) { 575 try { 576 test20(test18_mh1); 577 test20(test18_mh2); 578 test20(test19_mh1); 579 test20(test19_mh2); 580 } catch (Throwable t) { 581 throw new RuntimeException("test20 failed", t); 582 } 583 } 584 585 // Test writing null to a flattenable/non-flattenable value type field in a value type 586 value final class Test21Value { 587 final MyValue1.box valueField1; 588 final MyValue1.val valueField2; 589 final MyValue1.box alwaysNull; 590 591 private Test21Value() { 592 valueField1 = testValue1; 593 valueField2 = testValue1; 594 alwaysNull = testValue1; 595 } 596 597 @ForceInline 598 public Test21Value test1() { 599 return __WithField(this.valueField1, alwaysNull); // Should not throw NPE 600 } 601 602 @ForceInline 603 public Test21Value test2() { 604 return __WithField(this.valueField2, alwaysNull); // Should throw NPE 605 } 606 } 607 608 @Test 609 public Test21Value test21(Test21Value vt) { 610 vt = vt.test1(); 611 try { 612 vt = vt.test2(); 613 throw new RuntimeException("NullPointerException expected"); 614 } catch (NullPointerException e) { 615 // Expected 616 } 617 return vt; 618 } 619 620 @DontCompile 621 public void test21_verifier(boolean warmup) { 622 test21(Test21Value.default); 623 } 624 625 @DontInline 626 public MyValue1.val test22_helper() { 627 return nullField; 628 } 629 630 @Test 631 public void test22() { 632 valueField1 = test22_helper(); 633 } 634 635 @DontCompile 636 public void test22_verifier(boolean warmup) { 637 try { 638 test22(); 639 throw new RuntimeException("NullPointerException expected"); 640 } catch (NullPointerException e) { 641 // Expected 642 } 643 } 644 645 @Test 646 public void test23(MyValue1[] arr, MyValue1.box b) { 647 arr[0] = b; 648 } 649 650 @DontCompile 651 public void test23_verifier(boolean warmup) { 652 MyValue1[] arr = new MyValue1[2]; 653 MyValue1.box b = null; 654 try { 655 test23(arr, b); 656 throw new RuntimeException("NullPointerException expected"); 657 } catch (NullPointerException e) { 658 // Expected 659 } 660 } 661 662 static MyValue1.box nullBox; 663 664 @Test 665 public MyValue1 test24() { 666 return nullBox; 667 } 668 669 @DontCompile 670 public void test24_verifier(boolean warmup) { 671 try { 672 test24(); 673 throw new RuntimeException("NullPointerException expected"); 674 } catch (NullPointerException e) { 675 // Expected 676 } 677 } 678 }