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 }