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         //----------------------------------------------------------------------
 53         printTestCase("Training Run");
 54         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
 55             "-XX:AOTMode=record",
 56             "-XX:AOTConfiguration=" + aotConfigFile,
 57             "-Xlog:cds=debug",
 58             "-cp", appJar, helloClass);
 59 
 60         OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "train");
 61         out.shouldContain("Hello World");
 62         out.shouldContain("AOTConfiguration recorded: " + aotConfigFile);
 63         out.shouldHaveExitValue(0);
 64 
 65         //----------------------------------------------------------------------
 66         printTestCase("Assembly Phase (AOTClassLinking unspecified -> should be enabled by default)");
 67         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
 68             "-XX:AOTMode=create",
 69             "-XX:AOTConfiguration=" + aotConfigFile,
 70             "-XX:AOTCache=" + aotCacheFile,
 71             "-Xlog:cds",
 72             "-cp", appJar);
 73         out = CDSTestUtils.executeAndLog(pb, "asm");
 74         out.shouldContain("Dumping shared data to file:");
 75         out.shouldMatch("cds.*hello[.]aot");
 76         out.shouldHaveExitValue(0);
 77 
 78         //----------------------------------------------------------------------
 79         printTestCase("Production Run with AOTCache");
 80         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
 81             "-XX:AOTCache=" + aotCacheFile,
 82             "-Xlog:cds",
 83             "-cp", appJar, helloClass);
 84         out = CDSTestUtils.executeAndLog(pb, "prod");
 85         out.shouldContain("Using AOT-linked classes: true (static archive: has aot-linked classes)");
 86         out.shouldContain("Opened AOT cache hello.aot.");
 87         out.shouldContain("Hello World");
 88         out.shouldHaveExitValue(0);
 89 
 90         //----------------------------------------------------------------------
 91         printTestCase("AOTMode=off");
 92         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
 93             "-XX:AOTCache=" + aotCacheFile,
 94             "--show-version",
 95             "-Xlog:cds",
 96             "-XX:AOTMode=off",
 97             "-cp", appJar, helloClass);
 98         out = CDSTestUtils.executeAndLog(pb, "prod");
 99         out.shouldNotContain(", sharing");
