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 CDS should fail to load if production time GC flags do not match training run.
28 * @requires vm.flagless
29 * @requires vm.cds.write.archived.java.heap
30 * @library /test/jdk/lib/testlibrary /test/lib
31 * @build LeydenGCFlags
32 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
33 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar HelloApp
34 * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI LeydenGCFlags
35 */
36
37 import jdk.test.whitebox.WhiteBox;
38 import jdk.test.whitebox.gc.GC;
39
40 import jdk.test.lib.cds.CDSAppTester;
41 import jdk.test.lib.helpers.ClassFileInstaller;
42 import jdk.test.lib.process.OutputAnalyzer;
43 import jdk.test.lib.StringArrayUtils;
44
45 public class LeydenGCFlags {
46 static final String appJar = ClassFileInstaller.getJarPath("app.jar");
47 static final String mainClass = "HelloApp";
48 static final String ERROR_GC_MISMATCH = "CDS archive has aot-linked classes. It cannot be used because GC used during dump time (.*) is not the same as runtime (.*)";
49 static final String ERROR_COOP_MISMATCH = "Disable Startup Code Cache: 'HelloApp.cds.code' was created with CompressedOops::shift.. = .* vs current .*";
50
51 static String trainingArgs[];
52 static String productionArgs[];
53 static boolean shouldFailDump;
54 static boolean shouldFailRun;
55 static String productFailPattern;
56
57 public static void main(String[] args) throws Exception {
58 // Serial, Parallel and Shenandoah collectors are allowed to be used,
59 // as long as the same one is used between training and production
60 if (GC.Serial.isSupported()) {
61 good("-XX:+UseSerialGC", "-XX:+UseSerialGC");
62 }
63 if (GC.Parallel.isSupported()) {
64 good("-XX:+UseParallelGC", "-XX:+UseParallelGC");
65 }
66 if (GC.Shenandoah.isSupported()) {
67 good("-XX:+UseShenandoahGC", "-XX:+UseShenandoahGC");
68 }
69
70 // Fail if production uses a different collector than training
71 if (GC.Parallel.isSupported() && GC.G1.isSupported()) {
72 fail_run("-XX:+UseParallelGC", "-XX:+UseG1GC", ERROR_GC_MISMATCH );
73 }
74 if (GC.Parallel.isSupported()) {
75 fail_run(null, "-XX:+UseParallelGC", ERROR_GC_MISMATCH );
76 }
77
78 if (false) { // Disabled for now, as on MacOS we cannot guarantee to get differnt coop encodings
79 // Different oop encodings
80 fail_run(array("-XX:-UseCompatibleCompressedOops", "-Xmx128m"),
81 array("-XX:-UseCompatibleCompressedOops","-Xmx8g"),
82 ERROR_COOP_MISMATCH);
83 fail_run(array("-XX:-UseCompatibleCompressedOops", "-Xmx8g"),
84 array("-XX:-UseCompatibleCompressedOops","-Xmx128m"),
85 ERROR_COOP_MISMATCH);
86 }
87
88 // FIXME -- this causes
89 // java.lang.invoke.WrongMethodTypeException: handle's method type ()Object but found ()Object
90 /* fail_run(null, "NoSuchApp"); */
91 }
92
93 static String[] array(String... strings) {
94 return strings;
95 }
96 static void good(Object t, Object p) throws Exception {
97 shouldFailDump = false;
98 shouldFailRun = false;
99 run(t, p);
100 }
101
102 static void fail_dump(Object t, Object p, String regexp) throws Exception {
103 shouldFailDump = true;
104 shouldFailRun = true;
105 productFailPattern = regexp;
106 trainingArgs = makeArgs(t);
107 productionArgs = makeArgs(p);
108 Tester tester = new Tester();
109 tester.setCheckExitValue(false);
110 tester.run(new String[] {"AOT"} );
111 }
112
113 static void fail_run(Object t, Object p, String regexp) throws Exception {
114 shouldFailDump = false;
115 shouldFailRun = true;
116 productFailPattern = regexp;
117 run(t, p);
118 }
119
120 static void run(Object t, Object p) throws Exception {
121 trainingArgs = makeArgs(t);
122 productionArgs = makeArgs(p);
123 Tester tester = new Tester();
124 tester.run(new String[] {"AOT"} );
125 }
126
127 static String[] makeArgs(Object o) {
128 if (o == null) {
129 return new String[0];
130 }
131 if (o instanceof String[]) {
132 return (String[])o;
133 } else {
134 return new String[] { (String)o };
135 }
136 }
137
138 static class Tester extends CDSAppTester {
139 public Tester() {
140 super(mainClass);
141 }
142
143 @Override
144 public String classpath(RunMode runMode) {
145 return appJar;
146 }
147
148 @Override
149 public String[] appCommandLine(RunMode runMode) {
150 if (runMode.isProductionRun()) {
151 return StringArrayUtils.concat(productionArgs, "-XX:AOTMode=auto", mainClass);
152 } else {
153 return StringArrayUtils.concat(trainingArgs, "-Xlog:aot", mainClass);
154 }
155 }
156
157 @Override
158 public void checkExecution(OutputAnalyzer out, RunMode runMode) {
159 if (shouldFailDump) {
160 if (runMode != RunMode.PRODUCTION) {
161 out.shouldMatch(productFailPattern);
162 out.shouldHaveExitValue(1);
163 }
164 } else if (shouldFailRun) {
165 if (runMode == RunMode.PRODUCTION) {
166 out.shouldMatch(productFailPattern);
167 }
168 } else {
169 out.shouldContain("Hello Leyden");
170
171 if (isDumping(runMode)) {
172 // We should dump the heap even if the collector is not G1
173 out.shouldContain("Shared file region (hp)");
174 }
175
176 }
177 }
178 }
179 }
180
181 class HelloApp {
182 public static void main(String args[]) {
183 System.out.println("Hello Leyden");
184 }
185 }