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