1 /*
2 * Copyright (c) 2023, 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 package runtime.valhalla.inlinetypes;
25
26 import jdk.test.lib.Asserts;
27 import java.lang.management.ManagementFactory;
28 import java.lang.management.RuntimeMXBean;
29 import java.lang.reflect.Method;
30 import java.lang.reflect.Field;
31 import java.util.List;
32 import jdk.internal.misc.Unsafe;
33 import jdk.internal.vm.annotation.NullRestricted;
34 import jdk.internal.vm.annotation.LooselyConsistentValue;
35 import jdk.test.whitebox.WhiteBox;
36
37 /*
38 * @test
39 * @summary Test of NullRestricted, Strict and LooselyConsistentValue annotations
40 * @modules java.base/jdk.internal.misc
41 * java.base/jdk.internal.vm.annotation
42 * @library /test/lib
43 * @enablePreview
44 * @build jdk.test.whitebox.WhiteBox
45 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
46 * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI runtime.valhalla.inlinetypes.AnnotationsTests
47 */
48
49 public class AnnotationsTests {
50 private static final WhiteBox WHITEBOX = WhiteBox.getWhiteBox();
51 private static final boolean UseNullableAtomicValueFlattening = WHITEBOX.getBooleanVMFlag("UseNullableAtomicValueFlattening");
52
53 private static final Unsafe UNSAFE = Unsafe.getUnsafe();
54
55 public static void main(String[] args) {
56 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
57 AnnotationsTests tests = new AnnotationsTests();
58 Class c = tests.getClass();
59 for (Method m : c.getDeclaredMethods()) {
60 if (m.getName().startsWith("test_")) {
61 try {
62 System.out.println("Running " + m.getName());
63 m.invoke(tests);
64 } catch (Throwable t) {
65 t.printStackTrace();
66 throw new RuntimeException(t);
67 }
68 }
69 }
70 }
71
72 // Test invalid usage of @LooselyConsistentValue on an identity class
73 @LooselyConsistentValue
74 static class BadClass4 {
75
76 }
77
78 void test_4() {
79 Throwable exception = null;
80 try {
81 BadClass4 tc = new BadClass4();
82 } catch (ClassFormatError e) {
83 exception = e;
84 System.out.println("Received " + e);
85 }
86 Asserts.assertNotNull(exception, "Failed to detect illegal use of @LooselyConsistentValue");
87 }
88
89 // Test field flattening of @NullRestricted annotated fields
90
91 @LooselyConsistentValue
92 static value class ValueClass5 {
93 int i = 0;
94 }
95
96 static class GoodClass5 {
97 ValueClass5 f0 = new ValueClass5();
98
99 @NullRestricted
100 ValueClass5 f1;
101
102 GoodClass5() {
103 f1 = new ValueClass5();
104 super();
105 }
106 }
107
108 void test_5() {
109 Throwable exception = null;
110 try {
111 GoodClass5 vc = new GoodClass5();
112 Field f0 = vc.getClass().getDeclaredField("f0");
113 if (UseNullableAtomicValueFlattening) {
114 Asserts.assertTrue(UNSAFE.isFlatField(f0), "Flat field expected, but field is not flat");
115 } else {
116 Asserts.assertFalse(UNSAFE.isFlatField(f0), "Unexpected flat field");
117 }
118 Field f1 = vc.getClass().getDeclaredField("f1");
119 Asserts.assertTrue(UNSAFE.isFlatField(f1), "Flat field expected, but field is not flat");
120 } catch (IncompatibleClassChangeError e) {
121 exception = e;
122 System.out.println("Received " + e);
123 } catch(NoSuchFieldException e) {
124 Asserts.fail("Test error");
125 }
126 Asserts.assertNull(exception, "Unexpected exception: " + exception);
127 }
128
129
130 // Test detection/handling of circularity
131
132 static value class ValueClass6a {
133 @NullRestricted
134 ValueClass6b val = new ValueClass6b();
135 }
136
137 static value class ValueClass6b {
138 @NullRestricted
139 ValueClass6a val = new ValueClass6a();
140 }
141
142 static class BadClass6 {
143 @NullRestricted
144 ValueClass6a val;
145
146 BadClass6() {
147 val = new ValueClass6a();
148 super();
149 }
150 }
151
152 void test_6() {
153 Throwable exception = null;
154 try {
155 BadClass6 bc = new BadClass6();
156 } catch (StackOverflowError e) {
157 exception = e;
158 System.out.println("Received " + e);
159 }
160 Asserts.assertNotNull(exception, "Failed to trigger infinite recursion");
161 }
162
163 // Test null restricted static field
164 static value class ValueClass7 {
165 int i = 0;
166 }
167
168 static class GoodClass7 {
169 @NullRestricted
170 static ValueClass7 sval = new ValueClass7();
171 }
172
173 void test_7() {
174 Throwable exception = null;
175 try {
176 ValueClass7 val = GoodClass7.sval;
177 Asserts.assertNotNull(val, "Unexpected null value");
178 } catch (Throwable e) {
179 exception = e;
180 System.out.println("Received " + e);
181 }
182 Asserts.assertNull(exception, "Unexpected exception: " + exception);
183 }
184
185 // Test circularity on static fields
186 static value class ValueClass8 {
187 @NullRestricted
188 static ValueClass8 sval = new ValueClass8();
189 }
190
191 void test_8() {
192 Throwable exception = null;
193 try {
194 ValueClass8 val = ValueClass8.sval;
195 Asserts.assertNotNull(val, "Unexpected null value");
196 } catch (Throwable e) {
197 exception = e;
198 System.out.println("Received " + e);
199 }
200 Asserts.assertNull(exception, "Unexpected exception: " + exception);
201 }
202
203 // Test that writing null to a @NullRestricted non-static field throws an exception
204 static value class ValueClass9 {
205 int i = 0;
206 }
207
208 static class GoodClass9 {
209 @NullRestricted
210 ValueClass9 val;
211
212 GoodClass9() {
213 val = new ValueClass9();
214 super();
215 }
216 }
217
218 void test_9() {
219 Throwable exception = null;
220 try {
221 GoodClass9 gc = new GoodClass9();
222 gc.val = null;
223 } catch(NullPointerException e) {
224 exception = e;
225 System.out.println("Received " + e);
226 }
227 Asserts.assertNotNull(exception, "Expected NullPointerException not received");
228 }
229
230 // Test that writing null to a @NullRestricted static field throws an exception
231 static value class ValueClass10 {
232 @NullRestricted
233 static ValueClass10 sval = new ValueClass10();
234 }
235
236 void test_10() {
237 Throwable exception = null;
238 try {
239 ValueClass10.sval = null;
240 } catch(NullPointerException e) {
241 exception = e;
242 System.out.println("Received " + e);
243 }
244 Asserts.assertNotNull(exception, "Expected NullPointerException not received");
245 }
246
247 // Test illegal use of @NullRestricted on a primitive field
248 static class BadClass12 {
249 @NullRestricted
250 int i;
251
252 BadClass12() {
253 i = 0;
254 super();
255 }
256 }
257 void test_12() {
258 Throwable exception = null;
259 try {
260 BadClass12 val = new BadClass12();
261 System.out.println(val);
262 } catch(ClassFormatError e) {
263 exception = e;
264 System.out.println("Received " + e);
265 }
266 Asserts.assertNotNull(exception, "Expected ClassFormatError not received");
267 }
268
269 // Test illegal use of @NullRestricted on an array field
270 static class BadClass13 {
271 @NullRestricted
272 int[] intArray;
273
274 BadClass13() {
275 intArray = new int[1];
276 super();
277 }
278 }
279 void test_13() {
280 Throwable exception = null;
281 try {
282 BadClass13 val = new BadClass13();
283 System.out.println(val);
284 } catch(ClassFormatError e) {
285 exception = e;
286 System.out.println("Received " + e);
287 }
288 Asserts.assertNotNull(exception, "Expected ClassFormatError not received");
289 }
290
291 }
292