1 /*
  2  * Copyright (c) 2013, 2023, 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  * @test
 26  * @bug 8024927
 27  * @summary Testing address of compressed class pointer space as best as possible.
 28  * @requires vm.bits == 64 & !vm.graal.enabled
 29  * @requires vm.flagless
 30  * @comment Testing compressed class pointers without compressed oops is not possible
 31  *          on MacOS because the heap is given an arbitrary address that occasionally
 32  *          collides with where we would ideally have placed the compressed class space.
 33  * @requires os.family != "mac"
 34  * @library /test/lib
 35  * @modules java.base/jdk.internal.misc
 36  *          java.management
 37  * @run driver CompressedClassPointers
 38  */
 39 
 40 import jdk.test.lib.Platform;
 41 import jdk.test.lib.process.ProcessTools;
 42 import jdk.test.lib.process.OutputAnalyzer;
 43 import jtreg.SkippedException;
 44 
 45 public class CompressedClassPointers {
 46 
 47     static final String logging_option = "-Xlog:gc+metaspace=trace,metaspace=info,cds=trace";
 48     static final String reserveCCSAnywhere = "Reserving compressed class space anywhere";
 49     static final String usesCompactObjectHeadersPat = "UseCompactObjectHeaders 1";
 50 
 51     // Returns true if we are to test the narrow klass base; we only do this on
 52     // platforms where we can be reasonably shure that we get reproducable placement).
 53     static boolean testNarrowKlassBase() {
 54         if (Platform.isWindows()) {
 55             return false;
 56         }
 57         return true;
 58 
 59     }
 60 
 61     // Returns true if the output indicates that the VM uses compact object headers
 62     static boolean usesCompactObjectHeaders(OutputAnalyzer output) {
 63         return output.getOutput().contains(usesCompactObjectHeadersPat);
 64     }
 65 
 66     // Returns true if the output indicates that the ccs is reserved anywhere.
 67     static boolean isCCSReservedAnywhere(OutputAnalyzer output) {
 68         if (output.getOutput().contains(reserveCCSAnywhere)) {
 69             return true;
 70         } else {
 71             return false;
 72         }
 73     }
 74 
 75     // CDS off, small heap, ccs size default (1G)
 76     // A small heap should allow us to place the ccs within the lower 32G and thus allow zero based encoding.
 77     public static void smallHeapTest() throws Exception {
 78         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
 79             "-XX:+UnlockDiagnosticVMOptions",
 80             "-XX:SharedBaseAddress=8g",
 81             "-Xmx128m",
 82             logging_option,
 83             "-Xshare:off",
 84             "-XX:+VerifyBeforeGC", "-version");
 85         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 86         if (testNarrowKlassBase() && !isCCSReservedAnywhere(output)) {
 87             output.shouldContain("Narrow klass base: 0x0000000000000000");
 88         }
 89         output.shouldHaveExitValue(0);
 90     }
 91 
 92     // CDS off, small heap, ccs size explicitely set to 1G
 93     // A small heap should allow us to place the ccs within the lower 32G and thus allow zero based encoding.
 94     public static void smallHeapTestWith1G() throws Exception {
 95         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
 96             "-XX:+UnlockDiagnosticVMOptions",
 97             "-XX:CompressedClassSpaceSize=1g",
 98             "-Xmx128m",
 99             logging_option,
100             "-Xshare:off",
101             "-XX:+VerifyBeforeGC", "-version");
102         OutputAnalyzer output = new OutputAnalyzer(pb.start());
103         if (testNarrowKlassBase() && !isCCSReservedAnywhere(output)) {
104             output.shouldContain("Narrow klass base: 0x0000000000000000, Narrow klass shift: 3");
105         }
106         output.shouldHaveExitValue(0);
107     }
108 
109     // CDS off, a very large heap, ccs size left to 1G default.
110     // We expect the ccs to be mapped somewhere far beyond the heap, such that it is not possible
111     // to use zero based encoding.
112     public static void largeHeapTest() throws Exception {
113         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
114             "-XX:+UnlockDiagnosticVMOptions",
115             "-XX:+UnlockExperimentalVMOptions",
116             "-Xmx30g",
117             logging_option,
118             "-Xshare:off",
119             "-XX:+VerifyBeforeGC", "-version");
120         OutputAnalyzer output = new OutputAnalyzer(pb.start());
121         if (testNarrowKlassBase() && !Platform.isPPC() && !Platform.isOSX() && !isCCSReservedAnywhere(output)) {
122             // PPC: in most cases the heap cannot be placed below 32g so there
123             // is room for ccs and narrow klass base will be 0x0. Exception:
124             // Linux 4.1.42 or earlier (see ELF_ET_DYN_BASE in JDK-8244847).
125             // For simplicity we exclude PPC.
126             // OSX: similar.
127             output.shouldNotContain("Narrow klass base: 0x0000000000000000");
128             output.shouldContain("Narrow klass shift: 0");
129         }
130         output.shouldHaveExitValue(0);
131     }
132 
133     // Settings as in largeHeapTest() except for max heap size. We make max heap
134     // size even larger such that it cannot fit into lower 32G but not too large
135     // for compressed oops.
136     // We expect a zerobased ccs.
137     public static void largeHeapAbove32GTest() throws Exception {
138         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
139             "-XX:+UnlockDiagnosticVMOptions",
140             "-XX:+UnlockExperimentalVMOptions",
141             "-Xmx31g",
142             logging_option,
143             "-Xshare:off",
144             "-XX:+VerifyBeforeGC", "-version");
145         OutputAnalyzer output = new OutputAnalyzer(pb.start());
146         if (testNarrowKlassBase()) {
147             if (!(Platform.isAArch64() && Platform.isOSX())  && !isCCSReservedAnywhere(output)) { // see JDK-8262895
148                 output.shouldContain("Narrow klass base: 0x0000000000000000");
149                 if (!Platform.isAArch64() && !Platform.isPPC() && !Platform.isOSX()) {
150                     output.shouldContain("Narrow klass shift: 0");
151                 }
152             }
153         }
154         output.shouldHaveExitValue(0);
155     }
156 
157     // Using large paged heap, metaspace uses small pages.
158     public static void largePagesForHeapTest() throws Exception {
159         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
160                 "-XX:+UnlockDiagnosticVMOptions",
161                 "-Xmx128m",
162                 "-XX:+UseLargePages",
163                 logging_option,
164                 "-XX:+VerifyBeforeGC", "-version");
165         OutputAnalyzer output = new OutputAnalyzer(pb.start());
166         if (testNarrowKlassBase()) {
167             output.shouldContain("Narrow klass base:");
168         }
169         output.shouldHaveExitValue(0);
170     }
171 
172     public static void heapBaseMinAddressTest() throws Exception {
173         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
174             "-XX:HeapBaseMinAddress=1m",
175             "-Xlog:gc+heap+coops=debug",
176             "-version");
177         OutputAnalyzer output = new OutputAnalyzer(pb.start());
178         output.shouldContain("HeapBaseMinAddress must be at least");
179         output.shouldHaveExitValue(0);
180     }
181 
182     public static void sharingTest() throws Exception {
183         // Test small heaps
184         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
185             "-XX:+UnlockDiagnosticVMOptions",
186             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
187             "-Xmx128m",
188             "-XX:SharedBaseAddress=8g",
189             "-XX:+VerifyBeforeGC",
190             "-Xshare:dump",
191             "-Xlog:cds,gc+heap+coops=debug");
192         OutputAnalyzer output = new OutputAnalyzer(pb.start());
193         if (output.firstMatch("Shared spaces are not supported in this VM") != null) {
194             return;
195         }
196         try {
197           output.shouldContain("Loading classes to share");
198           output.shouldHaveExitValue(0);
199 
200           pb = ProcessTools.createLimitedTestJavaProcessBuilder(
201             "-XX:+UnlockDiagnosticVMOptions",
202             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
203             "-Xmx128m",
204             "-XX:SharedBaseAddress=8g",
205             "-Xlog:gc+heap+coops=debug",
206             "-Xshare:on",
207             "-version");
208           output = new OutputAnalyzer(pb.start());
209           output.shouldContain("sharing");
210           output.shouldHaveExitValue(0);
211 
212         } catch (RuntimeException e) {
213           output.shouldContain("Unable to use shared archive");
214           output.shouldHaveExitValue(1);
215         }
216     }
217 
218     public static void smallHeapTestNoCoop() throws Exception {
219         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
220             "-XX:-UseCompressedOops",
221             "-XX:+UseCompressedClassPointers",
222             "-XX:+UnlockDiagnosticVMOptions",
223             "-XX:SharedBaseAddress=8g",
224             "-Xmx128m",
225             "-Xlog:gc+metaspace=trace",
226             "-Xshare:off",
227             "-Xlog:cds=trace",
228             "-XX:+VerifyBeforeGC", "-version");
229         OutputAnalyzer output = new OutputAnalyzer(pb.start());
230         if (!isCCSReservedAnywhere(output) && !usesCompactObjectHeaders(output)) {
231             output.shouldContain("Narrow klass base: 0x0000000000000000");
232         }
233         output.shouldHaveExitValue(0);
234     }
235 
236     public static void smallHeapTestWith1GNoCoop() throws Exception {
237         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
238             "-XX:-UseCompressedOops",
239             "-XX:+UseCompressedClassPointers",
240             "-XX:+UnlockDiagnosticVMOptions",
241             "-XX:CompressedClassSpaceSize=1g",
242             "-Xmx128m",
243             "-Xlog:gc+metaspace=trace",
244             "-Xshare:off",
245             "-Xlog:cds=trace",
246             "-XX:+VerifyBeforeGC", "-version");
247         OutputAnalyzer output = new OutputAnalyzer(pb.start());
248         if (!isCCSReservedAnywhere(output) && !usesCompactObjectHeaders(output)) {
249             output.shouldContain("Narrow klass base: 0x0000000000000000");
250         }
251         if (!Platform.isAArch64()  && !usesCompactObjectHeaders(output) && !Platform.isPPC()) {
252             // Currently relax this test for Aarch64 and ppc.
253             output.shouldContain("Narrow klass shift: 0");
254         }
255         output.shouldHaveExitValue(0);
256     }
257 
258     public static void largeHeapTestNoCoop() throws Exception {
259         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
260             "-XX:-UseCompressedOops",
261             "-XX:+UseCompressedClassPointers",
262             "-XX:+UnlockDiagnosticVMOptions",
263             "-XX:+UnlockExperimentalVMOptions",
264             "-Xmx30g",
265             "-Xlog:gc+metaspace=trace",
266             "-Xshare:off",
267             "-Xlog:cds=trace",
268             "-XX:+VerifyBeforeGC", "-version");
269         OutputAnalyzer output = new OutputAnalyzer(pb.start());
270         if (!isCCSReservedAnywhere(output) && !usesCompactObjectHeaders(output)) {
271             output.shouldContain("Narrow klass base: 0x0000000000000000");
272         }
273         if (!Platform.isAArch64()  && !usesCompactObjectHeaders(output) && !Platform.isPPC()) {
274             // Currently relax this test for Aarch64 and ppc.
275             output.shouldContain("Narrow klass shift: 0");
276         }
277         output.shouldHaveExitValue(0);
278     }
279 
280     public static void largePagesTestNoCoop() throws Exception {
281         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
282             "-XX:-UseCompressedOops",
283             "-XX:+UseCompressedClassPointers",
284             "-XX:+UnlockDiagnosticVMOptions",
285             "-Xmx128m",
286             "-XX:+UseLargePages",
287             "-Xlog:gc+metaspace=trace",
288             "-XX:+VerifyBeforeGC", "-version");
289         OutputAnalyzer output = new OutputAnalyzer(pb.start());
290         output.shouldContain("Narrow klass base:");
291         output.shouldHaveExitValue(0);
292     }
293 
294     public static void heapBaseMinAddressTestNoCoop() throws Exception {
295         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
296             "-XX:-UseCompressedOops",
297             "-XX:+UseCompressedClassPointers",
298             "-XX:HeapBaseMinAddress=1m",
299             "-Xlog:gc+heap+coops=debug",
300             "-version");
301         OutputAnalyzer output = new OutputAnalyzer(pb.start());
302         output.shouldContain("HeapBaseMinAddress must be at least");
303         output.shouldHaveExitValue(0);
304     }
305 
306     public static void sharingTestNoCoop() throws Exception {
307         // Test small heaps
308         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(
309             "-XX:-UseCompressedOops",
310             "-XX:+UseCompressedClassPointers",
311             "-XX:+UnlockDiagnosticVMOptions",
312             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
313             "-Xmx128m",
314             "-XX:SharedBaseAddress=8g",
315             "-XX:+VerifyBeforeGC",
316             "-Xshare:dump",
317             "-Xlog:cds,gc+heap+coops=debug");
318         OutputAnalyzer output = new OutputAnalyzer(pb.start());
319         if (output.firstMatch("Shared spaces are not supported in this VM") != null) {
320             return;
321         }
322         try {
323           output.shouldContain("Loading classes to share");
324           output.shouldHaveExitValue(0);
325 
326           pb = ProcessTools.createLimitedTestJavaProcessBuilder(
327             "-XX:-UseCompressedOops",
328             "-XX:+UseCompressedClassPointers",
329             "-XX:+UnlockDiagnosticVMOptions",
330             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
331             "-Xmx128m",
332             "-XX:SharedBaseAddress=8g",
333             "-Xlog:gc+heap+coops=debug",
334             "-Xshare:on",
335             "-version");
336           output = new OutputAnalyzer(pb.start());
337           output.shouldContain("sharing");
338           output.shouldHaveExitValue(0);
339 
340         } catch (RuntimeException e) {
341           output.shouldContain("Unable to use shared archive");
342           output.shouldHaveExitValue(1);
343         }
344     }
345 
346     public static void main(String[] args) throws Exception {
347         smallHeapTest();
348         smallHeapTestWith1G();
349         largeHeapTest();
350         largeHeapAbove32GTest();
351         largePagesForHeapTest();
352         heapBaseMinAddressTest();
353         sharingTest();
354 
355         smallHeapTestNoCoop();
356         smallHeapTestWith1GNoCoop();
357         largeHeapTestNoCoop();
358         largePagesTestNoCoop();
359         heapBaseMinAddressTestNoCoop();
360         sharingTestNoCoop();
361     }
362 }