100         out.shouldNotContain("Opened AOT cache hello.aot.");
101         out.shouldContain("Hello World");
102         out.shouldHaveExitValue(0);
103 
104         //----------------------------------------------------------------------
105         printTestCase("AOTMode=auto");
106         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
107             "-XX:AOTCache=" + aotCacheFile,
108             "--show-version",
109             "-Xlog:cds",
110             "-XX:AOTMode=auto",
111             "-cp", appJar, helloClass);
112         out = CDSTestUtils.executeAndLog(pb, "prod");
113         out.shouldContain(", sharing");
114         out.shouldContain("Opened AOT cache hello.aot.");
115         out.shouldContain("Hello World");
116         out.shouldHaveExitValue(0);
117 
118         //----------------------------------------------------------------------
119         printTestCase("AOTMode=on");
120         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
121             "-XX:AOTCache=" + aotCacheFile,
122             "--show-version",
123             "-Xlog:cds",
124             "-XX:AOTMode=on",
125             "-cp", appJar, helloClass);
126         out = CDSTestUtils.executeAndLog(pb, "prod");
127         out.shouldContain(", sharing");
128         out.shouldContain("Opened AOT cache hello.aot.");
129         out.shouldContain("Hello World");
130         out.shouldHaveExitValue(0);
131 
132         //----------------------------------------------------------------------
133         printTestCase("Assembly Phase with -XX:-AOTClassLinking");
134         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
135             "-XX:AOTMode=create",
136             "-XX:-AOTClassLinking",
137             "-XX:AOTConfiguration=" + aotConfigFile,
138             "-XX:AOTCache=" + aotCacheFile,
139             "-Xlog:cds",
140             "-cp", appJar);
141         out = CDSTestUtils.executeAndLog(pb, "asm");
142         out.shouldContain("Dumping shared data to file:");
143         out.shouldMatch("cds.*hello[.]aot");
144         out.shouldHaveExitValue(0);
145 
146         //----------------------------------------------------------------------
147         printTestCase("Production Run with AOTCache, which was created with -XX:-AOTClassLinking");
148         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
149             "-XX:AOTCache=" + aotCacheFile,
150             "-Xlog:cds",
151             "-cp", appJar, helloClass);
152         out = CDSTestUtils.executeAndLog(pb, "prod");
153         out.shouldContain("Using AOT-linked classes: false (static archive: no aot-linked classes)");
154         out.shouldContain("Opened AOT cache hello.aot.");
155         out.shouldContain("Hello World");
156         out.shouldHaveExitValue(0);
157     }
158 
159     static void negativeTests() throws Exception {
160        //----------------------------------------------------------------------
161         printTestCase("Mixing old and new options");
162         String mixOldNewErrSuffix = " cannot be used at the same time with -Xshare:on, -Xshare:auto, "
163             + "-Xshare:off, -Xshare:dump, DumpLoadedClassList, SharedClassListFile, "
164             + "or SharedArchiveFile";
165 
166         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
167             "-Xshare:off",
168             "-XX:AOTConfiguration=" + aotConfigFile,
169             "-cp", appJar, helloClass);
170 
171         OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "neg");
172         out.shouldContain("Option AOTConfiguration" + mixOldNewErrSuffix);
173         out.shouldNotHaveExitValue(0);
174 
175         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
176             "-XX:SharedArchiveFile=" + aotCacheFile,
177             "-XX:AOTCache=" + aotCacheFile,
178             "-cp", appJar, helloClass);
179         out = CDSTestUtils.executeAndLog(pb, "neg");
180         out.shouldContain("Option AOTCache" + mixOldNewErrSuffix);
181         out.shouldNotHaveExitValue(0);
182 
183         //----------------------------------------------------------------------
184         printTestCase("Use AOTConfiguration without AOTMode");
185         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
186             "-XX:AOTConfiguration=" + aotConfigFile,
187             "-cp", appJar, helloClass);
188 
189         out = CDSTestUtils.executeAndLog(pb, "neg");
190         out.shouldContain("AOTConfiguration can only be used with -XX:AOTMode=record or -XX:AOTMode=create");
191         out.shouldNotHaveExitValue(0);
192 
193         //----------------------------------------------------------------------
194         printTestCase("Use AOTMode without AOTConfiguration");
195         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
196             "-XX:AOTMode=record",
197             "-cp", appJar, helloClass);
198 
199         out = CDSTestUtils.executeAndLog(pb, "neg");
200         out.shouldContain("-XX:AOTMode=record cannot be used without setting AOTConfiguration");
201 
202         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
203             "-XX:AOTMode=create",
204             "-cp", appJar, helloClass);
205 
206         out = CDSTestUtils.executeAndLog(pb, "neg");
207         out.shouldContain("-XX:AOTMode=create cannot be used without setting AOTConfiguration");
208         out.shouldNotHaveExitValue(0);
209 
210         //----------------------------------------------------------------------
211         printTestCase("Bad AOTMode");
212         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
213             "-XX:AOTMode=foo",
214             "-cp", appJar, helloClass);
215 
216         out = CDSTestUtils.executeAndLog(pb, "neg");
217         out.shouldContain("Unrecognized value foo for AOTMode. Must be one of the following: off, record, create, auto, on");
218         out.shouldNotHaveExitValue(0);
219 
220         //----------------------------------------------------------------------
221         printTestCase("AOTCache specified with -XX:AOTMode=record");
222         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
223             "-XX:AOTMode=record",
224             "-XX:AOTConfiguration=" + aotConfigFile,
225             "-XX:AOTCache=" + aotCacheFile,
226             "-cp", appJar, helloClass);
227 
228         out = CDSTestUtils.executeAndLog(pb, "neg");
229         out.shouldContain("AOTCache must not be specified when using -XX:AOTMode=record");
230         out.shouldNotHaveExitValue(0);
231 
232         //----------------------------------------------------------------------
233         printTestCase("AOTCache not specified with -XX:AOTMode=create");
234         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
235             "-XX:AOTMode=create",
236             "-XX:AOTConfiguration=" + aotConfigFile,
237             "-cp", appJar, helloClass);
238 
239         out = CDSTestUtils.executeAndLog(pb, "neg");
240         out.shouldContain("AOTCache must be specified when using -XX:AOTMode=create");
241         out.shouldNotHaveExitValue(0);
242 
243         //----------------------------------------------------------------------
244         printTestCase("No such config file");
245         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
246             "-XX:AOTMode=create",
247             "-XX:AOTConfiguration=no-such-file",
248             "-XX:AOTCache=" + aotCacheFile,
249             "-cp", appJar, helloClass);
250 
251         out = CDSTestUtils.executeAndLog(pb, "neg");
252         out.shouldContain("Must be a valid AOT configuration generated by the current JVM: no-such-file");
253         out.shouldNotHaveExitValue(0);
254 
255         //----------------------------------------------------------------------
256         printTestCase("AOTConfiguration file cannot be used as a CDS archive");
257 
258         // first make sure we have a valid aotConfigFile
259         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
260             "-XX:AOTMode=record",
261             "-XX:AOTConfiguration=" + aotConfigFile,
262             "-cp", appJar, helloClass);
263 
264         out = CDSTestUtils.executeAndLog(pb, "train");
265         out.shouldHaveExitValue(0);
266 
267         // Cannot use this config file as a AOT cache
268         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
269             "-XX:AOTMode=on",
270             "-XX:AOTCache=" + aotConfigFile,
271             "-cp", appJar, helloClass);
272 
273         out = CDSTestUtils.executeAndLog(pb, "neg");
274         out.shouldContain("Not a valid AOT cache (hello.aotconfig)");
275         out.shouldNotHaveExitValue(0);
276 
277         // Cannot use this config file as a CDS archive
278         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
279             "-Xshare:on",
280             "-XX:SharedArchiveFile=" + aotConfigFile,
281             "-cp", appJar, helloClass);
282 
283         out = CDSTestUtils.executeAndLog(pb, "neg");
284         out.shouldContain("Not a valid archive (hello.aotconfig)");
285         out.shouldNotHaveExitValue(0);
286 
287         //----------------------------------------------------------------------
288         printTestCase("Classpath mismatch when creating archive");
289 
290         pb = ProcessTools.createLimitedTestJavaProcessBuilder(
291             "-XX:AOTMode=create",
292             "-XX:AOTConfiguration=" + aotConfigFile,
293             "-XX:AOTCache=" + aotCacheFile,
294             "-cp", "noSuchJar.jar");
295 
296         out = CDSTestUtils.executeAndLog(pb, "neg");
297         out.shouldContain("class path and/or module path are not compatible with the ones " +
298                           "specified when the AOTConfiguration file was recorded");
299         out.shouldContain("Unable to use create AOT cache");
300         out.shouldHaveExitValue(1);
301     }
302 
303     static int testNum = 0;
304     static void printTestCase(String s) {
305         System.out.println("vvvvvvv TEST CASE " + testNum + ": " + s + " starts here vvvvvvv");
306         testNum++;
307     }
308 }