1 /*
  2  * Copyright (c) 2024, 2025, 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 /*
 26  * @test
 27  * @summary "AOT" aliases for traditional CDS command-line options
 28  * @requires vm.cds
 29  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes
 30  * @build Hello
 31  * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar hello.jar Hello
 32  * @run driver AOTFlags
 33  */
 34 
 35 import jdk.test.lib.cds.CDSTestUtils;
 36 import jdk.test.lib.helpers.ClassFileInstaller;
 37 import jdk.test.lib.process.OutputAnalyzer;
 38 import jdk.test.lib.process.ProcessTools;
 39 
 40 public class AOTFlags {
 41     static String appJar = ClassFileInstaller.getJarPath("hello.jar");
 42     static String aotConfigFile = "hello.aotconfig";
 43     static String aotCacheFile = "hello.aot";
 44     static String helloClass = "Hello";
 45 
 46     public static void main(String[] args) throws Exception {
 47         positiveTests();
 48         negativeTests();
 49     }
 50 
 51     static void positiveTests() throws Exception {
 52         String hasTrainingDataPattern = "MethodTrainingData *= *[1-9]";
 53         String noTrainingDataPattern = "MethodTrainingData *= *0";
 54         String hasCachedCodePattern = "Shared file region .cc. .: *[1-9]";
 55         String noCachedCodePattern = "Shared file region .cc. .: *0";
 56         String hasMappedCachedCodePattern = "Mapped [0-9]+ bytes at address 0x[0-9a-f]+ from AOT Code Cache";
 57 
 58         //----------------------------------------------------------------------
 59         printTestCase("Training Run");
 60         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
 61             "-XX:AOTMode=record",
 62             "-XX:AOTConfiguration=" + aotConfigFile,
 63             "-Xlog:cds=debug",
 64             "-cp", appJar, helloClass);
 65 
 66         OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "train");
 67         out.shouldContain("Hello World");
 68         out.shouldContain("AOTConfiguration recorded: " + aotConfigFile);
 69         out.shouldMatch(hasTrainingDataPattern);
 70         out.shouldMatch(noCachedCodePattern);
 71         out.shouldHaveExitValue(0);
 72 
 73         //----------------------------------------------------------------------
 74         printTestCase("Assembly Phase (AOTClassLinking unspecified -> should be enabled by default)");
 75         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
 76             "-XX:AOTMode=create",
 77             "-XX:AOTConfiguration=" + aotConfigFile,
 78             "-XX:AOTCache=" + aotCacheFile,
 79             "-Xlog:cds",
 80             "-cp", appJar);
 81         out = CDSTestUtils.executeAndLog(pb, "asm");
 82         out.shouldContain("Dumping shared data to file:");
 83         out.shouldMatch("cds.*hello[.]aot");
 84         out.shouldMatch(hasTrainingDataPattern);
 85         out.shouldMatch(hasCachedCodePattern);
 86         out.shouldHaveExitValue(0);
 87 
 88         //----------------------------------------------------------------------
 89         printTestCase("Production Run with AOTCache");
 90         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
 91             "-XX:AOTCache=" + aotCacheFile,
 92             "-Xlog:cds",
 93             "-Xlog:scc*",
 94             "-cp", appJar, helloClass);
 95         out = CDSTestUtils.executeAndLog(pb, "prod");
 96         out.shouldContain("Using AOT-linked classes: true (static archive: has aot-linked classes)");
 97         out.shouldContain("Opened AOT cache hello.aot.");
 98         out.shouldContain("Hello World");
 99         out.shouldMatch(hasMappedCachedCodePattern);
