1 /*
  2  * Copyright (c) 2026, 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 /*
 25  * @test
 26  * @bug 8375548
 27  * @enablePreview
 28  * @library / /test/lib
 29  * @summary Testing that compiler replay correctly loads sub classes of ObjArrayKlass.
 30  * @requires vm.flagless & vm.flightRecorder != true & vm.compMode != "Xint" & vm.compMode != "Xcomp" &
 31  *           vm.debug == true & vm.compiler2.enabled
 32  * @modules java.base/jdk.internal.misc
 33  *          java.base/jdk.internal.value
 34  *          java.base/jdk.internal.vm.annotation
 35  * @build jdk.test.whitebox.WhiteBox
 36  * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
 37  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+TieredCompilation
 38  *                   compiler.ciReplay.TestValueClassArrays
 39  */
 40 
 41 package compiler.ciReplay;
 42 
 43 import java.util.Arrays;
 44 import java.util.Collections;
 45 import java.util.List;
 46 import java.util.regex.Matcher;
 47 import java.util.regex.Pattern;
 48 
 49 import jdk.internal.value.ValueClass;
 50 import jdk.test.lib.Asserts;
 51 
 52 public class TestValueClassArrays extends DumpReplayBase {
 53     private static final String LOG_FILE = "hotspot.log";
 54     private static final String ERROR_FILE = "error.log";
 55     private final PrintIdeal printIdeal;
 56     private final String[] defaultReplayRunFlags;
 57 
 58     public static void main(String[] args) {
 59         new TestValueClassArrays().runTest("-XX:CompileCommand=dontinline,*::*",
 60                                            "--enable-preview",
 61                                            "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED",
 62                                            "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
 63                                            TIERED_DISABLED_VM_OPTION);
 64     }
 65 
 66     private TestValueClassArrays() {
 67         printIdeal = new PrintIdeal(LOG_FILE);
 68         defaultReplayRunFlags = defaultReplayRunFlags();
 69     }
 70 
 71 
 72     private String[] defaultReplayRunFlags() {
 73         List<String> vmFlags = printIdeal.vmFlags();
 74         Collections.addAll(vmFlags,
 75                            "-XX:+ReplayIgnoreInitErrors",
 76                            "-XX:CompileCommand=dontinline,*::*",
 77                            "--enable-preview",
 78                            "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED",
 79                            "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
 80                            "-XX:ErrorFile=" + ERROR_FILE,
 81                            TIERED_DISABLED_VM_OPTION
 82         );
 83         return vmFlags.toArray(new String[0]);
 84     }
 85 
 86     @Override
 87     public void testAction() {
 88         testArrayAccessSpeculation();
 89         testNoProfilingNoSpeculation();
 90         testInvalidArrayProperty();
 91         remove(LOG_FILE);
 92         remove(ERROR_FILE);
 93     }
 94 
 95     /**
 96      * Check that we emit traps for speculation on array stores and loads as captured in the profiling.
 97      */
 98     private void testArrayAccessSpeculation() {
 99         positiveTest(defaultReplayRunFlags);
100         printIdeal.parse();
101         int countClassCheck = printIdeal.count("class_check");
102         Asserts.assertEQ(countClassCheck, 8, "not found all class checks for speculation on array accesses");
103     }
104 
105     /**
106      * Check that we do not emit traps for speculation on array stores and loads since we disabled array profiling.
107      */
108     private void testNoProfilingNoSpeculation() {
109         String[] noProfilingFlags = Arrays.copyOf(defaultReplayRunFlags, defaultReplayRunFlags.length + 1);
110         noProfilingFlags[defaultReplayRunFlags.length] = "-XX:-UseArrayLoadStoreProfile";
111         positiveTest(noProfilingFlags);
112         printIdeal.parse();
113         String empty = printIdeal.find("class_check");
114         Asserts.assertTrue(empty.isEmpty(), "should not find UCTs for speculation without array profiling");
115     }
116 
117     /**
118      * Replace the "array property" in the "ciMethodData" with an invalid value -1 to make compiler replay fail
119      * with an assertion.
120      */
121     private void testInvalidArrayProperty() {
122         invalidateCiMethodDataInReplayFile();
123         negativeTest(defaultReplayRunFlags);
124         ErrorFile errorFile = new ErrorFile(ERROR_FILE);
125         Asserts.assertTrue(errorFile.find("guarantee(false) failed: invalid array_properties: -1, fall back to DEFAULT"));
126     }
127 
128     private void invalidateCiMethodDataInReplayFile() {
129         ReplayFile replayFile = new ReplayFile(getReplayFileName());
130         String ciMethodData = replayFile.findLineStartingWith(
131                 "ciMethodData compiler/ciReplay/TestValueClassArrays$Test test");
132         Pattern pattern = Pattern.compile("(\\[Lcompiler/ciReplay/TestValueClassArrays\\$Test\\$A;) (\\d+)");
133         Matcher matcher = pattern.matcher(ciMethodData);
134         Asserts.assertTrue(matcher.find(), "must find array_property");
135         String replacement = matcher.group(1) + " -1";
136         String newCiMethodData = matcher.replaceFirst(Matcher.quoteReplacement(replacement));
137         replayFile.replaceLineStartingWith(ciMethodData, newCiMethodData);
138     }
139 
140     @Override
141     public String getTestClass() {
142         return Test.class.getName();
143     }
144 
145 
146     private static class Test {
147         static A[] oArrDefault = new A[2];
148         static A[] oArrNullableAtomicArray = (A[]) ValueClass.newNullableAtomicArray(A.class, 2);
149         static A[] oArrNullRestrictedAtomicArray = (A[]) ValueClass.newNullRestrictedAtomicArray(A.class, 2, new A(1));
150         static A[] oArrNullRestrictedNonAtomicArray = (A[]) ValueClass.newNullRestrictedNonAtomicArray(A.class, 2, new A(2));
151 
152         static A o1, o2, o3, o4;
153         static A a = new A(10);
154 
155         public static void main(String[] args) {
156             oArrDefault[0] = new A(3);
157             oArrNullableAtomicArray[0] = new A(4);
158             oArrNullRestrictedAtomicArray[0] = new A(5);
159             oArrNullRestrictedNonAtomicArray[0] = new A(6);
160             for (int i = 0; i < 10000; i++) {
161                 test();
162             }
163         }
164 
165         static void test() {
166             o1 = oArrDefault[0];
167             oArrDefault[1] = a;
168             o2 = oArrNullableAtomicArray[0];
169             oArrNullableAtomicArray[1] = a;
170             o3 = oArrNullRestrictedAtomicArray[0];
171             oArrNullRestrictedAtomicArray[1] = a;
172             o4 = oArrNullRestrictedNonAtomicArray[0];
173             oArrNullRestrictedNonAtomicArray[1] = a;
174         }
175 
176         static value class A {
177             int x;
178             public A(int x) {
179                 this.x = x;
180             }
181         }
182     }
183 }