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 }