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 import jdk.internal.vm.annotation.LooselyConsistentValue;
25 import jdk.internal.vm.annotation.NullRestricted;
26
27 import jdk.test.lib.Asserts;
28
29 public class NullableFlatFieldApp {
30
31 @LooselyConsistentValue
32 static value class Value0 {
33 long l;
34 int i;
35 short s;
36 byte b;
37
38 Value0() {
39 l = 0;
40 i = 0;
41 s = 0;
42 b = 0;
43 }
44
45 Value0(long l0, int i0, short s0, byte b0) {
46 l = l0;
47 i = i0;
48 s = s0;
49 b = b0;
50 }
51 }
52
53 static class Container0 {
54 Value0 val;
55 long l;
56 int i;
57 }
58
59 // Container0 had a external null marker located just between two Java fields,
60 // and test0 checks that updating the null marker doesn't corrupt
61 // the surrounding fields and vice-versa.
62 static void test0() {
63 Container0 c = new Container0();
64 Asserts.assertNull(c.val);
65 Asserts.assertEquals(c.l, 0L);
66 Asserts.assertEquals(c.i, 0);
67 c.l = -1L;
68 c.i = -1;
69 Asserts.assertNull(c.val);
70 Value0 v = new Value0(-1L, -1, (short)-1, (byte)-1);
71 c.val = v;
72 Asserts.assertEquals(c.l, -1L);
73 Asserts.assertEquals(c.i, -1);
74 Value0 vr = c.val;
75 Asserts.assertEquals(vr.l, -1L);
76 Asserts.assertEquals(vr.i, -1);
77 Asserts.assertEquals(vr.s, (short)-1);
78 Asserts.assertEquals(vr.b, (byte)-1);
79 c.val = null;
80 Asserts.assertEquals(c.l, -1L);
81 Asserts.assertEquals(c.i, -1);
82 }
83
84 @LooselyConsistentValue
85 static value class Value1a {
86 long l;
87 short s;
88 byte b;
89
90 Value1a() {
91 l = 0;
92 s = 0;
93 b = 0;
94 }
95
96 Value1a(long l0, short s0, byte b0) {
97 l = l0;
98 s = s0;
99 b = b0;
100 }
101 }
102
103 @LooselyConsistentValue
104 static value class Value1b {
105 @NullRestricted
106 Value1a vala;
107 long l;
108 int i;
109
110 Value1b() {
111 vala = new Value1a();
112 l = 1L;
113 i = 1;
114 }
115
116 Value1b(Value1a v0, long l0, int i0) {
117 vala = v0;
118 l = l0;
119 i = i0;
120 }
121 }
122
123 static class Container1 {
124 Value1b valb;
125 }
126
127 // Container1 has a nullable flat field with an internal null marker,
128 // test1 checks that updating the null marker doesn't corrupt the
129 // flat field's values
130 static void test1() {
131 Container1 c = new Container1();
132 Asserts.assertNull(c.valb);
133 Value1a va = new Value1a(-1L, (short)-1, (byte)-1);
134 Asserts.assertEquals(va.l, -1L);
135 Asserts.assertEquals(va.s, (short)-1);
136 Asserts.assertEquals(va.b, (byte)-1);
137 Value1b vb = new Value1b(va, -1L, -1);
138 Asserts.assertNotNull(vb.vala);
139 Asserts.assertEquals(vb.vala.l, -1L);
140 Asserts.assertEquals(vb.vala.s, (short)-1);
141 Asserts.assertEquals(vb.vala.b, (byte)-1);
142 c.valb = vb;
143 Asserts.assertNotNull(c.valb);
144 Asserts.assertEquals(c.valb, vb);
145 Asserts.assertEquals(c.valb.vala, va);
146 Asserts.assertEquals(c.valb.l, -1L);
147 Asserts.assertEquals(c.valb.i, -1);
148 c.valb = null;
149 Asserts.assertNull(c.valb);
150 }
151
152 @LooselyConsistentValue
153 static value class Value2a {
154 long l;
155 int i;
156 byte b;
157 Value2a() {
158 l = 0;
159 i = 0;
160 b = 0;
161 }
162 Value2a(long l0, int i0, byte b0) {
163 l = l0;
164 i = i0;
165 b = b0;
166 }
167 }
168
169 @LooselyConsistentValue
170 static value class Value2b {
171 long l;
172 Value2b() {
173 l = 0;
174 }
175 Value2b(long l0) {
176 l = l0;
177 }
178 }
179
180 static class Container2 {
181 Value2a vala;
182 Value2b valb0;
183 Value2b valb1;
184 int i;
185 }
186
187 // Container2 has 3 contiguous null markers,
188 // test2 checks that updating a null marker doesn't affect the other markers
189 public static void test2() {
190 Container2 c = new Container2();
191 Asserts.assertNull(c.vala);
192 Asserts.assertNull(c.valb0);
193 Asserts.assertNull(c.valb1);
194 Value2a va = new Value2a(-1L, -1, (byte)-1);
195 c.vala = va;
196 Asserts.assertNotNull(c.vala);
197 Asserts.assertNull(c.valb0);
198 Asserts.assertNull(c.valb1);
199 c.vala = null;
200 Asserts.assertNull(c.vala);
201 Asserts.assertNull(c.valb0);
202 Asserts.assertNull(c.valb1);
203 Value2b vb = new Value2b(-1L);
204 c.valb0 = vb;
205 Asserts.assertNull(c.vala);
206 Asserts.assertNotNull(c.valb0);
207 Asserts.assertNull(c.valb1);
208 c.valb0 = null;
209 Asserts.assertNull(c.vala);
210 Asserts.assertNull(c.valb0);
211 Asserts.assertNull(c.valb1);
212 c.valb1 = vb;
213 Asserts.assertNull(c.vala);
214 Asserts.assertNull(c.valb0);
215 Asserts.assertNotNull(c.valb1);
216 c.valb1 = null;
217 Asserts.assertNull(c.vala);
218 Asserts.assertNull(c.valb0);
219 Asserts.assertNull(c.valb1);
220 c.vala = va;
221 c.valb0 = vb;
222 c.valb1 = vb;
223 Asserts.assertNotNull(c.vala);
224 Asserts.assertNotNull(c.valb0);
225 Asserts.assertNotNull(c.valb1);
226 c.vala = null;
227 Asserts.assertNull(c.vala);
228 Asserts.assertNotNull(c.valb0);
229 Asserts.assertNotNull(c.valb1);
230 c.vala = va;
231 Asserts.assertNotNull(c.vala);
232 Asserts.assertNotNull(c.valb0);
233 Asserts.assertNotNull(c.valb1);
234 c.valb0 = null;
235 Asserts.assertNotNull(c.vala);
236 Asserts.assertNull(c.valb0);
237 Asserts.assertNotNull(c.valb1);
238 c.valb0 = vb;
239 Asserts.assertNotNull(c.vala);
240 Asserts.assertNotNull(c.valb0);
241 Asserts.assertNotNull(c.valb1);
242 c.valb1 = null;
243 Asserts.assertNotNull(c.vala);
244 Asserts.assertNotNull(c.valb0);
245 Asserts.assertNull(c.valb1);
246 c.valb1 = vb;
247 Asserts.assertNotNull(c.vala);
248 Asserts.assertNotNull(c.valb0);
249 Asserts.assertNotNull(c.valb1);
250 }
251
252 @LooselyConsistentValue
253 static value class Value3 {
254 int i = 0;
255 }
256
257 static class Container3 {
258 Value3 val;
259 }
260
261 static Container3 getNullContainer3() {
262 return null;
263 }
264
265 public static void test3() {
266 NullPointerException npe = null;
267 Container3 c = getNullContainer3();
268 try {
269 Value3 v = c.val;
270 } catch(NullPointerException e) {
271 npe = e;
272 }
273 Asserts.assertNotNull(npe);
274 }
275
276 public static void main(String[] args) {
277 // All tests are run twice to exercise both the unresolved bytecodes and the rewritten ones
278 for (int i = 0; i < 2; i++) {
279 System.out.println("Pass " + i);
280 test0();
281 test1();
282 test2();
283 test3();
284 }
285 }
286 }