1 /* 2 * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package compiler.valhalla.inlinetypes; 25 26 import jdk.internal.value.ValueClass; 27 import jdk.internal.vm.annotation.LooselyConsistentValue; 28 import jdk.internal.vm.annotation.NullRestricted; 29 import jdk.internal.vm.annotation.Strict; 30 31 import jdk.test.lib.Asserts; 32 33 /* 34 * @test 35 * @key randomness 36 * @summary Test support for null markers in flat fields. 37 * @library /test/lib / 38 * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64") 39 * @enablePreview 40 * @modules java.base/jdk.internal.value 41 * java.base/jdk.internal.vm.annotation 42 * @run main/othervm compiler.valhalla.inlinetypes.TestFieldNullMarkers 43 * @run main/othervm -Xbatch -XX:-UseNullableValueFlattening -XX:-UseAtomicValueFlattening -XX:-UseNonAtomicValueFlattening 44 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 45 * @run main/othervm -Xbatch -XX:-UseNullableValueFlattening -XX:-UseAtomicValueFlattening -XX:+UseNonAtomicValueFlattening 46 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 47 * @run main/othervm -Xbatch -XX:-UseNullableValueFlattening -XX:+UseAtomicValueFlattening -XX:-UseNonAtomicValueFlattening 48 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 49 * @run main/othervm -Xbatch -XX:-UseNullableValueFlattening -XX:+UseAtomicValueFlattening -XX:+UseNonAtomicValueFlattening 50 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 51 * @run main/othervm -Xbatch -XX:+UseNullableValueFlattening -XX:-UseAtomicValueFlattening -XX:-UseNonAtomicValueFlattening 52 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 53 * @run main/othervm -Xbatch -XX:+UseNullableValueFlattening -XX:-UseAtomicValueFlattening -XX:+UseNonAtomicValueFlattening 54 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 55 * @run main/othervm -Xbatch -XX:+UseNullableValueFlattening -XX:+UseAtomicValueFlattening -XX:-UseNonAtomicValueFlattening 56 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 57 * @run main/othervm -Xbatch -XX:+UseNullableValueFlattening -XX:+UseAtomicValueFlattening -XX:+UseNonAtomicValueFlattening 58 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 59 * 60 * @run main/othervm -Xbatch -XX:+UseNullableValueFlattening -XX:+UseAtomicValueFlattening -XX:+UseNonAtomicValueFlattening 61 * -XX:CompileCommand=dontinline,*::testHelper* 62 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 63 * @run main/othervm -Xbatch -XX:+UseNullableValueFlattening -XX:+UseAtomicValueFlattening -XX:+UseNonAtomicValueFlattening 64 * -XX:+InlineTypeReturnedAsFields -XX:+InlineTypePassFieldsAsArgs 65 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 66 * @run main/othervm -Xbatch -XX:+UseNullableValueFlattening -XX:+UseAtomicValueFlattening -XX:+UseNonAtomicValueFlattening 67 * -XX:-InlineTypeReturnedAsFields -XX:-InlineTypePassFieldsAsArgs 68 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 69 * @run main/othervm -Xbatch -XX:+UseNullableValueFlattening -XX:+UseAtomicValueFlattening -XX:+UseNonAtomicValueFlattening 70 * -XX:+InlineTypeReturnedAsFields -XX:-InlineTypePassFieldsAsArgs 71 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 72 * @run main/othervm -Xbatch -XX:+UseNullableValueFlattening -XX:+UseAtomicValueFlattening -XX:+UseNonAtomicValueFlattening 73 * -XX:-InlineTypeReturnedAsFields -XX:+InlineTypePassFieldsAsArgs 74 * compiler.valhalla.inlinetypes.TestFieldNullMarkers 75 */ 76 77 public class TestFieldNullMarkers { 78 79 // Value class with two nullable flat fields 80 @LooselyConsistentValue 81 static value class MyValue1 { 82 byte x; 83 MyValue2 val1; 84 MyValue2 val2; 85 86 public MyValue1(byte x, MyValue2 val1, MyValue2 val2) { 87 this.x = x; 88 this.val1 = val1; 89 this.val2 = val2; 90 } 91 92 public String toString() { 93 return "x = " + x + ", val1 = [" + val1 + "], val2 = [" + val2 + "]"; 94 } 95 } 96 97 @LooselyConsistentValue 98 static abstract value class MyAbstract1 { 99 byte x; 100 101 public MyAbstract1(byte x) { 102 this.x = x; 103 } 104 } 105 106 // Empty value class inheriting single field from abstract super class 107 @LooselyConsistentValue 108 static value class MyValue2 extends MyAbstract1 { 109 public MyValue2(byte x) { 110 super(x); 111 } 112 113 public String toString() { 114 return "x = " + x; 115 } 116 } 117 118 // Value class with a hole in the payload that will be used for the null marker 119 @LooselyConsistentValue 120 static value class MyValue3 { 121 byte x; 122 // Hole that will be used by the null marker 123 int i; 124 125 public MyValue3(byte x) { 126 this.x = x; 127 this.i = x; 128 } 129 130 public String toString() { 131 return "x = " + x + ", i = " + i; 132 } 133 } 134 135 // Value class with two nullable flat fields that have their null markers *not* at the end of the payload 136 @LooselyConsistentValue 137 static value class MyValue4 { 138 MyValue3 val1; 139 MyValue3 val2; 140 141 public MyValue4(MyValue3 val1, MyValue3 val2) { 142 this.val1 = val1; 143 this.val2 = val2; 144 } 145 146 public String toString() { 147 return "val1 = [" + val1 + "], val2 = [" + val2 + "]"; 148 } 149 } 150 151 @LooselyConsistentValue 152 static value class MyValue5_3 { 153 byte x; 154 155 public MyValue5_3(byte x) { 156 this.x = x; 157 } 158 } 159 160 @LooselyConsistentValue 161 static value class MyValue5_2 { 162 byte x; 163 MyValue5_3 val; 164 165 public MyValue5_2(byte x, MyValue5_3 val) { 166 this.x = x; 167 this.val = val; 168 } 169 } 170 171 @LooselyConsistentValue 172 static value class MyValue5_1 { 173 byte x; 174 MyValue5_2 val; 175 176 public MyValue5_1(byte x, MyValue5_2 val) { 177 this.x = x; 178 this.val = val; 179 } 180 } 181 182 // Value class with deep nesting of nullable flat fields 183 @LooselyConsistentValue 184 static value class MyValue5 { 185 byte x; 186 MyValue5_1 val; 187 188 public MyValue5(byte x, MyValue5_1 val) { 189 this.x = x; 190 this.val = val; 191 } 192 } 193 194 @LooselyConsistentValue 195 static value class MyValueEmpty { 196 197 } 198 199 // Value class with flat field of empty value class 200 @LooselyConsistentValue 201 static value class MyValue6 { 202 MyValueEmpty val; 203 204 public MyValue6(MyValueEmpty val) { 205 this.val = val; 206 } 207 } 208 209 // Same as MyValue6 but one more level of nested flat fields 210 @LooselyConsistentValue 211 static value class MyValue7 { 212 MyValue6 val; 213 214 public MyValue7(MyValue6 val) { 215 this.val = val; 216 } 217 } 218 219 // Some more field types 220 221 @LooselyConsistentValue 222 static value class MyValue8 { 223 byte b; 224 225 public MyValue8(byte b) { 226 this.b = b; 227 } 228 } 229 230 @LooselyConsistentValue 231 static value class MyValue9 { 232 short s; 233 234 public MyValue9(short s) { 235 this.s = s; 236 } 237 } 238 239 @LooselyConsistentValue 240 static value class MyValue10 { 241 int i; 242 243 public MyValue10(int i) { 244 this.i = i; 245 } 246 } 247 248 @LooselyConsistentValue 249 static value class MyValue11 { 250 float f; 251 252 public MyValue11(float f) { 253 this.f = f; 254 } 255 } 256 257 @LooselyConsistentValue 258 static value class MyValue12 { 259 char c; 260 261 public MyValue12(char c) { 262 this.c = c; 263 } 264 } 265 266 @LooselyConsistentValue 267 static value class MyValue13 { 268 boolean b; 269 270 public MyValue13(boolean b) { 271 this.b = b; 272 } 273 } 274 275 // Test value class with nullable and null-free fields 276 @LooselyConsistentValue 277 static value class MyValue14 { 278 @Strict 279 @NullRestricted 280 MyValue8 nullfree; 281 MyValue8 nullable; 282 283 public MyValue14(MyValue8 nullfree, MyValue8 nullable) { 284 this.nullfree = nullfree; 285 this.nullable = nullable; 286 } 287 288 public static final MyValue14 DEFAULT = new MyValue14(new MyValue8((byte)0), null); 289 } 290 291 static class MyClass { 292 int x; 293 294 public MyClass(int x) { 295 this.x = x; 296 } 297 } 298 299 // Value class with oop field 300 @LooselyConsistentValue 301 static value class MyValue15 { 302 MyClass obj; 303 304 public MyValue15(MyClass obj) { 305 this.obj = obj; 306 } 307 } 308 309 // Value class with two oop fields 310 @LooselyConsistentValue 311 static value class MyValue16 { 312 MyClass obj1; 313 MyClass obj2; 314 315 public MyValue16(MyClass obj1, MyClass obj2) { 316 this.obj1 = obj1; 317 this.obj2 = obj2; 318 } 319 } 320 321 // Value class with oop field and primitive fields 322 @LooselyConsistentValue 323 static value class MyValue17 { 324 byte b1; 325 MyClass obj; 326 byte b2; 327 328 public MyValue17(MyClass obj, byte b1, byte b2) { 329 this.obj = obj; 330 this.b1 = b1; 331 this.b2 = b2; 332 } 333 } 334 335 MyValue1 field1; // Not flat 336 MyValue4 field2; // Not flat 337 MyValue5 field3; // Flat 338 MyValue6 field4; // Flat 339 MyValue7 field5; // Flat 340 MyValue8 field6; // Flat 341 MyValue9 field7; // Flat 342 MyValue10 field8; // Flat 343 MyValue11 field9; // Flat 344 MyValue12 field10; // Flat 345 MyValue13 field11; // Flat 346 347 @Strict 348 @NullRestricted 349 volatile MyValue8 field12 = new MyValue8((byte)0); 350 351 @Strict 352 @NullRestricted 353 MyValue14 field13 = MyValue14.DEFAULT; // Null-free, flat 354 volatile MyValue14 field14; // Nullable, atomic, flat 355 MyValue14 field15; // Nullable, (atomic), flat 356 @Strict 357 @NullRestricted 358 volatile MyValue14 field16 = MyValue14.DEFAULT; // Null-free, atomic, flat 359 360 @Strict 361 @NullRestricted 362 volatile MyValue15 field17 = new MyValue15(null); 363 MyValue15 field18; 364 @Strict 365 @NullRestricted 366 volatile MyValue16 field19 = new MyValue16(null, null); 367 @Strict 368 @NullRestricted 369 volatile MyValue17 field20 = new MyValue17(null, (byte)0, (byte)0); 370 MyValue17 field21; 371 372 // Combinations of strict fields 373 static class StrictFieldHolder { 374 @Strict 375 MyValue8 strictField1; 376 @Strict 377 final MyValue8 strictField2; 378 @Strict 379 @NullRestricted 380 MyValue8 strictField3; 381 @Strict 382 @NullRestricted 383 final MyValue8 strictField4; 384 @Strict 385 volatile MyValue8 strictField5; 386 @Strict 387 @NullRestricted 388 volatile MyValue8 strictField6; 389 390 @Strict 391 TwoBytes strictField7; 392 @Strict 393 final TwoBytes strictField8; 394 @Strict 395 @NullRestricted 396 TwoBytes strictField9; 397 @Strict 398 @NullRestricted 399 final TwoBytes strictField10; 400 @Strict 401 volatile TwoBytes strictField11; 402 @Strict 403 @NullRestricted 404 volatile TwoBytes strictField12; 405 406 public StrictFieldHolder(MyValue8 val8, MyValue8 val8NullFree, TwoBytes twoBytes, TwoBytes twoBytesNullFree) { 407 strictField1 = val8; 408 strictField2 = val8; 409 strictField3 = val8NullFree; 410 strictField4 = val8NullFree; 411 strictField5 = val8NullFree; 412 strictField6 = val8NullFree; 413 414 strictField7 = twoBytes; 415 strictField8 = twoBytes; 416 strictField9 = twoBytesNullFree; 417 strictField10 = twoBytesNullFree; 418 strictField11 = twoBytesNullFree; 419 strictField12 = twoBytesNullFree; 420 } 421 } 422 423 @Strict 424 @NullRestricted 425 MyValueEmpty emptyField1 = new MyValueEmpty(); 426 @Strict 427 @NullRestricted 428 volatile MyValueEmpty emptyField2 = new MyValueEmpty(); 429 MyValueEmpty emptyField3; 430 volatile MyValueEmpty emptyField4; 431 432 static final MyValue1 VAL1 = new MyValue1((byte)42, new MyValue2((byte)43), null); 433 static final MyValue4 VAL4 = new MyValue4(new MyValue3((byte)42), null); 434 static final MyValue5 VAL5 = new MyValue5((byte)42, new MyValue5_1((byte)43, new MyValue5_2((byte)44, new MyValue5_3((byte)45)))); 435 static final MyValue6 VAL6 = new MyValue6(new MyValueEmpty()); 436 static final MyValue7 VAL7 = new MyValue7(new MyValue6(new MyValueEmpty())); 437 438 // Using two bytes such that null-free fields will not be naturally atomic 439 @LooselyConsistentValue 440 static value class TwoBytes { 441 byte b1; 442 byte b2; 443 444 public TwoBytes(byte b1, byte b2) { 445 this.b1 = b1; 446 this.b2 = b2; 447 } 448 449 public static final TwoBytes DEFAULT = new TwoBytes((byte)0, (byte)0); 450 } 451 452 static private final MyValue8 CANARY_VALUE = new MyValue8((byte)42); 453 454 public static class Cage1 { 455 MyValue8 canary1 = CANARY_VALUE; 456 457 @Strict 458 @NullRestricted 459 volatile TwoBytes field = TwoBytes.DEFAULT; 460 461 MyValue8 canary2 = CANARY_VALUE; 462 463 public void verify(TwoBytes val) { 464 Asserts.assertEQ(canary1, CANARY_VALUE); 465 Asserts.assertEQ(field, val); 466 Asserts.assertEQ(canary2, CANARY_VALUE); 467 } 468 } 469 470 public static class Cage2 { 471 @Strict 472 @NullRestricted 473 MyValue8 canary1 = CANARY_VALUE; 474 475 @Strict 476 @NullRestricted 477 volatile TwoBytes field = TwoBytes.DEFAULT; 478 479 @Strict 480 @NullRestricted 481 MyValue8 canary2 = CANARY_VALUE; 482 483 public void verify(TwoBytes val) { 484 Asserts.assertEQ(canary1, CANARY_VALUE); 485 Asserts.assertEQ(field, val); 486 Asserts.assertEQ(canary2, CANARY_VALUE); 487 } 488 } 489 490 public static class Cage3 { 491 @Strict 492 @NullRestricted 493 MyValue8 canary1 = CANARY_VALUE; 494 495 volatile TwoBytes field; 496 497 @Strict 498 @NullRestricted 499 MyValue8 canary2 = CANARY_VALUE; 500 501 public void verify(TwoBytes val) { 502 Asserts.assertEQ(canary1, CANARY_VALUE); 503 Asserts.assertEQ(field, val); 504 Asserts.assertEQ(canary2, CANARY_VALUE); 505 } 506 } 507 508 public static class Cage4 { 509 MyValue8 canary1 = CANARY_VALUE; 510 511 volatile TwoBytes field; 512 513 MyValue8 canary2 = CANARY_VALUE; 514 515 public void verify(TwoBytes val) { 516 Asserts.assertEQ(canary1, CANARY_VALUE); 517 Asserts.assertEQ(field, val); 518 Asserts.assertEQ(canary2, CANARY_VALUE); 519 } 520 } 521 522 static final Cage1 canaryCage1 = new Cage1(); 523 static final Cage2 canaryCage2 = new Cage2(); 524 static final Cage3 canaryCage3 = new Cage3(); 525 static final Cage4 canaryCage4 = new Cage4(); 526 527 // Check that the canary values are not accidentally overwritten 528 public void testOutOfBoundsAccess(int i) { 529 TwoBytes val = new TwoBytes((byte)i, (byte)(i+1)); 530 canaryCage1.field = val; 531 canaryCage1.verify(val); 532 533 canaryCage2.field = val; 534 canaryCage2.verify(val); 535 536 canaryCage3.field = val; 537 canaryCage3.verify(val); 538 539 canaryCage3.field = null; 540 canaryCage3.verify(null); 541 542 canaryCage4.field = val; 543 canaryCage4.verify(val); 544 545 canaryCage4.field = null; 546 canaryCage4.verify(null); 547 } 548 549 // Test that the calling convention is keeping track of the null marker 550 public MyValue1 testHelper1(MyValue1 val) { 551 return val; 552 } 553 554 public void testSet1(MyValue1 val) { 555 field1 = testHelper1(val); 556 } 557 558 public MyValue1 testGet1() { 559 return field1; 560 } 561 562 public void testDeopt1(byte x, MyValue1 neverNull, MyValue1 alwaysNull, boolean deopt) { 563 MyValue2 val2 = new MyValue2(x); 564 MyValue1 val1 = new MyValue1(x, val2, val2); 565 if (deopt) { 566 Asserts.assertEQ(val1.x, x); 567 Asserts.assertEQ(val1.val1, val2); 568 Asserts.assertEQ(val1.val2, val2); 569 Asserts.assertEQ(neverNull.x, x); 570 Asserts.assertEQ(neverNull.val1, val2); 571 Asserts.assertEQ(neverNull.val2, val2); 572 Asserts.assertEQ(alwaysNull.x, x); 573 Asserts.assertEQ(alwaysNull.val1, null); 574 Asserts.assertEQ(alwaysNull.val2, null); 575 } 576 } 577 578 public void testOSR() { 579 // Trigger OSR 580 for (int i = 0; i < 100_000; ++i) { 581 field1 = null; 582 Asserts.assertEQ(field1, null); 583 MyValue2 val2 = new MyValue2((byte)i); 584 MyValue1 val = new MyValue1((byte)i, val2, null); 585 field1 = val; 586 Asserts.assertEQ(field1.x, (byte)i); 587 Asserts.assertEQ(field1.val1, val2); 588 Asserts.assertEQ(field1.val2, null); 589 } 590 } 591 592 public boolean testACmp(MyValue2 val2) { 593 return field1.val1 == val2; 594 } 595 596 // Test that the calling convention is keeping track of the null marker 597 public MyValue4 testHelper2(MyValue4 val) { 598 return val; 599 } 600 601 public void testSet2(MyValue4 val) { 602 field2 = testHelper2(val); 603 } 604 605 public MyValue4 testGet2() { 606 return field2; 607 } 608 609 public void testDeopt2(byte x, MyValue4 neverNull, MyValue4 alwaysNull, boolean deopt) { 610 MyValue3 val3 = new MyValue3(x); 611 MyValue4 val4 = new MyValue4(val3, null); 612 if (deopt) { 613 Asserts.assertEQ(val4.val1, val3); 614 Asserts.assertEQ(val4.val2, null); 615 Asserts.assertEQ(neverNull.val1, val3); 616 Asserts.assertEQ(neverNull.val2, val3); 617 Asserts.assertEQ(alwaysNull.val1, null); 618 Asserts.assertEQ(alwaysNull.val2, null); 619 } 620 } 621 622 // Test that the calling convention is keeping track of the null marker 623 public MyValue5 testHelper3(MyValue5 val) { 624 return val; 625 } 626 627 public void testSet3(MyValue5 val) { 628 field3 = testHelper3(val); 629 } 630 631 public MyValue5 testGet3() { 632 return field3; 633 } 634 635 public void testDeopt3(byte x, MyValue5 val6, MyValue5 val7, MyValue5 val8, MyValue5 val9, boolean deopt) { 636 MyValue5 val1 = new MyValue5(x, new MyValue5_1(x, new MyValue5_2(x, new MyValue5_3(x)))); 637 MyValue5 val2 = new MyValue5(x, new MyValue5_1(x, new MyValue5_2(x, null))); 638 MyValue5 val3 = new MyValue5(x, new MyValue5_1(x, null)); 639 MyValue5 val4 = new MyValue5(x, null); 640 MyValue5 val5 = null; 641 if (deopt) { 642 Asserts.assertEQ(val1.x, x); 643 Asserts.assertEQ(val1.val.x, x); 644 Asserts.assertEQ(val1.val.val.x, x); 645 Asserts.assertEQ(val1.val.val.val.x, x); 646 Asserts.assertEQ(val2.x, x); 647 Asserts.assertEQ(val2.val.x, x); 648 Asserts.assertEQ(val2.val.val.x, x); 649 Asserts.assertEQ(val2.val.val.val, null); 650 Asserts.assertEQ(val3.x, x); 651 Asserts.assertEQ(val3.val.x, x); 652 Asserts.assertEQ(val3.val.val, null); 653 Asserts.assertEQ(val4.x, x); 654 Asserts.assertEQ(val4.val, null); 655 Asserts.assertEQ(val5, null); 656 657 Asserts.assertEQ(val6.x, x); 658 Asserts.assertEQ(val6.val.x, x); 659 Asserts.assertEQ(val6.val.val.x, x); 660 Asserts.assertEQ(val6.val.val.val.x, x); 661 Asserts.assertEQ(val7.x, x); 662 Asserts.assertEQ(val7.val.x, x); 663 Asserts.assertEQ(val7.val.val.x, x); 664 Asserts.assertEQ(val7.val.val.val, null); 665 Asserts.assertEQ(val8.x, x); 666 Asserts.assertEQ(val8.val.x, x); 667 Asserts.assertEQ(val8.val.val, null); 668 Asserts.assertEQ(val9.x, x); 669 Asserts.assertEQ(val9.val, null); 670 } 671 } 672 673 // Test that the calling convention is keeping track of the null marker 674 public MyValue6 testHelper4(MyValue6 val) { 675 return val; 676 } 677 678 public void testSet4(MyValue6 val) { 679 field4 = testHelper4(val); 680 } 681 682 public MyValue6 testGet4() { 683 return field4; 684 } 685 686 public void testDeopt4(MyValue6 val4, MyValue6 val5, MyValue6 val6, boolean deopt) { 687 MyValue6 val1 = new MyValue6(new MyValueEmpty()); 688 MyValue6 val2 = new MyValue6(null); 689 MyValue6 val3 = null; 690 if (deopt) { 691 Asserts.assertEQ(val1.val, new MyValueEmpty()); 692 Asserts.assertEQ(val2.val, null); 693 Asserts.assertEQ(val3, null); 694 695 Asserts.assertEQ(val4.val, new MyValueEmpty()); 696 Asserts.assertEQ(val5.val, null); 697 Asserts.assertEQ(val6, null); 698 } 699 } 700 701 // Test that the calling convention is keeping track of the null marker 702 public MyValue7 testHelper5(MyValue7 val) { 703 return val; 704 } 705 706 public void testSet5(MyValue7 val) { 707 field5 = testHelper5(val); 708 } 709 710 public MyValue7 testGet5() { 711 return field5; 712 } 713 714 public void testDeopt5(MyValue7 val5, MyValue7 val6, MyValue7 val7, MyValue7 val8, boolean deopt) { 715 MyValue7 val1 = new MyValue7(new MyValue6(new MyValueEmpty())); 716 MyValue7 val2 = new MyValue7(new MyValue6(null)); 717 MyValue7 val3 = new MyValue7(null); 718 MyValue7 val4 = null; 719 if (deopt) { 720 Asserts.assertEQ(val1.val, new MyValue6(new MyValueEmpty())); 721 Asserts.assertEQ(val2.val, new MyValue6(null)); 722 Asserts.assertEQ(val3.val, null); 723 Asserts.assertEQ(val4, null); 724 725 Asserts.assertEQ(val5.val, new MyValue6(new MyValueEmpty())); 726 Asserts.assertEQ(val6.val, new MyValue6(null)); 727 Asserts.assertEQ(val7.val, null); 728 Asserts.assertEQ(val8, null); 729 } 730 } 731 732 // Make sure that flat field accesses contain a (implicit) null check 733 public static void testNPE1() { 734 TestFieldNullMarkers t = null; 735 try { 736 MyValue8 v = t.field6; 737 throw new RuntimeException("No NPE thrown!"); 738 } catch (NullPointerException e) { 739 // Expected 740 } 741 } 742 743 public static void testNPE2() { 744 TestFieldNullMarkers t = null; 745 try { 746 t.field6 = null; 747 throw new RuntimeException("No NPE thrown!"); 748 } catch (NullPointerException e) { 749 // Expected 750 } 751 } 752 753 public void checkFields(int i) { 754 Asserts.assertEQ(field6.b, (byte)i); 755 Asserts.assertEQ(field7.s, (short)i); 756 Asserts.assertEQ(field8.i, i); 757 Asserts.assertEQ(field9.f, (float)i); 758 Asserts.assertEQ(field10.c, (char)i); 759 Asserts.assertEQ(field11.b, (i % 2) == 0); 760 } 761 762 // Test that writing and reading a (signed) byte stays in bounds 763 public void testBounds(int i) { 764 MyValue8 val = new MyValue8((byte)i); 765 field6 = val; 766 int b = field6.b; 767 if (b < -128 || b > 127) { 768 throw new RuntimeException("Byte value out of bounds: " + b); 769 } 770 } 771 772 static void produceGarbage() { 773 for (int i = 0; i < 100; ++i) { 774 Object[] arrays = new Object[1024]; 775 for (int j = 0; j < arrays.length; j++) { 776 arrays[j] = new int[1024]; 777 } 778 } 779 System.gc(); 780 } 781 782 // Test that barriers are emitted when writing flat, atomic fields with oops 783 public void testWriteOopFields1(MyValue15 val) { 784 field17 = val; 785 field18 = val; 786 } 787 788 public void testWriteOopFields2(MyValue16 val) { 789 field19 = val; 790 } 791 792 public void testWriteOopFields3(MyValue17 val) { 793 field20 = val; 794 field21 = val; 795 } 796 797 public static class MyHolderClass9 { 798 @Strict 799 @NullRestricted 800 TwoBytes field1 = TwoBytes.DEFAULT; 801 802 TwoBytes field2; 803 804 @Strict 805 @NullRestricted 806 volatile TwoBytes field3 = TwoBytes.DEFAULT; 807 808 volatile TwoBytes field4; 809 } 810 811 static final MyHolderClass9 constantHolder = new MyHolderClass9(); 812 813 // Test loading a flat field from a constant container (should not be constant folded because fields are immutable) 814 public void testLoadingFromConstantHolder(int i) { 815 TwoBytes val = new TwoBytes((byte)i, (byte)(i + 1)); 816 constantHolder.field1 = val; 817 Asserts.assertEQ(constantHolder.field1, val); 818 819 constantHolder.field2 = val; 820 Asserts.assertEQ(constantHolder.field2, val); 821 822 constantHolder.field2 = null; 823 Asserts.assertEQ(constantHolder.field2, null); 824 825 constantHolder.field3 = val; 826 Asserts.assertEQ(constantHolder.field3, val); 827 828 constantHolder.field4 = val; 829 Asserts.assertEQ(constantHolder.field4, val); 830 831 constantHolder.field4 = null; 832 Asserts.assertEQ(constantHolder.field4, null); 833 } 834 835 public void testStrictFields(StrictFieldHolder holder, MyValue8 val8, MyValue8 val8NullFree, TwoBytes twoBytes, TwoBytes twoBytesNullFree) { 836 Asserts.assertEQ(holder.strictField1, val8); 837 Asserts.assertEQ(holder.strictField2, val8); 838 Asserts.assertEQ(holder.strictField3, val8NullFree); 839 Asserts.assertEQ(holder.strictField4, val8NullFree); 840 Asserts.assertEQ(holder.strictField5, val8NullFree); 841 Asserts.assertEQ(holder.strictField6, val8NullFree); 842 843 Asserts.assertEQ(holder.strictField7, twoBytes); 844 Asserts.assertEQ(holder.strictField8, twoBytes); 845 Asserts.assertEQ(holder.strictField9, twoBytesNullFree); 846 Asserts.assertEQ(holder.strictField10, twoBytesNullFree); 847 Asserts.assertEQ(holder.strictField11, twoBytesNullFree); 848 Asserts.assertEQ(holder.strictField12, twoBytesNullFree); 849 } 850 851 public static void main(String[] args) { 852 TestFieldNullMarkers t = new TestFieldNullMarkers(); 853 t.testOSR(); 854 855 final int LIMIT = 50_000; 856 for (int i = -50_000; i < LIMIT; ++i) { 857 t.field1 = null; 858 Asserts.assertEQ(t.testGet1(), null); 859 860 boolean useNull = (i % 2) == 0; 861 MyValue2 val2 = useNull ? null : new MyValue2((byte)i); 862 MyValue1 val = new MyValue1((byte)i, val2, val2); 863 t.field1 = val; 864 Asserts.assertEQ(t.testGet1().x, val.x); 865 Asserts.assertEQ(t.testGet1().val1, val2); 866 Asserts.assertEQ(t.testGet1().val2, val2); 867 868 Asserts.assertTrue(t.testACmp(val2)); 869 870 t.testSet1(null); 871 Asserts.assertEQ(t.field1, null); 872 873 t.testSet1(val); 874 Asserts.assertEQ(t.field1.x, val.x); 875 Asserts.assertEQ(t.field1.val1, val2); 876 Asserts.assertEQ(t.field1.val2, val2); 877 878 t.testDeopt1((byte)i, null, null, false); 879 880 t.field2 = null; 881 Asserts.assertEQ(t.testGet2(), null); 882 883 MyValue3 val3 = useNull ? null : new MyValue3((byte)i); 884 MyValue4 val4 = new MyValue4(val3, val3); 885 t.field2 = val4; 886 Asserts.assertEQ(t.testGet2().val1, val3); 887 Asserts.assertEQ(t.testGet2().val2, val3); 888 889 t.testSet2(null); 890 Asserts.assertEQ(t.testGet2(), null); 891 892 t.testSet2(val4); 893 Asserts.assertEQ(t.testGet2().val1, val3); 894 Asserts.assertEQ(t.testGet2().val2, val3); 895 896 t.testDeopt2((byte)i, null, null, false); 897 898 t.field3 = null; 899 Asserts.assertEQ(t.testGet3(), null); 900 901 boolean useNull_1 = (i % 4) == 0; 902 boolean useNull_2 = (i % 4) == 1; 903 boolean useNull_3 = (i % 4) == 2; 904 MyValue5_3 val5_3 = useNull_3 ? null : new MyValue5_3((byte)i); 905 MyValue5_2 val5_2 = useNull_2 ? null : new MyValue5_2((byte)i, val5_3); 906 MyValue5_1 val5_1 = useNull_1 ? null : new MyValue5_1((byte)i, val5_2); 907 MyValue5 val5 = new MyValue5((byte)i, val5_1); 908 t.field3 = val5; 909 Asserts.assertEQ(t.testGet3().x, val5.x); 910 if (useNull_1) { 911 Asserts.assertEQ(t.testGet3().val, null); 912 } else { 913 Asserts.assertEQ(t.testGet3().val.x, val5_1.x); 914 if (useNull_2) { 915 Asserts.assertEQ(t.testGet3().val.val, null); 916 } else { 917 Asserts.assertEQ(t.testGet3().val.val.x, val5_2.x); 918 if (useNull_3) { 919 Asserts.assertEQ(t.testGet3().val.val.val, null); 920 } else { 921 Asserts.assertEQ(t.testGet3().val.val.val.x, val5_3.x); 922 } 923 } 924 } 925 926 t.testSet3(null); 927 Asserts.assertEQ(t.field3, null); 928 929 t.testSet3(val5); 930 Asserts.assertEQ(t.testGet3().x, val5.x); 931 if (useNull_1) { 932 Asserts.assertEQ(t.testGet3().val, null); 933 } else { 934 Asserts.assertEQ(t.testGet3().val.x, val5_1.x); 935 if (useNull_2) { 936 Asserts.assertEQ(t.testGet3().val.val, null); 937 } else { 938 Asserts.assertEQ(t.testGet3().val.val.x, val5_2.x); 939 if (useNull_3) { 940 Asserts.assertEQ(t.testGet3().val.val.val, null); 941 } else { 942 Asserts.assertEQ(t.testGet3().val.val.val.x, val5_3.x); 943 } 944 } 945 } 946 t.testDeopt3((byte)i, null, null, null, null, false); 947 948 t.field4 = null; 949 Asserts.assertEQ(t.testGet4(), null); 950 951 MyValueEmpty empty = useNull ? null : new MyValueEmpty(); 952 MyValue6 val6 = new MyValue6(empty); 953 t.field4 = val6; 954 Asserts.assertEQ(t.testGet4().val, empty); 955 956 t.testSet4(null); 957 Asserts.assertEQ(t.testGet4(), null); 958 959 t.testSet4(val6); 960 Asserts.assertEQ(t.testGet4().val, empty); 961 962 t.testDeopt4(null, null, null, false); 963 964 t.field5 = null; 965 Asserts.assertEQ(t.testGet5(), null); 966 967 empty = ((i % 3) == 0) ? null : new MyValueEmpty(); 968 val6 = ((i % 3) == 1) ? null : new MyValue6(empty); 969 MyValue7 val7 = new MyValue7(val6); 970 t.field5 = val7; 971 Asserts.assertEQ(t.testGet5().val, val6); 972 973 t.testSet5(null); 974 Asserts.assertEQ(t.testGet5(), null); 975 976 t.testSet5(val7); 977 Asserts.assertEQ(t.testGet5().val, val6); 978 979 t.testDeopt5(null, null, null, null, false); 980 981 // Check accesses with constant value 982 t.field1 = VAL1; 983 Asserts.assertEQ(t.field1.x, VAL1.x); 984 Asserts.assertEQ(t.field1.val1, VAL1.val1); 985 Asserts.assertEQ(t.field1.val2, VAL1.val2); 986 987 t.field2 = VAL4; 988 Asserts.assertEQ(t.field2.val1, VAL4.val1); 989 Asserts.assertEQ(t.field2.val2, VAL4.val2); 990 991 t.field3 = VAL5; 992 Asserts.assertEQ(t.field3.x, VAL5.x); 993 Asserts.assertEQ(t.field3.val.x, VAL5.val.x); 994 Asserts.assertEQ(t.field3.val.val.x, VAL5.val.val.x); 995 Asserts.assertEQ(t.field3.val.val.val.x, VAL5.val.val.val.x); 996 997 t.field4 = VAL6; 998 Asserts.assertEQ(t.field4.val, VAL6.val); 999 1000 t.field5 = VAL7; 1001 Asserts.assertEQ(t.field5.val, VAL7.val); 1002 1003 // Some more values classes with different flavors of primitive fields 1004 t.field6 = null; 1005 Asserts.assertEQ(t.field6, null); 1006 t.field6 = new MyValue8((byte)i); 1007 Asserts.assertEQ(t.field6.b, (byte)i); 1008 t.field7 = null; 1009 Asserts.assertEQ(t.field7, null); 1010 t.field7 = new MyValue9((short)i); 1011 Asserts.assertEQ(t.field7.s, (short)i); 1012 t.field8 = null; 1013 Asserts.assertEQ(t.field8, null); 1014 t.field8 = new MyValue10(i); 1015 Asserts.assertEQ(t.field8.i, i); 1016 t.field9 = null; 1017 Asserts.assertEQ(t.field9, null); 1018 t.field9 = new MyValue11((float)i); 1019 Asserts.assertEQ(t.field9.f, (float)i); 1020 t.field10 = null; 1021 Asserts.assertEQ(t.field10, null); 1022 t.field10 = new MyValue12((char)i); 1023 Asserts.assertEQ(t.field10.c, (char)i); 1024 t.field11 = null; 1025 Asserts.assertEQ(t.field11, null); 1026 t.field11 = new MyValue13((i % 2) == 0); 1027 Asserts.assertEQ(t.field11.b, (i % 2) == 0); 1028 1029 // Write the fields again and check that we don't overwrite other fields 1030 t.checkFields(i); 1031 t.field6 = new MyValue8((byte)i); 1032 t.checkFields(i); 1033 t.field7 = new MyValue9((short)i); 1034 t.checkFields(i); 1035 t.field8 = new MyValue10(i); 1036 t.checkFields(i); 1037 t.field9 = new MyValue11((float)i); 1038 t.checkFields(i); 1039 t.field10 = new MyValue12((char)i); 1040 t.checkFields(i); 1041 t.field11 = new MyValue13((i % 2) == 0); 1042 t.checkFields(i); 1043 1044 testNPE1(); 1045 testNPE2(); 1046 1047 t.testBounds(i); 1048 1049 // Null-free, flat, atomic 1050 MyValue8 val8 = new MyValue8((byte)i); 1051 t.field12 = val8; 1052 Asserts.assertEQ(t.field12.b, (byte)i); 1053 1054 try { 1055 t.field12 = null; 1056 throw new RuntimeException("No NPE thrown"); 1057 } catch (NullPointerException npe) { 1058 // Expected 1059 } 1060 1061 // Null-free, flat with both nullable and null-free fields 1062 t.field13 = new MyValue14(val8, val8); 1063 Asserts.assertEQ(t.field13.nullfree, val8); 1064 Asserts.assertEQ(t.field13.nullable, val8); 1065 1066 t.field13 = new MyValue14(val8, null); 1067 Asserts.assertEQ(t.field13.nullfree, val8); 1068 Asserts.assertEQ(t.field13.nullable, null); 1069 1070 try { 1071 t.field13 = new MyValue14(null, null); 1072 throw new RuntimeException("No NPE thrown"); 1073 } catch (NullPointerException npe) { 1074 // Expected 1075 } 1076 try { 1077 t.field13 = null; 1078 throw new RuntimeException("No NPE thrown"); 1079 } catch (NullPointerException npe) { 1080 // Expected 1081 } 1082 1083 // Nullable, atomic, flat with both nullable and null-free fields 1084 t.field14 = null; 1085 Asserts.assertEQ(t.field14, null); 1086 1087 t.field14 = new MyValue14(val8, val8); 1088 Asserts.assertEQ(t.field14.nullfree, val8); 1089 Asserts.assertEQ(t.field14.nullable, val8); 1090 1091 t.field14 = new MyValue14(val8, null); 1092 Asserts.assertEQ(t.field14.nullfree, val8); 1093 Asserts.assertEQ(t.field14.nullable, null); 1094 1095 try { 1096 t.field14 = new MyValue14(null, null); 1097 throw new RuntimeException("No NPE thrown"); 1098 } catch (NullPointerException npe) { 1099 // Expected 1100 } 1101 1102 // Nullable, (atomic), flat with both nullable and null-free fields 1103 t.field15 = null; 1104 Asserts.assertEQ(t.field15, null); 1105 1106 t.field15 = new MyValue14(val8, val8); 1107 Asserts.assertEQ(t.field15.nullfree, val8); 1108 Asserts.assertEQ(t.field15.nullable, val8); 1109 1110 t.field15 = new MyValue14(val8, null); 1111 Asserts.assertEQ(t.field15.nullfree, val8); 1112 Asserts.assertEQ(t.field15.nullable, null); 1113 1114 try { 1115 t.field15 = new MyValue14(null, null); 1116 throw new RuntimeException("No NPE thrown"); 1117 } catch (NullPointerException npe) { 1118 // Expected 1119 } 1120 1121 // Null-free, atomic, flat with both nullable and null-free fields 1122 t.field16 = new MyValue14(val8, val8); 1123 Asserts.assertEQ(t.field16.nullfree, val8); 1124 Asserts.assertEQ(t.field16.nullable, val8); 1125 1126 t.field16 = new MyValue14(val8, null); 1127 Asserts.assertEQ(t.field16.nullfree, val8); 1128 Asserts.assertEQ(t.field16.nullable, null); 1129 1130 try { 1131 t.field16 = new MyValue14(null, null); 1132 throw new RuntimeException("No NPE thrown"); 1133 } catch (NullPointerException npe) { 1134 // Expected 1135 } 1136 try { 1137 t.field16 = null; 1138 throw new RuntimeException("No NPE thrown"); 1139 } catch (NullPointerException npe) { 1140 // Expected 1141 } 1142 1143 MyValue15 val15 = new MyValue15(new MyClass(i)); 1144 t.testWriteOopFields1(val15); 1145 if (i > (LIMIT - 50)) { 1146 // After warmup, produce some garbage to trigger GC 1147 produceGarbage(); 1148 } 1149 Asserts.assertEQ(t.field17.obj.x, i); 1150 Asserts.assertEQ(t.field18.obj.x, i); 1151 1152 MyValue16 val16 = new MyValue16(new MyClass(i), new MyClass(i)); 1153 t.testWriteOopFields2(val16); 1154 if (i > (LIMIT - 50)) { 1155 // After warmup, produce some garbage to trigger GC 1156 produceGarbage(); 1157 } 1158 Asserts.assertEQ(t.field19.obj1.x, i); 1159 Asserts.assertEQ(t.field19.obj2.x, i); 1160 1161 MyValue17 val17 = new MyValue17(new MyClass(i), (byte)i, (byte)i); 1162 t.testWriteOopFields3(val17); 1163 if (i > (LIMIT - 50)) { 1164 // After warmup, produce some garbage to trigger GC 1165 produceGarbage(); 1166 } 1167 Asserts.assertEQ(t.field20.obj.x, i); 1168 Asserts.assertEQ(t.field20.b1, (byte)i); 1169 Asserts.assertEQ(t.field20.b2, (byte)i); 1170 Asserts.assertEQ(t.field21.obj.x, i); 1171 Asserts.assertEQ(t.field21.b1, (byte)i); 1172 Asserts.assertEQ(t.field21.b2, (byte)i); 1173 1174 Asserts.assertEQ(t.emptyField1, new MyValueEmpty()); 1175 Asserts.assertEQ(t.emptyField2, new MyValueEmpty()); 1176 1177 // Test empty fields 1178 t.emptyField3 = new MyValueEmpty(); 1179 t.emptyField4 = new MyValueEmpty(); 1180 Asserts.assertEQ(t.emptyField3, new MyValueEmpty()); 1181 Asserts.assertEQ(t.emptyField4, new MyValueEmpty()); 1182 t.emptyField3 = null; 1183 t.emptyField4 = null; 1184 Asserts.assertEQ(t.emptyField3, null); 1185 Asserts.assertEQ(t.emptyField4, null); 1186 1187 t.testLoadingFromConstantHolder(i); 1188 1189 // Verify that no out of bounds accesses happen 1190 t.testOutOfBoundsAccess(i); 1191 1192 // Test strict fields 1193 // TODO 8355277 Re-enable 1194 /* 1195 TwoBytes twoBytes = new TwoBytes((byte)i, (byte)(i + 1)); 1196 t.testStrictFields(new StrictFieldHolder(val8, val8, twoBytes, twoBytes), val8, val8, twoBytes, twoBytes); 1197 t.testStrictFields(new StrictFieldHolder(null, val8, null, twoBytes), null, val8, null, twoBytes); 1198 */ 1199 } 1200 1201 // Trigger deoptimization to check that re-materialization takes the null marker into account 1202 byte x = (byte)42; 1203 t.testDeopt1(x, new MyValue1(x, new MyValue2(x), new MyValue2(x)), new MyValue1(x, null, null), true); 1204 t.testDeopt2(x, new MyValue4(new MyValue3(x), new MyValue3(x)), new MyValue4(null, null), true); 1205 1206 MyValue5 val1 = new MyValue5(x, new MyValue5_1(x, new MyValue5_2(x, new MyValue5_3(x)))); 1207 MyValue5 val2 = new MyValue5(x, new MyValue5_1(x, new MyValue5_2(x, null))); 1208 MyValue5 val3 = new MyValue5(x, new MyValue5_1(x, null)); 1209 MyValue5 val4 = new MyValue5(x, null); 1210 t.testDeopt3(x, val1, val2, val3, val4, true); 1211 1212 MyValue6 val5 = new MyValue6(new MyValueEmpty()); 1213 MyValue6 val6 = new MyValue6(null); 1214 MyValue6 val7 = null; 1215 t.testDeopt4(val5, val6, val7, true); 1216 1217 MyValue7 val8 = new MyValue7(new MyValue6(new MyValueEmpty())); 1218 MyValue7 val9 = new MyValue7(new MyValue6(null)); 1219 MyValue7 val10 = new MyValue7(null); 1220 MyValue7 val11 = null; 1221 t.testDeopt5(val8, val9, val10, val11, false); 1222 } 1223 } 1224