1 /*
2 * Copyright (c) 2024, 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 PreloadCircularityTest
26 * @modules java.base/jdk.internal.vm.annotation
27 * java.base/jdk.internal.value
28 * @library /test/lib
29 * @requires vm.flagless
30 * @enablePreview
31 * @compile PreloadCircularityTest.java
32 * @run main PreloadCircularityTest
33 */
34
35 import java.lang.reflect.Method;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.List;
39
40 import javax.management.relation.RelationServiceNotRegisteredException;
41
42 import jdk.internal.value.ValueClass;
43 import jdk.internal.vm.annotation.LooselyConsistentValue;
44 import jdk.internal.vm.annotation.NullRestricted;
45
46 import jdk.test.lib.Asserts;
47 import jdk.test.lib.Utils;
48 import jdk.test.lib.process.OutputAnalyzer;
49 import jdk.test.lib.process.ProcessTools;
50
51 public class PreloadCircularityTest {
52
53 // Testing preload due to non-static fields
54
55 static value class Class0a {
56 @NullRestricted
57 Class0b vb = new Class0b();
58 }
59
60 static value class Class0b {
61 @NullRestricted
62 Class0c vc = new Class0c();
63 }
64
65 static value class Class0c {
66 int i = 0;
67 }
68
69 void test_0() throws Exception {
70 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class0a");
71 out.shouldHaveExitValue(0);
72 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class0b during loading of class PreloadCircularityTest$Class0a. Cause: field type in LoadableDescriptors attribute");
73 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class0c during loading of class PreloadCircularityTest$Class0b. Cause: field type in LoadableDescriptors attribute");
74 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class0c during loading of class PreloadCircularityTest$Class0b (cause: field type in LoadableDescriptors attribute) succeeded");
75 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class0b during loading of class PreloadCircularityTest$Class0a (cause: field type in LoadableDescriptors attribute) succeeded");
76 out.shouldNotContain("the annotation is ignored");
77 out.shouldNotContain("failed");
78 }
79
80 static value class Class1a {
81 @NullRestricted
82 Class1b vb = new Class1b();
83 }
84
85 static value class Class1b {
86 Class1c vc = new Class1c();
87 }
88
89 static value class Class1c {
90 int i = 0;
91 }
92
93 void test_1() throws Exception {
94 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class1a");
95 out.shouldHaveExitValue(0);
96 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class1b during loading of class PreloadCircularityTest$Class1a. Cause: field type in LoadableDescriptors attribute");
97 out.shouldContain("Preloading of class PreloadCircularityTest$Class1c during loading of class PreloadCircularityTest$Class1b. Cause: field type in LoadableDescriptors attribute");
98 out.shouldContain("Preloading of class PreloadCircularityTest$Class1c during loading of class PreloadCircularityTest$Class1b (cause: field type in LoadableDescriptors attribute) succeeded");
99 out.shouldContain("Preloading of class PreloadCircularityTest$Class1b during loading of class PreloadCircularityTest$Class1a (cause: field type in LoadableDescriptors attribute) succeeded");
100 out.shouldNotContain("the annotation is ignored");
101 out.shouldNotContain("failed");
102 }
103
104 static value class Class2a {
105 @NullRestricted
106 Class2b vb = new Class2b();
107 }
108
109 static value class Class2b {
110 @NullRestricted
111 Class2c vc = new Class2c();
112 }
113
114 static value class Class2c {
115 @NullRestricted
116 Class2b vb = new Class2b();
117 }
118
119 void test_2() throws Exception {
120 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class2a");
121 out.shouldHaveExitValue(0);
122 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class2b during loading of class PreloadCircularityTest$Class2a. Cause: field type in LoadableDescriptors attribute");
123 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class2c during loading of class PreloadCircularityTest$Class2b. Cause: field type in LoadableDescriptors attribute");
124 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class2b during loading of class PreloadCircularityTest$Class2c. Cause: field type in LoadableDescriptors attribute");
125 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class2b during loading of class PreloadCircularityTest$Class2c (cause: field type in LoadableDescriptors attribute) failed : java/lang/ClassCircularityError");
126 out.shouldContain("[warning][class,preload] After preloading of class PreloadCircularityTest$Class2b during loading of class PreloadCircularityTest$Class2c failed,field was annotated with @NullRestricted but class is unknown, the annotation is ignored");
127 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class2c during loading of class PreloadCircularityTest$Class2b (cause: field type in LoadableDescriptors attribute) succeeded");
128 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class2b during loading of class PreloadCircularityTest$Class2a (cause: field type in LoadableDescriptors attribute) succeeded");
129 }
130
131 static value class Class3a {
132 @NullRestricted
133 Class3b vb = new Class3b();
134 }
135
136 static value class Class3b {
137 @NullRestricted
138 Class3c vc = new Class3c();
139 }
140
141 static value class Class3c {
142 Class3b vb = new Class3b();
143 }
144
145 void test_3() throws Exception {
146 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class3a");
147 out.shouldHaveExitValue(0);
148
149 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class3b during loading of class PreloadCircularityTest$Class3a. Cause: field type in LoadableDescriptors attribute");
150 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class3c during loading of class PreloadCircularityTest$Class3b. Cause: field type in LoadableDescriptors attribute");
151 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class3b during loading of class PreloadCircularityTest$Class3c. Cause: field type in LoadableDescriptors attribute");
152 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class3b during loading of class PreloadCircularityTest$Class3c (cause: field type in LoadableDescriptors attribute) failed : java/lang/ClassCircularityError");
153 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class3c during loading of class PreloadCircularityTest$Class3b (cause: field type in LoadableDescriptors attribute) succeeded");
154 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class3b during loading of class PreloadCircularityTest$Class3a (cause: field type in LoadableDescriptors attribute) succeeded");
155 out.shouldNotContain("the annotation is ignored");
156 }
157
158 static value class Class4a {
159 @NullRestricted
160 Class4b vb = new Class4b();
161 }
162
163 static value class Class4b {
164 @NullRestricted
165 Class4a vc = new Class4a();
166 }
167
168 void test_4() throws Exception {
169 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class4a");
170 out.shouldHaveExitValue(0);
171
172 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class4b during loading of class PreloadCircularityTest$Class4a. Cause: field type in LoadableDescriptors attribute");
173 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class4a during loading of class PreloadCircularityTest$Class4b. Cause: field type in LoadableDescriptors attribute");
174 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class4a during loading of class PreloadCircularityTest$Class4b (cause: field type in LoadableDescriptors attribute) failed : java/lang/ClassCircularityError");
175 out.shouldContain("[warning][class,preload] After preloading of class PreloadCircularityTest$Class4a during loading of class PreloadCircularityTest$Class4b failed,field was annotated with @NullRestricted but class is unknown, the annotation is ignored");
176 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class4b during loading of class PreloadCircularityTest$Class4a (cause: field type in LoadableDescriptors attribute) succeeded");
177 }
178
179 static value class Class5a {
180 Class5b vb = new Class5b();
181
182 @NullRestricted
183 Class5c vc = new Class5c();
184 }
185
186 static value class Class5b {
187 @NullRestricted
188 Class5d vd = new Class5d();
189 }
190
191 static value class Class5c {
192 Class5b vb = new Class5b();
193 }
194
195 static value class Class5d {
196 @NullRestricted
197 Class5b vb = new Class5b();
198 }
199
200 void test_5() throws Exception {
201 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class5a");
202 out.shouldHaveExitValue(0);
203 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class5b during loading of class PreloadCircularityTest$Class5a. Cause: field type in LoadableDescriptors attribute");
204 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class5d during loading of class PreloadCircularityTest$Class5b. Cause: field type in LoadableDescriptors attribute");
205 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class5b during loading of class PreloadCircularityTest$Class5d. Cause: field type in LoadableDescriptors attribute");
206 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class5b during loading of class PreloadCircularityTest$Class5d (cause: field type in LoadableDescriptors attribute) failed : java/lang/ClassCircularityError");
207 out.shouldContain("[warning][class,preload] After preloading of class PreloadCircularityTest$Class5b during loading of class PreloadCircularityTest$Class5d failed,field was annotated with @NullRestricted but class is unknown, the annotation is ignored");
208 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class5d during loading of class PreloadCircularityTest$Class5b (cause: field type in LoadableDescriptors attribute) succeeded");
209 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class5b during loading of class PreloadCircularityTest$Class5a (cause: field type in LoadableDescriptors attribute) succeeded");
210 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class5c during loading of class PreloadCircularityTest$Class5a. Cause: field type in LoadableDescriptors attribute");
211 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class5b during loading of class PreloadCircularityTest$Class5c. Cause: field type in LoadableDescriptors attribute");
212 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class5b during loading of class PreloadCircularityTest$Class5c (cause: field type in LoadableDescriptors attribute) succeeded");
213 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class5c during loading of class PreloadCircularityTest$Class5a (cause: field type in LoadableDescriptors attribute) succeeded");
214 }
215
216 static value class Class6a {
217 @NullRestricted
218 Class6b vb = new Class6b();
219 }
220
221 static value class Class6b {
222 Class6c vc = new Class6c();
223
224 @NullRestricted
225 Class6d vd = new Class6d();
226 }
227
228 static value class Class6c {
229 int i = 0;
230 }
231
232 static value class Class6d {
233 @NullRestricted
234 Class6b vb = new Class6b();
235 }
236
237 void test_6() throws Exception {
238 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class6a");
239 out.shouldHaveExitValue(0);
240
241 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class6b during loading of class PreloadCircularityTest$Class6a. Cause: field type in LoadableDescriptors attribute");
242 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class6c during loading of class PreloadCircularityTest$Class6b. Cause: field type in LoadableDescriptors attribute");
243 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class6c during loading of class PreloadCircularityTest$Class6b (cause: field type in LoadableDescriptors attribute) succeeded");
244 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class6d during loading of class PreloadCircularityTest$Class6b. Cause: field type in LoadableDescriptors attribute");
245 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class6b during loading of class PreloadCircularityTest$Class6d. Cause: field type in LoadableDescriptors attribute");
246 out.shouldContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class6b during loading of class PreloadCircularityTest$Class6d (cause: field type in LoadableDescriptors attribute) failed : java/lang/ClassCircularityError");
247 out.shouldContain("[warning][class,preload] After preloading of class PreloadCircularityTest$Class6b during loading of class PreloadCircularityTest$Class6d failed,field was annotated with @NullRestricted but class is unknown, the annotation is ignored");
248 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class6d during loading of class PreloadCircularityTest$Class6b (cause: field type in LoadableDescriptors attribute) succeeded");
249 out.shouldContain("[info ][class,preload] Preloading of class PreloadCircularityTest$Class6b during loading of class PreloadCircularityTest$Class6a (cause: field type in LoadableDescriptors attribute) succeeded");
250 }
251
252 static value class Class7a {
253 @NullRestricted
254 Class7a va = new Class7a();
255 }
256
257 void test_7() throws Exception {
258 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class7a");
259 out.shouldHaveExitValue(0);
260 out.shouldNotContain("[warning][class,preload] During loading of class PreloadCircularityTest$Class7a, class PreloadCircularityTest$Class7a is unknown, but a field of this type was annotated with @NullRestricted, the annotation is ignored");
261 }
262
263 static value class Class8a {
264 Class8a va = new Class8a();
265 }
266
267 void test_8() throws Exception {
268 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class8a");
269 out.shouldHaveExitValue(0);
270 out.shouldNotContain("[info][class,preload] Preloading of class PreloadCircularityTest$Class8a during loading of class PreloadCircularityTest$Class8a. Cause: field type in LoadableDescriptors attribute");
271 }
272
273 static value class Class9a {
274 @NullRestricted
275 Class9b vb = new Class9b();
276 }
277
278 static class Class9b { }
279
280 void test_9() throws Exception {
281 OutputAnalyzer out = tryLoadingClass("PreloadCircularityTest$Class9a");
282 out.shouldHaveExitValue(0);
283 out.shouldContain("[warning][class,preload] During loading of class PreloadCircularityTest$Class9a, class PreloadCircularityTest$Class9b is unknown, but a field of this type was annotated with @NullRestricted, the annotation is ignored");
284 }
285
286 public static class TestHelper {
287 public static void main(String[] args) {
288 try {
289 Class c = Class.forName(args[0]);
290 } catch (Throwable ex) {
291 ex.printStackTrace();
292 System.exit(1);
293 }
294 System.exit(0);
295 }
296 }
297
298 static OutputAnalyzer tryLoadingClass(String className) throws Exception {
299 ProcessBuilder pb = exec("PreloadCircularityTest$TestHelper", className);
300 OutputAnalyzer out = new OutputAnalyzer(pb.start());
301 System.out.println(out.getOutput());
302 return out;
303 }
304
305 static ProcessBuilder exec(String... args) throws Exception {
306 List<String> argsList = new ArrayList<>();
307 Collections.addAll(argsList, "--enable-preview");
308 Collections.addAll(argsList, "-Dtest.class.path=" + System.getProperty("test.class.path", "."));
309 Collections.addAll(argsList, "-Xlog:class+preload=info");
310 Collections.addAll(argsList, args);
311 return ProcessTools.createTestJavaProcessBuilder(argsList);
312 }
313
314 public static void main(String[] args) throws Exception {
315 System.out.println("Creating tests");
316 PreloadCircularityTest tests = new PreloadCircularityTest();
317 Class c = tests.getClass();
318 System.out.println("Iterating over test methods");
319 boolean hasFailedTest = false;
320 StringBuilder sb = new StringBuilder("Following tests have failed: ");
321 for (Method m : c.getDeclaredMethods()) {
322 if (m.getName().startsWith("test_")) {
323 boolean failed = false;
324 try {
325 System.out.println("Running " + m.getName());
326 m.invoke(tests);
327 } catch (Throwable t) {
328 t.printStackTrace();
329 failed = true;
330 }
331 System.out.println("Test " + m.getName() + " : " + (failed ? "FAILED" : "PASSED"));
332 hasFailedTest = failed ? true : hasFailedTest;
333 if (failed) sb.append(m.getName()).append(", ");
334 }
335 }
336 if (hasFailedTest) {
337 throw new RuntimeException(sb.toString());
338 }
339 }
340 }