1 /*
2 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
3 * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 /*
26 * @test
27 * @bug 8333791
28 * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
29 * @requires vm.gc.Parallel
30 * @requires vm.compiler2.enabled
31 * @summary Check stable field folding and barriers
32 * @modules java.base/jdk.internal.vm.annotation
33 * @library /test/lib /
34 * @run driver compiler.c2.irTests.stable.StableRefArrayTest
35 */
36
37 package compiler.c2.irTests.stable;
38
39 import compiler.lib.ir_framework.*;
40 import jdk.test.lib.Asserts;
41
42 import jdk.internal.vm.annotation.Stable;
43
44 public class StableRefArrayTest {
45
46 public static void main(String[] args) {
47 TestFramework tf = new TestFramework();
48 tf.addTestClassesToBootClassPath();
49 tf.addFlags(
50 "-XX:+UnlockExperimentalVMOptions",
51 "-XX:CompileThreshold=100",
52 "-XX:-TieredCompilation",
53 "-XX:+UseParallelGC"
54 );
55 tf.start();
56 }
57
58 static final Integer[] EMPTY_INTEGER = new Integer[] { null };
59 static final Integer[] FULL_INTEGER = new Integer[] { 42 };
60
61 static class Carrier {
62 @Stable
63 Integer[] field;
64
65 @ForceInline
66 public Carrier(int initLevel) {
67 switch (initLevel) {
68 case 0:
69 // Do nothing.
70 break;
71 case 1:
72 field = EMPTY_INTEGER;
73 break;
74 case 2:
75 field = FULL_INTEGER;
76 break;
77 default:
78 throw new IllegalStateException("Unknown level");
79 }
80 }
81
82 @ForceInline
83 public void initEmpty() {
84 field = EMPTY_INTEGER;
85 }
86
87 @ForceInline
88 public void initFull() {
89 field = FULL_INTEGER;
90 }
91
92 }
93
94 static final Carrier BLANK_CARRIER = new Carrier(0);
95 static final Carrier INIT_EMPTY_CARRIER = new Carrier(1);
96 static final Carrier INIT_FULL_CARRIER = new Carrier(2);
97
98 @Test
99 @IR(counts = { IRNode.LOAD, ">0" })
100 @IR(failOn = { IRNode.MEMBAR })
101 static int testNoFold() {
102 // Access should not be folded.
103 // No barriers expected for plain fields.
104 Integer[] is = BLANK_CARRIER.field;
105 if (is != null) {
106 Integer i = is[0];
107 if (i != null) {
108 return i;
109 }
110 }
111 return 0;
112 }
113
114 @Test
115 @IR(counts = { IRNode.LOAD, ">0" })
116 @IR(applyIf = {"enable-valhalla", "false"}, failOn = { IRNode.MEMBAR })
117 // We have barriers with valhalla from the atomic expansion of the LoadFlatNode
118 // Indeed, since the array element is not initialized, it is not known to be constant yet,
119 // and so, the LoadFlat cannot be expanded non-atomically. We need barriers to synchronize
120 // the LoadFlat and potential updates to field of the flatten array element.
121 @IR(applyIfAnd = {"UseArrayFlattening", "true", "enable-valhalla", "true"}, counts = { IRNode.MEMBAR, "> 0" })
122 static int testPartialFold() {
123 // Access should not be folded.
124 Integer[] is = INIT_EMPTY_CARRIER.field;
125 if (is != null) {
126 Integer i = is[0];
127 if (i != null) {
128 return i;
129 }
130 }
131 return 0;
132 }
133
134
135 @Test
136 @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR })
137 static int testFold() {
138 // Access should be completely folded.
139 Integer[] is = INIT_FULL_CARRIER.field;
140 if (is != null) {
141 Integer i = is[0];
142 if (i != null) {
143 return i;
144 }
145 }
146 return 0;
147 }
148
149 @Test
150 @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
151 static Carrier testConstructorBlankInit() {
152 // Only the header barrier.
153 return new Carrier(0);
154 }
155
156 @Test
157 @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
158 static Carrier testConstructorEmptyInit() {
159 // Only the header barrier.
160 return new Carrier(1);
161 }
162
163 @Test
164 @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
165 static Carrier testConstructorFullInit() {
166 // Only the header barrier.
167 return new Carrier(2);
168 }
169
170 @Test
171 @IR(failOn = { IRNode.MEMBAR })
172 static void testMethodEmptyInit() {
173 // Reference inits do not have membars.
174 INIT_EMPTY_CARRIER.initEmpty();
175 }
176
177 @Test
178 @IR(failOn = { IRNode.MEMBAR })
179 static void testMethodFullInit() {
180 // Reference inits do not have membars.
181 INIT_FULL_CARRIER.initFull();
182 }
183
184 }