1 /*
  2  * Copyright (c) 2015, 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 // NOTE: the test takes a long time for each VM option combination, so we split
 26 // it into 3 @test parts, so that they can be executed in parallel. If you make a
 27 // change, please ensure all @test blocks are in sync.
 28 
 29 
 30 /*
 31  * @test
 32  * @summary Test options that are incompatible with use of shared strings
 33  *          Also test mismatch in oops encoding between dump time and run time
 34  * @requires vm.cds.write.archived.java.heap
 35  * @comment This test explicitly chooses the type of GC to be used by sub-processes. It may conflict with the GC type set
 36  * via the -vmoptions command line option of JTREG. vm.gc==null will help the test case to discard the explicitly passed
 37  * vm options.
 38  * @requires (vm.gc=="null")
 39  * @requires vm.flagless
 40  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
 41  * @build jdk.test.whitebox.WhiteBox
 42  * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
 43  * @build HelloString
 44  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. IncompatibleOptions 0
 45  */
 46 
 47 
 48 /*
 49  * @test
 50  * @requires vm.cds.write.archived.java.heap
 51  * @requires (vm.gc=="null")
 52  * @requires vm.flagless
 53  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
 54  * @build jdk.test.whitebox.WhiteBox
 55  * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
 56  * @build HelloString
 57  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. IncompatibleOptions 1
 58  */
 59 
 60 /*
 61  * @test
 62  * @requires vm.cds.write.archived.java.heap
 63  * @requires (vm.gc=="null")
 64  * @requires vm.flagless
 65  * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds
 66  * @build jdk.test.whitebox.WhiteBox
 67  * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
 68  * @build HelloString
 69  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. IncompatibleOptions 2
 70  */
 71 
 72 
 73 import jdk.test.lib.Asserts;
 74 import jdk.test.lib.Platform;
 75 import jdk.test.lib.process.OutputAnalyzer;
 76 
 77 import jdk.test.whitebox.code.Compiler;
 78 import jdk.test.whitebox.gc.GC;
 79 
 80 public class IncompatibleOptions {
 81     static final String COOPS_DUMP_WARNING =
 82         "Cannot dump shared archive when UseCompressedOops or UseCompressedClassPointers is off";
 83     static final String GC_WARNING =
 84         "Archived java heap is not supported";
 85     static final String OBJ_ALIGNMENT_MISMATCH =
 86         "The shared archive file's ObjectAlignmentInBytes of .* does not equal the current ObjectAlignmentInBytes of";
 87     static final String COMPACT_STRING_MISMATCH =
 88         "The shared archive file's CompactStrings setting .* does not equal the current CompactStrings setting";
 89     static final String COMPRESSED_OOPS_NOT_CONSISTENT =
 90         "The saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime, CDS will be disabled.";
 91     static String appJar;
 92     static String[] vmOptionsPrefix = {};
 93 
 94     public static void main(String[] args) throws Exception {
 95         String[] noargs = {};
 96         SharedStringsUtils.run(Integer.parseInt(args[0]), 3, noargs, IncompatibleOptions::test);
 97         // Add a new @test block if you get an assert ----^ about this number. See
 98         // SharedStringsUtils.java for details.
 99     }
100 
101     public static void test(String[] args_ignored) throws Exception {
102         vmOptionsPrefix = SharedStringsUtils.getChildVMOptionsPrefix();
103         appJar = JarBuilder.build("IncompatibleOptions", "HelloString");
104 
105         // Uncompressed OOPs
106         testDump(1, "-XX:+UseG1GC", "-XX:-UseCompressedOops", null, false);
107         if (GC.Z.isSupported()) {
108             testDump(1, "-XX:+UseZGC", "-XX:-UseCompressedOops", null, false);
109         }
110 
111         // ParallelGC and SerialGC now supports dumping heap objects
112         testDump(2, "-XX:+UseParallelGC", "", "", false);
113         testDump(3, "-XX:+UseSerialGC", "", "", false);
114 
115         // Explicitly archive with compressed oops, run without.
116         testDump(5, "-XX:+UseG1GC", "-XX:+UseCompressedOops", null, false);
117         testExec(5, "-XX:+UseG1GC", "-XX:-UseCompressedOops",
118                  COMPRESSED_OOPS_NOT_CONSISTENT, true);
119 
120         // NOTE: No warning is displayed, by design
121         // Still run, to ensure no crash or exception
122         testExec(6, "-XX:+UseParallelGC", "", "", false);
123         testExec(7, "-XX:+UseSerialGC", "", "", false);
124 
125         // Test various oops encodings, by varying ObjectAlignmentInBytes and heap sizes
126         testDump(9, "-XX:+UseG1GC", "-XX:ObjectAlignmentInBytes=8", null, false);
127         testExec(9, "-XX:+UseG1GC", "-XX:ObjectAlignmentInBytes=16",
128                  OBJ_ALIGNMENT_MISMATCH, true);
129 
130         // Implicitly archive with compressed oops, run without.
131         // Max heap size for compressed oops is around 31G.
132         // UseCompressedOops is turned on by default when heap
133         // size is under 31G, but will be turned off when heap
134         // size is greater than that.
135         testDump(10, "-XX:+UseG1GC", "-Xmx1g", null, false);
136         testExec(10, "-XX:+UseG1GC", "-Xmx32g", null, true);
137         // Explicitly archive without compressed oops and run with.
138         testDump(11, "-XX:+UseG1GC", "-XX:-UseCompressedOops", null, false);
139         testExec(11, "-XX:+UseG1GC", "-XX:+UseCompressedOops", null, true);
140         // Implicitly archive without compressed oops and run with.
141         testDump(12, "-XX:+UseG1GC", "-Xmx32G", null, false);
142         testExec(12, "-XX:+UseG1GC", "-Xmx1G", null, true);
143         // CompactStrings must match between dump time and run time
144         testDump(13, "-XX:+UseG1GC", "-XX:-CompactStrings", null, false);
145         testExec(13, "-XX:+UseG1GC", "-XX:+CompactStrings",
146                  COMPACT_STRING_MISMATCH, true);
147         testDump(14, "-XX:+UseG1GC", "-XX:+CompactStrings", null, false);
148         testExec(14, "-XX:+UseG1GC", "-XX:-CompactStrings",
149                  COMPACT_STRING_MISMATCH, true);
150     }
151 
152     static void testDump(int testCaseNr, String collectorOption, String extraOption,
153         String expectedWarning, boolean expectedToFail) throws Exception {
154 
155         System.out.println("Testcase: " + testCaseNr);
156         OutputAnalyzer output = TestCommon.dump(appJar, TestCommon.list("Hello"),
157             TestCommon.concat(vmOptionsPrefix,
158                 "-XX:+UseCompressedOops",
159                 collectorOption,
160                 "-XX:SharedArchiveConfigFile=" + TestCommon.getSourceFile("SharedStringsBasic.txt"),
161                 "-Xlog:cds,cds+hashtables",
162                 extraOption));
163 
164         if (expectedWarning != null) {
165             output.shouldContain(expectedWarning);
166         }
167 
168         if (expectedToFail) {
169             Asserts.assertNE(output.getExitValue(), 0,
170             "JVM is expected to fail, but did not");
171         }
172     }
173 
174     static void testExec(int testCaseNr, String collectorOption, String extraOption,
175         String expectedWarning, boolean expectedToFail) throws Exception {
176 
177         OutputAnalyzer output;
178         System.out.println("Testcase: " + testCaseNr);
179 
180         // needed, otherwise system considers empty extra option as a
181         // main class param, and fails with "Could not find or load main class"
182         if (!extraOption.isEmpty()) {
183             output = TestCommon.exec(appJar,
184                 TestCommon.concat(vmOptionsPrefix,
185                     "-XX:+UseCompressedOops",
186                     collectorOption, "-Xlog:cds", extraOption, "HelloString"));
187         } else {
188             output = TestCommon.exec(appJar,
189                 TestCommon.concat(vmOptionsPrefix,
190                     "-XX:+UseCompressedOops",
191                     collectorOption, "-Xlog:cds", "HelloString"));
192         }
193 
194         if (expectedWarning != null) {
195             output.shouldMatch(expectedWarning);
196         }
197 
198         if (expectedToFail) {
199             Asserts.assertNE(output.getExitValue(), 0);
200         } else {
201             SharedStringsUtils.checkExec(output);
202         }
203     }
204 }