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