1 /* 2 * Copyright (c) 2024, 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_SUPPORTED = "Cannot create the CacheDataStore: UseCompressedClassPointers must be enabled, and collector must be G1, Parallel, Serial, Epsilon, or Shenandoah"; 49 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 (.*)"; 50 static final String ERROR_COOP_MISMATCH = "Disable Startup Code Cache: 'HelloApp.cds.code' was created with CompressedOops::shift.. = .* vs current .*"; 51 52 static String trainingArgs[]; 53 static String productionArgs[]; 54 static boolean shouldFailDump; 55 static boolean shouldFailRun; 56 static String productFailPattern; 57 58 public static void main(String[] args) throws Exception { 59 if (GC.Z.isSupported()) { 60 // ZGC not supported for now 61 fail_dump("-XX:+UseZGC", "-Xmx8g", ERROR_GC_SUPPORTED); 62 } 63 64 // Serial, Parallel and Shenandoah collectors are allowed to be used, 65 // as long as the same one is used between training and production 66 if (GC.Serial.isSupported()) { 67 good("-XX:+UseSerialGC", "-XX:+UseSerialGC"); 68 } 69 if (GC.Parallel.isSupported()) { 70 good("-XX:+UseParallelGC", "-XX:+UseParallelGC"); 71 } 72 if (GC.Shenandoah.isSupported()) { 73 good("-XX:+UseShenandoahGC", "-XX:+UseShenandoahGC"); 74 } 75 76 // Fail if production uses a different collector than training 77 if (GC.Parallel.isSupported() && GC.G1.isSupported()) { 78 fail_run("-XX:+UseParallelGC", "-XX:+UseG1GC", ERROR_GC_MISMATCH ); 79 } 80 if (GC.Parallel.isSupported()) { 81 fail_run(null, "-XX:+UseParallelGC", ERROR_GC_MISMATCH ); 82 } 83 84 if (false) { // Disabled for now, as on MacOS we cannot guarantee to get differnt coop encodings 85 // Different oop encodings 86 fail_run(array("-XX:-UseCompatibleCompressedOops", "-Xmx128m"), 87 array("-XX:-UseCompatibleCompressedOops","-Xmx8g"), 88 ERROR_COOP_MISMATCH); 89 fail_run(array("-XX:-UseCompatibleCompressedOops", "-Xmx8g"), 90 array("-XX:-UseCompatibleCompressedOops","-Xmx128m"), 91 ERROR_COOP_MISMATCH); 92 } 93 94 // FIXME -- this causes 95 // java.lang.invoke.WrongMethodTypeException: handle's method type ()Object but found ()Object 96 /* fail_run(null, "NoSuchApp"); */ 97 } 98 99 static String[] array(String... strings) { 100 return strings; 101 } 102 static void good(Object t, Object p) throws Exception { 103 shouldFailDump = false; 104 shouldFailRun = false; 105 run(t, p); 106 } 107 108 static void fail_dump(Object t, Object p, String regexp) throws Exception { 109 shouldFailDump = true; 110 shouldFailRun = true; 111 productFailPattern = regexp; 112 trainingArgs = makeArgs(t); 113 productionArgs = makeArgs(p); 114 Tester tester = new Tester(); 115 tester.setCheckExitValue(false); 116 tester.run(new String[] {"LEYDEN_TRAINONLY"} ); 117 } 118 119 static void fail_run(Object t, Object p, String regexp) throws Exception { 120 shouldFailDump = false; 121 shouldFailRun = true; 122 productFailPattern = regexp; 123 run(t, p); 124 } 125 126 static void run(Object t, Object p) throws Exception { 127 trainingArgs = makeArgs(t); 128 productionArgs = makeArgs(p); 129 Tester tester = new Tester(); 130 tester.run(new String[] {"LEYDEN"} ); 131 } 132 133 static String[] makeArgs(Object o) { 134 if (o == null) { 135 return new String[0]; 136 } 137 if (o instanceof String[]) { 138 return (String[])o; 139 } else { 140 return new String[] { (String)o }; 141 } 142 } 143 144 static class Tester extends CDSAppTester { 145 public Tester() { 146 super(mainClass); 147 } 148 149 @Override 150 public String classpath(RunMode runMode) { 151 return appJar; 152 } 153 154 @Override 155 public String[] appCommandLine(RunMode runMode) { 156 if (runMode.isProductionRun()) { 157 return StringArrayUtils.concat(productionArgs, "-Xshare:auto", mainClass); 158 } else { 159 return StringArrayUtils.concat(trainingArgs, mainClass); 160 } 161 } 162 163 @Override 164 public void checkExecution(OutputAnalyzer out, RunMode runMode) { 165 if (shouldFailDump) { 166 if (runMode != RunMode.PRODUCTION) { 167 out.shouldMatch(productFailPattern); 168 out.shouldHaveExitValue(1); 169 } 170 } else if (shouldFailRun) { 171 if (runMode == RunMode.PRODUCTION) { 172 out.shouldMatch(productFailPattern); 173 //out.shouldHaveExitValue(1); TODO VM should enable -Xshare:on by default 174 } 175 } else { 176 if (runMode != RunMode.TRAINING1) { 177 out.shouldContain("Hello Leyden"); 178 } 179 180 if (runMode == RunMode.TRAINING || runMode == RunMode.TRAINING1) { 181 // We should dump the heap even if the collector is not G1 182 out.shouldContain("Shared file region (hp)"); 183 } 184 185 } 186 } 187 } 188 } 189 190 class HelloApp { 191 public static void main(String args[]) { 192 System.out.println("Hello Leyden"); 193 } 194 }