100         out.shouldHaveExitValue(0);
101 
102         //----------------------------------------------------------------------
103         printTestCase("AOTMode=off");
104         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
105             "-XX:AOTCache=" + aotCacheFile,
106             "--show-version",
107             "-Xlog:cds",
108             "-XX:AOTMode=off",
109             "-cp", appJar, helloClass);
110         out = CDSTestUtils.executeAndLog(pb, "prod");
111         out.shouldNotContain(", sharing");
112         out.shouldNotContain("Opened AOT cache hello.aot.");
113         out.shouldContain("Hello World");
114         out.shouldHaveExitValue(0);
115 
116         //----------------------------------------------------------------------
117         printTestCase("AOTMode=auto");
118         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
119             "-XX:AOTCache=" + aotCacheFile,
120             "--show-version",
121             "-Xlog:cds",
122             "-XX:AOTMode=auto",
123             "-cp", appJar, helloClass);
124         out = CDSTestUtils.executeAndLog(pb, "prod");
125         out.shouldContain(", sharing");
126         out.shouldContain("Opened AOT cache hello.aot.");
127         out.shouldContain("Hello World");
128         out.shouldHaveExitValue(0);
129 
130         //----------------------------------------------------------------------
131         printTestCase("AOTMode=on");
132         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
133             "-XX:AOTCache=" + aotCacheFile,
134             "--show-version",
135             "-Xlog:cds",
136             "-XX:AOTMode=on",
137             "-cp", appJar, helloClass);
138         out = CDSTestUtils.executeAndLog(pb, "prod");
139         out.shouldContain(", sharing");
140         out.shouldContain("Opened AOT cache hello.aot.");
141         out.shouldContain("Hello World");
142         out.shouldHaveExitValue(0);
143 
144         //----------------------------------------------------------------------
145         printTestCase("Assembly Phase with -XX:-AOTClassLinking");
146         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
147             "-XX:AOTMode=create",
148             "-XX:-AOTClassLinking",
149             "-XX:AOTConfiguration=" + aotConfigFile,
150             "-XX:AOTCache=" + aotCacheFile,
151             "-Xlog:cds=debug",
152             "-cp", appJar);
153         out = CDSTestUtils.executeAndLog(pb, "asm");
154         out.shouldContain("Dumping shared data to file:");
155         out.shouldMatch("cds.*hello[.]aot");
156         out.shouldMatch(noTrainingDataPattern);
157         out.shouldMatch(noCachedCodePattern);
158         out.shouldHaveExitValue(0);
159 
160         //----------------------------------------------------------------------
161         printTestCase("Production Run with AOTCache, which was created with -XX:-AOTClassLinking");
162         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
163             "-XX:AOTCache=" + aotCacheFile,
164             "-Xlog:cds",
165             "-Xlog:scc*",
166             "-cp", appJar, helloClass);
167         out = CDSTestUtils.executeAndLog(pb, "prod");
168         out.shouldContain("Using AOT-linked classes: false (static archive: no aot-linked classes)");
169         out.shouldContain("Opened AOT cache hello.aot.");
170         out.shouldContain("Hello World");
171         out.shouldNotMatch(hasMappedCachedCodePattern);
172         out.shouldHaveExitValue(0);
173 
174         //----------------------------------------------------------------------
175         printTestCase("Training run with -XX:-AOTClassLinking, but assembly run with -XX:+AOTClassLinking");
176         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
177             "-XX:AOTMode=record",
178             "-XX:-AOTClassLinking",
179             "-XX:AOTConfiguration=" + aotConfigFile,
180             "-Xlog:cds=debug",
181             "-cp", appJar, helloClass);
182         out = CDSTestUtils.executeAndLog(pb, "train");
183         out.shouldContain("Hello World");
184         out.shouldContain("AOTConfiguration recorded: " + aotConfigFile);
185         out.shouldHaveExitValue(0);
186 
187         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
188             "-XX:AOTMode=create",
189             "-XX:+AOTClassLinking",
190             "-XX:AOTConfiguration=" + aotConfigFile,
191             "-XX:AOTCache=" + aotCacheFile,
192             "-Xlog:cds=debug",
193             "-cp", appJar);
194         out = CDSTestUtils.executeAndLog(pb, "asm");
195         out.shouldContain("Dumping shared data to file:");
196         out.shouldMatch("cds.*hello[.]aot");
197         out.shouldHaveExitValue(0);
198     }
199 
200     static void negativeTests() throws Exception {
201        //----------------------------------------------------------------------
202         printTestCase("Mixing old and new options");
203         String mixOldNewErrSuffix = " cannot be used at the same time with -Xshare:on, -Xshare:auto, "
204             + "-Xshare:off, -Xshare:dump, DumpLoadedClassList, SharedClassListFile, "
205             + "or SharedArchiveFile";
206 
207         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
208             "-Xshare:off",
209             "-XX:AOTConfiguration=" + aotConfigFile,
210             "-cp", appJar, helloClass);
211 
212         OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "neg");
213         out.shouldContain("Option AOTConfiguration" + mixOldNewErrSuffix);
214         out.shouldNotHaveExitValue(0);
215 
216         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
217             "-XX:SharedArchiveFile=" + aotCacheFile,
218             "-XX:AOTCache=" + aotCacheFile,
219             "-cp", appJar, helloClass);
220         out = CDSTestUtils.executeAndLog(pb, "neg");
221         out.shouldContain("Option AOTCache" + mixOldNewErrSuffix);
222         out.shouldNotHaveExitValue(0);
223 
224         //----------------------------------------------------------------------
225         printTestCase("Use AOTConfiguration without AOTMode");
226         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
227             "-XX:AOTConfiguration=" + aotConfigFile,
228             "-cp", appJar, helloClass);
229 
230         out = CDSTestUtils.executeAndLog(pb, "neg");
231         out.shouldContain("AOTConfiguration can only be used with -XX:AOTMode=record or -XX:AOTMode=create");
232         out.shouldNotHaveExitValue(0);
233 
234         //----------------------------------------------------------------------
235         printTestCase("Use AOTMode without AOTConfiguration");
236         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
237             "-XX:AOTMode=record",
238             "-cp", appJar, helloClass);
239 
240         out = CDSTestUtils.executeAndLog(pb, "neg");
241         out.shouldContain("-XX:AOTMode=record cannot be used without setting AOTConfiguration");
242 
243         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
244             "-XX:AOTMode=create",
245             "-cp", appJar, helloClass);
246 
247         out = CDSTestUtils.executeAndLog(pb, "neg");
248         out.shouldContain("-XX:AOTMode=create cannot be used without setting AOTConfiguration");
249         out.shouldNotHaveExitValue(0);
250 
251         //----------------------------------------------------------------------
252         printTestCase("Bad AOTMode");
253         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
254             "-XX:AOTMode=foo",
255             "-cp", appJar, helloClass);
256 
257         out = CDSTestUtils.executeAndLog(pb, "neg");
258         out.shouldContain("Unrecognized value foo for AOTMode. Must be one of the following: off, record, create, auto, on");
259         out.shouldNotHaveExitValue(0);
260 
261         //----------------------------------------------------------------------
262         printTestCase("AOTCache specified with -XX:AOTMode=record");
263         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
264             "-XX:AOTMode=record",
265             "-XX:AOTConfiguration=" + aotConfigFile,
266             "-XX:AOTCache=" + aotCacheFile,
267             "-cp", appJar, helloClass);
268 
269         out = CDSTestUtils.executeAndLog(pb, "neg");
270         out.shouldContain("AOTCache must not be specified when using -XX:AOTMode=record");
271         out.shouldNotHaveExitValue(0);
272 
273         //----------------------------------------------------------------------
274         printTestCase("AOTCache not specified with -XX:AOTMode=create");
275         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
276             "-XX:AOTMode=create",
277             "-XX:AOTConfiguration=" + aotConfigFile,
278             "-cp", appJar, helloClass);
279 
280         out = CDSTestUtils.executeAndLog(pb, "neg");
281         out.shouldContain("AOTCache must be specified when using -XX:AOTMode=create");
282         out.shouldNotHaveExitValue(0);
283 
284         //----------------------------------------------------------------------
285         printTestCase("No such config file");
286         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
287             "-XX:AOTMode=create",
288             "-XX:AOTConfiguration=no-such-file",
289             "-XX:AOTCache=" + aotCacheFile,
290             "-cp", appJar, helloClass);
291 
292         out = CDSTestUtils.executeAndLog(pb, "neg");
293         out.shouldContain("Must be a valid AOT configuration generated by the current JVM: no-such-file");
294         out.shouldNotHaveExitValue(0);
295 
296         //----------------------------------------------------------------------
297         printTestCase("AOTConfiguration file cannot be used as a CDS archive");
298 
299         // first make sure we have a valid aotConfigFile
300         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
301             "-XX:AOTMode=record",
302             "-XX:AOTConfiguration=" + aotConfigFile,
303             "-cp", appJar, helloClass);
304 
305         out = CDSTestUtils.executeAndLog(pb, "train");
306         out.shouldHaveExitValue(0);
307 
308         // Cannot use this config file as a AOT cache
309         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
310             "-XX:AOTMode=on",
311             "-XX:AOTCache=" + aotConfigFile,
312             "-cp", appJar, helloClass);
313 
314         out = CDSTestUtils.executeAndLog(pb, "neg");
315         out.shouldContain("Not a valid AOT cache (hello.aotconfig)");
316         out.shouldNotHaveExitValue(0);
317 
318         // Cannot use this config file as a CDS archive
319         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
320             "-Xshare:on",
321             "-XX:SharedArchiveFile=" + aotConfigFile,
322             "-cp", appJar, helloClass);
323 
324         out = CDSTestUtils.executeAndLog(pb, "neg");
325         out.shouldContain("Not a valid archive (hello.aotconfig)");
326         out.shouldNotHaveExitValue(0);
327 
328         //----------------------------------------------------------------------
329         printTestCase("Classpath mismatch when creating archive");
330 
331         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
332             "-XX:AOTMode=create",
333             "-XX:AOTConfiguration=" + aotConfigFile,
334             "-XX:AOTCache=" + aotCacheFile,
335             "-cp", "noSuchJar.jar");
336 
337         out = CDSTestUtils.executeAndLog(pb, "neg");
338         out.shouldContain("class path and/or module path are not compatible with the ones " +
339                           "specified when the AOTConfiguration file was recorded");
340         out.shouldContain("Unable to use create AOT cache");
341         out.shouldHaveExitValue(1);
342     }
343 
344     static int testNum = 0;
345     static void printTestCase(String s) {
346         System.out.println("vvvvvvv TEST CASE " + testNum + ": " + s + ": starts here vvvvvvv");
347         testNum++;
348     }
349 }