1 /*
   2  * Copyright (c) 2019, 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 compiler.lib.ir_framework.*;
  27 import jdk.test.lib.Asserts;
  28 
  29 import jdk.internal.value.ValueClass;
  30 import jdk.internal.vm.annotation.LooselyConsistentValue;
  31 import jdk.internal.vm.annotation.NullRestricted;
  32 import jdk.internal.vm.annotation.Strict;
  33 
  34 import static compiler.valhalla.inlinetypes.InlineTypes.rI;
  35 
  36 /*
  37  * @test
  38  * @key randomness
  39  * @summary Test the handling of fields of unloaded value classes.
  40  * @library /test/lib /
  41  * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64")
  42  * @enablePreview
  43  * @modules java.base/jdk.internal.value
  44  *          java.base/jdk.internal.vm.annotation
  45  * @compile hack/GetUnresolvedInlineFieldWrongSignature.java
  46  * @compile TestUnloadedInlineTypeField.java
  47  * @run main/othervm/timeout=300 compiler.valhalla.inlinetypes.TestUnloadedInlineTypeField
  48  */
  49 
  50 public class TestUnloadedInlineTypeField {
  51     // Only prevent loading of classes when testing with C1. Load classes
  52     // early when executing with C2 to prevent uncommon traps. It's still
  53     // beneficial to execute this test with C2 because it also checks handling
  54     // of type mismatches.
  55 
  56     public static void main(String[] args) {
  57         final Scenario[] scenarios = {
  58                 new Scenario(0),
  59                 new Scenario(1, "-XX:-UseFieldFlattening"),
  60                 new Scenario(2, "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PatchALot"),
  61                 new Scenario(3, "-XX:-UseFieldFlattening",
  62                                 "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PatchALot")
  63         };
  64         InlineTypes.getFramework()
  65                    .addScenarios(scenarios)
  66                    .addFlags("--enable-preview",
  67                              // Prevent IR Test Framework from loading classes
  68                              "-DIgnoreCompilerControls=true",
  69                              // Some tests trigger frequent re-compilation. Don't mark them as non-compilable.
  70                              "-XX:PerMethodRecompilationCutoff=-1", "-XX:PerBytecodeRecompilationCutoff=-1")
  71                    .start();
  72     }
  73 
  74     // Test case 1:
  75     // The value class field class has been loaded, but the holder class has not been loaded.
  76     //
  77     //     aload_0
  78     //     getfield  MyValue1Holder.v:LMyValue1;
  79     //               ^ not loaded      ^ already loaded
  80     //
  81     // MyValue1 has already been loaded, because it's in the preload attribute of
  82     // TestUnloadedInlineTypeField, due to TestUnloadedInlineTypeField.test1_precondition().
  83     @LooselyConsistentValue
  84     static value class MyValue1 {
  85         int foo;
  86 
  87         MyValue1() {
  88             foo = rI;
  89         }
  90     }
  91 
  92     static class MyValue1Holder {
  93         @Strict
  94         @NullRestricted
  95         MyValue1 v;
  96 
  97         public MyValue1Holder() {
  98             v = new MyValue1();
  99         }
 100     }
 101 
 102     static MyValue1 test1_precondition() {
 103         return new MyValue1();
 104     }
 105 
 106     @Test
 107     public int test1(Object holder) {
 108         if (holder != null) {
 109             // Don't use MyValue1Holder in the signature, it might trigger class loading
 110             return ((MyValue1Holder)holder).v.foo;
 111         } else {
 112             return 0;
 113         }
 114     }
 115 
 116     @Run(test = "test1")
 117     public void test1_verifier(RunInfo info) {
 118         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 119             test1(null);
 120         } else {
 121             MyValue1Holder holder = new MyValue1Holder();
 122             Asserts.assertEQ(test1(holder), rI);
 123         }
 124     }
 125 
 126     // Test case 2:
 127     // Both the value class field class, and the holder class have not been loaded.
 128     //
 129     //     aload_0
 130     //     getfield  MyValue2Holder.v:LMyValue2;
 131     //               ^ not loaded     ^ not loaded
 132     //
 133     // MyValue2 has not been loaded, because it is not explicitly referenced by
 134     // TestUnloadedInlineTypeField.
 135     @LooselyConsistentValue
 136     static value class MyValue2 {
 137         int foo;
 138 
 139         public MyValue2(int n) {
 140             foo = n;
 141         }
 142     }
 143 
 144     static class MyValue2Holder {
 145         @Strict
 146         @NullRestricted
 147         MyValue2 v;
 148 
 149         public MyValue2Holder() {
 150             v = new MyValue2(rI);
 151         }
 152     }
 153 
 154     @Test
 155     public int test2(Object holder) {
 156         if (holder != null) {
 157             // Don't use MyValue2Holder in the signature, it might trigger class loading
 158             return ((MyValue2Holder)holder).v.foo;
 159         } else {
 160             return 0;
 161         }
 162     }
 163 
 164     @Run(test = "test2")
 165     public void test2_verifier(RunInfo info) {
 166         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 167             test2(null);
 168         } else {
 169             MyValue2Holder holder = new MyValue2Holder();
 170             Asserts.assertEQ(test2(holder), rI);
 171         }
 172     }
 173 
 174     // Test case 4:
 175     // Same as case 1, except we use putfield instead of getfield.
 176     @LooselyConsistentValue
 177     static value class MyValue4 {
 178         int foo;
 179 
 180         MyValue4(int n) {
 181             foo = n;
 182         }
 183     }
 184 
 185     static class MyValue4Holder {
 186         @Strict
 187         @NullRestricted
 188         MyValue4 v;
 189 
 190         public MyValue4Holder() {
 191             v = new MyValue4(0);
 192         }
 193     }
 194 
 195     @Test
 196     public void test4(Object holder, MyValue4 v) {
 197         if (holder != null) {
 198             // Don't use MyValue4Holder in the signature, it might trigger class loading
 199             ((MyValue4Holder)holder).v = v;
 200         }
 201     }
 202 
 203     @Run(test = "test4")
 204     public void test4_verifier(RunInfo info) {
 205         MyValue4 v = new MyValue4(rI);
 206         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 207             test4(null, v);
 208         } else {
 209             MyValue4Holder holder = new MyValue4Holder();
 210             test4(holder, v);
 211             Asserts.assertEQ(holder.v.foo, rI);
 212         }
 213     }
 214 
 215     // Test case 5:
 216     // Same as case 2, except we use putfield instead of getfield.
 217     @LooselyConsistentValue
 218     static value class MyValue5 {
 219         int foo;
 220 
 221         MyValue5(int n) {
 222             foo = n;
 223         }
 224     }
 225 
 226     static class MyValue5Holder {
 227         @Strict
 228         @NullRestricted
 229         MyValue5 v;
 230 
 231         public MyValue5Holder() {
 232             v = new MyValue5(0);
 233         }
 234 
 235         public Object make(int n) {
 236             return new MyValue5(n);
 237         }
 238     }
 239 
 240     @Test
 241     public void test5(Object holder, Object o) {
 242         if (holder != null) {
 243             // Don't use MyValue5 and MyValue5Holder in the signature, it might trigger class loading
 244             MyValue5 v = (MyValue5)o;
 245             ((MyValue5Holder)holder).v = v;
 246         }
 247     }
 248 
 249     @Run(test = "test5")
 250     public void test5_verifier(RunInfo info) {
 251         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 252             test5(null, null);
 253         } else {
 254             MyValue5Holder holder = new MyValue5Holder();
 255             Object v = holder.make(rI);
 256             test5(holder, v);
 257             Asserts.assertEQ(holder.v.foo, rI);
 258         }
 259     }
 260 
 261 
 262     // Test case 6: (same as test1, except we use getstatic instead of getfield)
 263     // The value class field class has been loaded, but the holder class has not been loaded.
 264     //
 265     //     getstatic  MyValue6Holder.v:LMyValue1;
 266     //                ^ not loaded       ^ already loaded
 267     //
 268     // MyValue6 has already been loaded, because it's in the preload attribute of
 269     // TestUnloadedInlineTypeField, due to TestUnloadedInlineTypeField.test1_precondition().
 270     @LooselyConsistentValue
 271     static value class MyValue6 {
 272         int foo;
 273 
 274         MyValue6() {
 275             foo = rI;
 276         }
 277     }
 278 
 279     static class MyValue6Holder {
 280         @Strict
 281         @NullRestricted
 282         static MyValue6 v = new MyValue6();
 283     }
 284 
 285     static MyValue6 test6_precondition() {
 286         return new MyValue6();
 287     }
 288 
 289     @Test
 290     public int test6(int n) {
 291         if (n == 0) {
 292             return 0;
 293         } else {
 294             return MyValue6Holder.v.foo + n;
 295         }
 296     }
 297 
 298     @Run(test = "test6")
 299     public void test6_verifier(RunInfo info) {
 300         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 301             test6(0);
 302         } else {
 303             Asserts.assertEQ(test6(rI), 2*rI);
 304         }
 305     }
 306 
 307 
 308     // Test case 7:  (same as test2, except we use getstatic instead of getfield)
 309     // Both the value class field class, and the holder class have not been loaded.
 310     //
 311     //     getstatic  MyValue7Holder.v:LMyValue7;
 312     //                ^ not loaded       ^ not loaded
 313     //
 314     // MyValue7 has not been loaded, because it is not explicitly referenced by
 315     // TestUnloadedInlineTypeField.
 316     @LooselyConsistentValue
 317     static value class MyValue7 {
 318         int foo;
 319 
 320         MyValue7(int n) {
 321             foo = n;
 322         }
 323     }
 324 
 325     static class MyValue7Holder {
 326         @Strict
 327         @NullRestricted
 328         static MyValue7 v = new MyValue7(rI);
 329     }
 330 
 331     @Test
 332     public int test7(int n) {
 333         if (n == 0) {
 334             return 0;
 335         } else {
 336             return MyValue7Holder.v.foo + n;
 337         }
 338     }
 339 
 340     @Run(test = "test7")
 341     public void test7_verifier(RunInfo info) {
 342         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 343             test7(0);
 344         } else {
 345             Asserts.assertEQ(test7(rI), 2*rI);
 346         }
 347     }
 348 
 349     // Test case 8:
 350     // Same as case 1, except holder is allocated in test method (-> no holder null check required)
 351     @LooselyConsistentValue
 352     static value class MyValue8 {
 353         int foo;
 354 
 355         MyValue8() {
 356             foo = rI;
 357         }
 358     }
 359 
 360     static class MyValue8Holder {
 361         @Strict
 362         @NullRestricted
 363         MyValue8 v;
 364 
 365         public MyValue8Holder() {
 366             v = new MyValue8();
 367         }
 368     }
 369 
 370     static MyValue8 test8_precondition() {
 371         return new MyValue8();
 372     }
 373 
 374     @Test
 375     public int test8(boolean warmup) {
 376         if (!warmup) {
 377             MyValue8Holder holder = new MyValue8Holder();
 378             return holder.v.foo;
 379         } else {
 380             return 0;
 381         }
 382     }
 383 
 384     @Run(test = "test8")
 385     public void test8_verifier(RunInfo info) {
 386         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 387             test8(true);
 388         } else {
 389             Asserts.assertEQ(test8(false), rI);
 390         }
 391     }
 392 
 393     // Test case 9:
 394     // Same as case 2, except holder is allocated in test method (-> no holder null check required)
 395     @LooselyConsistentValue
 396     static value class MyValue9 {
 397         int foo;
 398 
 399         public MyValue9(int n) {
 400             foo = n;
 401         }
 402     }
 403 
 404     static class MyValue9Holder {
 405         @Strict
 406         @NullRestricted
 407         MyValue9 v;
 408 
 409         public MyValue9Holder() {
 410             v = new MyValue9(rI);
 411         }
 412     }
 413 
 414     @Test
 415     public int test9(boolean warmup) {
 416         if (!warmup) {
 417             MyValue9Holder holder = new MyValue9Holder();
 418             return holder.v.foo;
 419         } else {
 420             return 0;
 421         }
 422     }
 423 
 424     @Run(test = "test9")
 425     public void test9_verifier(RunInfo info) {
 426         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 427             test9(true);
 428         } else {
 429             Asserts.assertEQ(test9(false), rI);
 430         }
 431     }
 432 
 433     // Test case 11:
 434     // Same as case 4, except holder is allocated in test method (-> no holder null check required)
 435     @LooselyConsistentValue
 436     static value class MyValue11 {
 437         int foo;
 438 
 439         MyValue11(int n) {
 440             foo = n;
 441         }
 442     }
 443 
 444     static class MyValue11Holder {
 445         @Strict
 446         @NullRestricted
 447         MyValue11 v;
 448 
 449         public MyValue11Holder() {
 450             v = new MyValue11(0);
 451         }
 452     }
 453 
 454     @Test
 455     public Object test11(boolean warmup, MyValue11 v) {
 456         if (!warmup) {
 457             MyValue11Holder holder = new MyValue11Holder();
 458             holder.v = v;
 459             return holder;
 460         } else {
 461             return null;
 462         }
 463     }
 464 
 465     @Run(test = "test11")
 466     public void test11_verifier(RunInfo info) {
 467         MyValue11 v = new MyValue11(rI);
 468         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 469             test11(true, v);
 470         } else {
 471             MyValue11Holder holder = (MyValue11Holder)test11(false, v);
 472             Asserts.assertEQ(holder.v.foo, rI);
 473         }
 474     }
 475 
 476     // Test case 12:
 477     // Same as case 5, except holder is allocated in test method (-> no holder null check required)
 478     @LooselyConsistentValue
 479     static value class MyValue12 {
 480         int foo;
 481 
 482         MyValue12(int n) {
 483             foo = n;
 484         }
 485     }
 486 
 487     static class MyValue12Holder {
 488         @Strict
 489         @NullRestricted
 490         MyValue12 v;
 491 
 492         public MyValue12Holder() {
 493             v = new MyValue12(0);
 494         }
 495     }
 496 
 497     @Test
 498     public Object test12(boolean warmup, Object o) {
 499         if (!warmup) {
 500             // Don't use MyValue12 in the signature, it might trigger class loading
 501             MyValue12Holder holder = new MyValue12Holder();
 502             holder.v = (MyValue12)o;
 503             return holder;
 504         } else {
 505             return null;
 506         }
 507     }
 508 
 509     @Run(test = "test12")
 510     public void test12_verifier(RunInfo info) {
 511         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 512             test12(true, null);
 513         } else {
 514             MyValue12 v = new MyValue12(rI);
 515             MyValue12Holder holder = (MyValue12Holder)test12(false, v);
 516             Asserts.assertEQ(holder.v.foo, rI);
 517         }
 518     }
 519 
 520     // Test case 13:
 521     // Same as case 10, except MyValue13 is allocated in test method
 522     @LooselyConsistentValue
 523     static value class MyValue13 {
 524         int foo;
 525 
 526         public MyValue13() {
 527             foo = rI;
 528         }
 529     }
 530 
 531     static class MyValue13Holder {
 532         @Strict
 533         @NullRestricted
 534         MyValue13 v;
 535 
 536         public MyValue13Holder() {
 537             v = new MyValue13();
 538         }
 539     }
 540 
 541     static MyValue13 test13_precondition() {
 542         return new MyValue13();
 543     }
 544 
 545     @Test
 546     public void test13(Object holder) {
 547         // Don't use MyValue13Holder in the signature, it might trigger class loading
 548         GetUnresolvedInlineFieldWrongSignature.test13(holder);
 549     }
 550 
 551     @Run(test = "test13")
 552     public void test13_verifier(RunInfo info) {
 553         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 554             test13(null);
 555         } else {
 556             // Make sure klass is resolved
 557             for (int i = 0; i < 10; ++i) {
 558                 test13(new MyValue13Holder());
 559             }
 560         }
 561     }
 562 
 563     // Test case 15:
 564     // Same as case 13, except MyValue15 is unloaded
 565     @LooselyConsistentValue
 566     static value class MyValue15 {
 567         int foo;
 568 
 569         public MyValue15() {
 570             foo = rI;
 571         }
 572     }
 573 
 574     static class MyValue15Holder {
 575         @Strict
 576         @NullRestricted
 577         MyValue15 v;
 578 
 579         public MyValue15Holder() {
 580             v = new MyValue15();
 581         }
 582     }
 583 
 584     @Test
 585     public void test15(Object holder) {
 586         // Don't use MyValue15Holder in the signature, it might trigger class loading
 587         GetUnresolvedInlineFieldWrongSignature.test15(holder);
 588     }
 589 
 590     @Run(test = "test15")
 591     public void test15_verifier(RunInfo info) {
 592         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 593             test15(null);
 594         } else {
 595             // Make sure klass is resolved
 596             for (int i = 0; i < 10; ++i) {
 597                 test15(new MyValue15Holder());
 598             }
 599         }
 600     }
 601 
 602     // Test case 16:
 603     // aconst_init with type which is not a value class
 604     static class MyValue16 {
 605         int foo;
 606 
 607         public MyValue16() {
 608             foo = rI;
 609         }
 610     }
 611 
 612     static MyValue16 test16_precondition() {
 613         return new MyValue16();
 614     }
 615 
 616     @Test
 617     public Object test16(boolean warmup) {
 618         return GetUnresolvedInlineFieldWrongSignature.test16(warmup);
 619     }
 620 
 621     @Run(test = "test16")
 622     public void test16_verifier(RunInfo info) {
 623         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 624             test16(true);
 625         } else {
 626             // Make sure klass is resolved
 627             for (int i = 0; i < 10; ++i) {
 628                 test16(false);
 629             }
 630         }
 631     }
 632 
 633     // Test case 17:
 634     // Same as test16 but with unloaded type at aconst_init
 635     static class MyValue17 {
 636         int foo;
 637 
 638         public MyValue17() {
 639             foo = rI;
 640         }
 641     }
 642 
 643     @Test
 644     public Object test17(boolean warmup) {
 645         return GetUnresolvedInlineFieldWrongSignature.test17(warmup);
 646     }
 647 
 648     @Run(test = "test17")
 649     public void test17_verifier(RunInfo info) {
 650         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 651             test17(true);
 652         } else {
 653             // Make sure klass is resolved
 654             for (int i = 0; i < 10; ++i) {
 655                 test17(false);
 656             }
 657         }
 658     }
 659 
 660     // Test case 18:
 661     // Same as test7 but with the holder being loaded
 662     @LooselyConsistentValue
 663     static value class MyValue18 {
 664         int foo;
 665 
 666         MyValue18(int n) {
 667             foo = n;
 668         }
 669     }
 670 
 671     static class MyValue18Holder {
 672         @Strict
 673         @NullRestricted
 674         static MyValue18 v = new MyValue18(rI);
 675     }
 676 
 677     @Test
 678     public int test18(int n) {
 679         if (n == 0) {
 680             return 0;
 681         } else {
 682             return MyValue18Holder.v.foo + n;
 683         }
 684     }
 685 
 686     @Run(test = "test18")
 687     public void test18_verifier(RunInfo info) {
 688         // Make sure MyValue18Holder is loaded
 689         MyValue18Holder holder = new MyValue18Holder();
 690         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 691             test18(0);
 692         } else {
 693             Asserts.assertEQ(test18(rI), 2*rI);
 694         }
 695     }
 696 
 697     // Test case 19:
 698     // Same as test18 but uninitialized (null) static value class field
 699     @LooselyConsistentValue
 700     static value class MyValue19 {
 701         int foo;
 702 
 703         MyValue19(int n) {
 704             foo = n;
 705         }
 706     }
 707 
 708     static class MyValue19Holder {
 709         @Strict
 710         @NullRestricted
 711         static MyValue19 v = new MyValue19(0);
 712     }
 713 
 714     @Test
 715     public int test19(int n) {
 716         if (n == 0) {
 717             return 0;
 718         } else {
 719             return MyValue19Holder.v.foo + n;
 720         }
 721     }
 722 
 723     @Run(test = "test19")
 724     public void test19_verifier(RunInfo info) {
 725         // Make sure MyValue19Holder is loaded
 726         MyValue19Holder holder = new MyValue19Holder();
 727         if (info.isWarmUp() && !info.isC2CompilationEnabled()) {
 728             test19(0);
 729         } else {
 730             Asserts.assertEQ(test19(rI), rI);
 731         }
 732     }
 733 
 734     // Test case 20:
 735     // Value class with object field of unloaded type.
 736     static class MyObject20 {
 737         int x = 42;
 738     }
 739 
 740     @LooselyConsistentValue
 741     static value class MyValue20 {
 742         MyObject20 obj;
 743 
 744         MyValue20() {
 745             this.obj = null;
 746         }
 747     }
 748 
 749     @Test
 750     public MyValue20 test20() {
 751         return new MyValue20();
 752     }
 753 
 754     @Run(test = "test20")
 755     public void test20_verifier() {
 756         MyValue20 vt = test20();
 757         Asserts.assertEQ(vt.obj, null);
 758     }
 759 
 760     @LooselyConsistentValue
 761     static value class Test21ClassA {
 762         static Test21ClassB b;
 763         @Strict
 764         @NullRestricted
 765         static Test21ClassC c = new Test21ClassC();
 766     }
 767 
 768     @LooselyConsistentValue
 769     static value class Test21ClassB {
 770         static int x = Test21ClassA.c.x;
 771     }
 772 
 773     @LooselyConsistentValue
 774     static value class Test21ClassC {
 775         int x = 42;
 776     }
 777 
 778     // Test access to static value class field with unloaded type
 779     @Test
 780     public Object test21() {
 781         return new Test21ClassA();
 782     }
 783 
 784     @Run(test = "test21")
 785     public void test21_verifier() {
 786         Object ret = test21();
 787         Asserts.assertEQ(Test21ClassA.b.x, 42);
 788         Asserts.assertEQ(Test21ClassA.c.x, 42);
 789     }
 790 
 791     static boolean test22FailInit = true;
 792 
 793     @LooselyConsistentValue
 794     static value class Test22ClassA {
 795         int x = 0;
 796         @Strict
 797         @NullRestricted
 798         static Test22ClassB b = new Test22ClassB();
 799     }
 800 
 801     @LooselyConsistentValue
 802     static value class Test22ClassB {
 803         int x = 0;
 804         static {
 805             if (test22FailInit) {
 806                 throw new RuntimeException("Init failed");
 807             }
 808         }
 809     }
 810 
 811     // Test that load from static field of uninitialized value class throws an exception
 812     @Test
 813     public Object test22() {
 814         return Test22ClassA.b;
 815     }
 816 
 817     @Run(test = "test22")
 818     public void test22_verifier() {
 819         // Trigger initialization error in Test22ClassB
 820         try {
 821             Test22ClassB b = new Test22ClassB();
 822             throw new RuntimeException("Should have thrown error during initialization");
 823         } catch (ExceptionInInitializerError | NoClassDefFoundError e) {
 824             // Expected
 825         }
 826         try {
 827             test22();
 828             throw new RuntimeException("Should have thrown NoClassDefFoundError");
 829         } catch (NoClassDefFoundError e) {
 830             // Expected
 831         }
 832     }
 833 
 834     static boolean test23FailInit = true;
 835 
 836     @LooselyConsistentValue
 837     static value class Test23ClassA {
 838         int x = 0;
 839         @Strict
 840         @NullRestricted
 841         static Test23ClassB b = new Test23ClassB();
 842     }
 843 
 844     @LooselyConsistentValue
 845     static value class Test23ClassB {
 846         static {
 847             if (test23FailInit) {
 848                 throw new RuntimeException("Init failed");
 849             }
 850         }
 851     }
 852 
 853     // Same as test22 but with empty ClassB
 854     @Test
 855     public Object test23() {
 856         return Test23ClassA.b;
 857     }
 858 
 859     @Run(test = "test23")
 860     public void test23_verifier() {
 861         // Trigger initialization error in Test23ClassB
 862         try {
 863             Test23ClassB b = new Test23ClassB();
 864             throw new RuntimeException("Should have thrown error during initialization");
 865         } catch (ExceptionInInitializerError | NoClassDefFoundError e) {
 866             // Expected
 867         }
 868         try {
 869             test23();
 870             throw new RuntimeException("Should have thrown NoClassDefFoundError");
 871         } catch (NoClassDefFoundError e) {
 872             // Expected
 873         }
 874     }
 875 
 876     static boolean test24FailInit = true;
 877 
 878     @LooselyConsistentValue
 879     static value class Test24ClassA {
 880         @Strict
 881         @NullRestricted
 882         Test24ClassB b = new Test24ClassB();
 883     }
 884 
 885     @LooselyConsistentValue
 886     static value class Test24ClassB {
 887         int x = 0;
 888         static {
 889             if (test24FailInit) {
 890                 throw new RuntimeException("Init failed");
 891             }
 892         }
 893     }
 894 
 895     // Test that access to non-static field of uninitialized value class throws an exception
 896     @Test
 897     public Object test24() {
 898         return (new Test24ClassA()).b.x;
 899     }
 900 
 901     @Run(test = "test24")
 902     public void test24_verifier() {
 903         // Trigger initialization error in Test24ClassB
 904         try {
 905             Test24ClassB b = new Test24ClassB();
 906             throw new RuntimeException("Should have thrown error during initialization");
 907         } catch (ExceptionInInitializerError | NoClassDefFoundError e) {
 908             // Expected
 909         }
 910         try {
 911             test24();
 912             throw new RuntimeException("Should have thrown NoClassDefFoundError");
 913         } catch (NoClassDefFoundError e) {
 914             // Expected
 915         }
 916     }
 917 
 918     static boolean test25FailInit = true;
 919 
 920     @LooselyConsistentValue
 921     static value class Test25ClassA {
 922         @Strict
 923         @NullRestricted
 924         Test25ClassB b = new Test25ClassB();
 925     }
 926 
 927     @LooselyConsistentValue
 928     static value class Test25ClassB {
 929         int x = 24;
 930         static {
 931             if (test25FailInit) {
 932                 throw new RuntimeException("Init failed");
 933             }
 934         }
 935     }
 936 
 937     // Same as test24 but with field access outside of test method
 938     @Test
 939     public Test25ClassB test25() {
 940         return (new Test25ClassA()).b;
 941     }
 942 
 943     @Run(test = "test25")
 944     public void test25_verifier() {
 945         // Trigger initialization error in Test25ClassB
 946         try {
 947             Test25ClassB b = new Test25ClassB();
 948             throw new RuntimeException("Should have thrown error during initialization");
 949         } catch (ExceptionInInitializerError | NoClassDefFoundError e) {
 950             // Expected
 951         }
 952         try {
 953             Test25ClassB res = test25();
 954             Asserts.assertEQ(res.x, 0);
 955             throw new RuntimeException("Should have thrown NoClassDefFoundError");
 956         } catch (NoClassDefFoundError e) {
 957             // Expected
 958         }
 959     }
 960 
 961     static boolean test26FailInit = true;
 962 
 963     @LooselyConsistentValue
 964     static value class Test26ClassA {
 965         @Strict
 966         @NullRestricted
 967         Test26ClassB b = new Test26ClassB();
 968     }
 969 
 970     @LooselyConsistentValue
 971     static value class Test26ClassB {
 972         static {
 973             if (test26FailInit) {
 974                 throw new RuntimeException("Init failed");
 975             }
 976         }
 977     }
 978 
 979     // Same as test25 but with empty ClassB
 980     @Test
 981     public Object test26() {
 982         return (new Test26ClassA()).b;
 983     }
 984 
 985     @Run(test = "test26")
 986     public void test26_verifier() {
 987         // Trigger initialization error in Test26ClassB
 988         try {
 989             Test26ClassB b = new Test26ClassB();
 990             throw new RuntimeException("Should have thrown error during initialization");
 991         } catch (ExceptionInInitializerError | NoClassDefFoundError e) {
 992             // Expected
 993         }
 994         try {
 995             test26();
 996             throw new RuntimeException("Should have thrown NoClassDefFoundError");
 997         } catch (NoClassDefFoundError e) {
 998             // Expected
 999         }
1000     }
1001 
1002     @LooselyConsistentValue
1003     static value class MyValue27 {
1004         int foo = 42;
1005     }
1006 
1007     static class MyValue27Holder {
1008         MyValue27 v;
1009     }
1010 
1011     // Make sure MyValue27Holder is loaded but MyValue27 is not
1012     Class test27Class = MyValue27Holder.class;
1013 
1014     // Test unloaded value class field load from loaded holder
1015     @Test
1016     public static Object test27() {
1017         MyValue27Holder holder = new MyValue27Holder();
1018         return holder.v;
1019     }
1020 
1021     @Run(test = "test27")
1022     public void test27_verifier() {
1023         Asserts.assertEQ(test27(), null);
1024     }
1025 
1026     @LooselyConsistentValue
1027     static value class MyValue28 {
1028         @Strict
1029         @NullRestricted
1030         static MyValue28 field1 = new MyValue28();
1031     }
1032 
1033     // Test null store to null restricted field with unloaded holder
1034     @Test
1035     public static void test28() {
1036         MyValue28.field1 = null;
1037     }
1038 
1039     @Run(test = "test28")
1040     @Warmup(0) // Make sure that MyValue28 is not loaded
1041     public void test28_verifier() {
1042         try {
1043             test28();
1044             throw new RuntimeException("No exception thrown");
1045         } catch (NullPointerException e) {
1046             // Expected
1047         }
1048     }
1049 }