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  * @requires vm.flagless
 30  * @library /test/lib
 31  * @modules java.base/jdk.internal.misc
 32  *          java.management
 33  * @run driver CompressedClassPointers
 34  */
 35 
 36 import jdk.test.lib.Platform;
 37 import jdk.test.lib.process.ProcessTools;
 38 import jdk.test.lib.process.OutputAnalyzer;
 39 import jtreg.SkippedException;
 40 
 41 public class CompressedClassPointers {
 42 
 43     static final String logging_option = "-Xlog:gc+metaspace=trace,cds=trace";
 44 
 45     // Returns true if we are to test the narrow klass base; we only do this on
 46     // platforms where we can be reasonably shure that we get reproducable placement).
 47     static boolean testNarrowKlassBase() {
 48         if (Platform.isWindows()) {
 49             return false;
 50         }
 51         return true;
 52 
 53     }
 54 
 55     // CDS off, small heap, ccs size default (1G)
 56     // A small heap should allow us to place the ccs within the lower 32G and thus allow zero based encoding.



 57     public static void smallHeapTest() throws Exception {
 58         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
 59             "-XX:+UnlockDiagnosticVMOptions",
 60             "-XX:SharedBaseAddress=8g",
 61             "-Xmx128m",
 62             logging_option,
 63             "-Xshare:off",
 64             "-XX:+VerifyBeforeGC", "-version");
 65         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 66         if (testNarrowKlassBase()) {
 67             output.shouldContain("Narrow klass base: 0x0000000000000000");
 68         }
 69         output.shouldHaveExitValue(0);
 70     }

 71 
 72     // CDS off, small heap, ccs size explicitely set to 1G
 73     // A small heap should allow us to place the ccs within the lower 32G and thus allow zero based encoding.

 74     public static void smallHeapTestWith1G() throws Exception {
 75         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
 76             "-XX:+UnlockDiagnosticVMOptions",
 77             "-XX:CompressedClassSpaceSize=1g",
 78             "-Xmx128m",
 79             logging_option,
 80             "-Xshare:off",
 81             "-XX:+VerifyBeforeGC", "-version");
 82         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 83         if (testNarrowKlassBase()) {
 84             output.shouldContain("Narrow klass base: 0x0000000000000000, Narrow klass shift: 3");
 85         }
 86         output.shouldHaveExitValue(0);
 87     }

 88 
 89     // CDS off, a very large heap, ccs size left to 1G default.
 90     // We expect the ccs to be mapped somewhere far beyond the heap, such that it is not possible
 91     // to use zero based encoding.


 92     public static void largeHeapTest() throws Exception {
 93         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
 94             "-XX:+UnlockDiagnosticVMOptions",
 95             "-XX:+UnlockExperimentalVMOptions",
 96             "-Xmx30g",
 97             logging_option,
 98             "-Xshare:off",
 99             "-XX:+VerifyBeforeGC", "-version");
100         OutputAnalyzer output = new OutputAnalyzer(pb.start());
101         if (testNarrowKlassBase() && !Platform.isPPC() && !Platform.isOSX()) {
102             // PPC: in most cases the heap cannot be placed below 32g so there
103             // is room for ccs and narrow klass base will be 0x0. Exception:
104             // Linux 4.1.42 or earlier (see ELF_ET_DYN_BASE in JDK-8244847).
105             // For simplicity we exclude PPC.
106             // OSX: similar.
107             output.shouldNotContain("Narrow klass base: 0x0000000000000000");
108             output.shouldContain("Narrow klass shift: 0");
109         }
110         output.shouldHaveExitValue(0);
111     }

112 
113     // Settings as in largeHeapTest() except for max heap size. We make max heap
114     // size even larger such that it cannot fit into lower 32G but not too large
115     // for compressed oops.
116     // We expect a zerobased ccs.

117     public static void largeHeapAbove32GTest() throws Exception {
118         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
119             "-XX:+UnlockDiagnosticVMOptions",
120             "-XX:+UnlockExperimentalVMOptions",
121             "-Xmx31g",
122             logging_option,
123             "-Xshare:off",
124             "-XX:+VerifyBeforeGC", "-version");
125         OutputAnalyzer output = new OutputAnalyzer(pb.start());
126         if (testNarrowKlassBase()) {
127             if (!(Platform.isAArch64() && Platform.isOSX())) { // see JDK-8262895
128                 output.shouldContain("Narrow klass base: 0x0000000000000000");
129                 if (!Platform.isAArch64() && !Platform.isOSX()) {
130                     output.shouldContain("Narrow klass shift: 0");
131                 }
132             }
133         }
134         output.shouldHaveExitValue(0);
135     }

136 
137     // Using large paged heap, metaspace uses small pages.




138     public static void largePagesForHeapTest() throws Exception {
139         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
140                 "-XX:+UnlockDiagnosticVMOptions",
141                 "-Xmx128m",
142                 "-XX:+UseLargePages",
143                 logging_option,
144                 "-XX:+VerifyBeforeGC", "-version");
145         OutputAnalyzer output = new OutputAnalyzer(pb.start());
146         if (testNarrowKlassBase()) {
147             output.shouldContain("Narrow klass base:");
148         }
149         output.shouldHaveExitValue(0);
150     }
151 
152     public static void heapBaseMinAddressTest() throws Exception {
153         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
154             "-XX:HeapBaseMinAddress=1m",
155             "-Xlog:gc+heap+coops=debug",
156             "-version");
157         OutputAnalyzer output = new OutputAnalyzer(pb.start());
158         output.shouldContain("HeapBaseMinAddress must be at least");
159         output.shouldHaveExitValue(0);
160     }
161 
162     public static void sharingTest() throws Exception {
163         // Test small heaps
164         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
165             "-XX:+UnlockDiagnosticVMOptions",
166             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
167             "-Xmx128m",
168             "-XX:SharedBaseAddress=8g",
169             "-XX:+VerifyBeforeGC",
170             "-Xshare:dump",
171             "-Xlog:cds,gc+heap+coops=debug");
172         OutputAnalyzer output = new OutputAnalyzer(pb.start());
173         if (output.firstMatch("Shared spaces are not supported in this VM") != null) {
174             return;
175         }
176         try {
177           output.shouldContain("Loading classes to share");
178           output.shouldHaveExitValue(0);
179 
180           pb = ProcessTools.createJavaProcessBuilder(
181             "-XX:+UnlockDiagnosticVMOptions",
182             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
183             "-Xmx128m",
184             "-XX:SharedBaseAddress=8g",
185             "-Xlog:gc+heap+coops=debug",
186             "-Xshare:on",
187             "-version");
188           output = new OutputAnalyzer(pb.start());
189           output.shouldContain("sharing");
190           output.shouldHaveExitValue(0);
191 
192         } catch (RuntimeException e) {
193           output.shouldContain("Unable to use shared archive");
194           output.shouldHaveExitValue(1);
195         }
196     }
197 

198     public static void smallHeapTestNoCoop() throws Exception {
199         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
200             "-XX:-UseCompressedOops",
201             "-XX:+UseCompressedClassPointers",
202             "-XX:+UnlockDiagnosticVMOptions",
203             "-XX:SharedBaseAddress=8g",
204             "-Xmx128m",
205             "-Xlog:gc+metaspace=trace",
206             "-Xshare:off",
207             "-Xlog:cds=trace",
208             "-XX:+VerifyBeforeGC", "-version");
209         OutputAnalyzer output = new OutputAnalyzer(pb.start());
210         output.shouldContain("Narrow klass base: 0x0000000000000000");
211         output.shouldHaveExitValue(0);
212     }

213 

214     public static void smallHeapTestWith1GNoCoop() throws Exception {
215         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
216             "-XX:-UseCompressedOops",
217             "-XX:+UseCompressedClassPointers",
218             "-XX:+UnlockDiagnosticVMOptions",
219             "-XX:CompressedClassSpaceSize=1g",
220             "-Xmx128m",
221             "-Xlog:gc+metaspace=trace",
222             "-Xshare:off",
223             "-Xlog:cds=trace",
224             "-XX:+VerifyBeforeGC", "-version");
225         OutputAnalyzer output = new OutputAnalyzer(pb.start());
226         output.shouldContain("Narrow klass base: 0x0000000000000000");
227         if (!Platform.isAArch64() && !Platform.isPPC()) {
228             // Currently relax this test for Aarch64 and ppc.
229             output.shouldContain("Narrow klass shift: 0");
230         }
231         output.shouldHaveExitValue(0);
232     }

233 

234     public static void largeHeapTestNoCoop() throws Exception {
235         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
236             "-XX:-UseCompressedOops",
237             "-XX:+UseCompressedClassPointers",
238             "-XX:+UnlockDiagnosticVMOptions",
239             "-XX:+UnlockExperimentalVMOptions",
240             "-Xmx30g",
241             "-Xlog:gc+metaspace=trace",
242             "-Xshare:off",
243             "-Xlog:cds=trace",
244             "-XX:+VerifyBeforeGC", "-version");
245         OutputAnalyzer output = new OutputAnalyzer(pb.start());
246         output.shouldContain("Narrow klass base: 0x0000000000000000");
247         if (!Platform.isAArch64() && !Platform.isPPC()) {
248             // Currently relax this test for Aarch64 and ppc.
249             output.shouldContain("Narrow klass shift: 0");
250         }
251         output.shouldHaveExitValue(0);
252     }

253 
254     public static void largePagesTestNoCoop() throws Exception {
255         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
256             "-XX:-UseCompressedOops",
257             "-XX:+UseCompressedClassPointers",
258             "-XX:+UnlockDiagnosticVMOptions",
259             "-Xmx128m",
260             "-XX:+UseLargePages",
261             "-Xlog:gc+metaspace=trace",
262             "-XX:+VerifyBeforeGC", "-version");
263         OutputAnalyzer output = new OutputAnalyzer(pb.start());
264         output.shouldContain("Narrow klass base:");
265         output.shouldHaveExitValue(0);
266     }
267 
268     public static void heapBaseMinAddressTestNoCoop() throws Exception {
269         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
270             "-XX:-UseCompressedOops",
271             "-XX:+UseCompressedClassPointers",
272             "-XX:HeapBaseMinAddress=1m",
273             "-Xlog:gc+heap+coops=debug",
274             "-version");
275         OutputAnalyzer output = new OutputAnalyzer(pb.start());
276         output.shouldContain("HeapBaseMinAddress must be at least");
277         output.shouldHaveExitValue(0);
278     }
279 
280     public static void sharingTestNoCoop() throws Exception {
281         // Test small heaps
282         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
283             "-XX:-UseCompressedOops",
284             "-XX:+UseCompressedClassPointers",
285             "-XX:+UnlockDiagnosticVMOptions",
286             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
287             "-Xmx128m",
288             "-XX:SharedBaseAddress=8g",
289             "-XX:+VerifyBeforeGC",
290             "-Xshare:dump",
291             "-Xlog:cds,gc+heap+coops=debug");
292         OutputAnalyzer output = new OutputAnalyzer(pb.start());
293         if (output.firstMatch("Shared spaces are not supported in this VM") != null) {
294             return;
295         }
296         try {
297           output.shouldContain("Loading classes to share");
298           output.shouldHaveExitValue(0);
299 
300           pb = ProcessTools.createJavaProcessBuilder(
301             "-XX:-UseCompressedOops",
302             "-XX:+UseCompressedClassPointers",
303             "-XX:+UnlockDiagnosticVMOptions",
304             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
305             "-Xmx128m",
306             "-XX:SharedBaseAddress=8g",
307             "-Xlog:gc+heap+coops=debug",
308             "-Xshare:on",
309             "-version");
310           output = new OutputAnalyzer(pb.start());
311           output.shouldContain("sharing");
312           output.shouldHaveExitValue(0);
313 
314         } catch (RuntimeException e) {
315           output.shouldContain("Unable to use shared archive");
316           output.shouldHaveExitValue(1);
317         }
318     }
319 
320     public static void main(String[] args) throws Exception {
321         smallHeapTest();
322         smallHeapTestWith1G();
323         largeHeapTest();
324         largeHeapAbove32GTest();
325         largePagesForHeapTest();
326         heapBaseMinAddressTest();
327         sharingTest();
328 
329         if (!Platform.isOSX()) {
330             // Testing compressed class pointers without compressed oops.
331             // This is only possible if the platform supports it. Notably,
332             // on macOS, when compressed oops is disabled and the heap is
333             // given an arbitrary address, that address occasionally collides
334             // with where we would ideally have placed the compressed class
335             // space. Therefore, macOS is omitted for now.
336             smallHeapTestNoCoop();
337             smallHeapTestWith1GNoCoop();
338             largeHeapTestNoCoop();
339             largePagesTestNoCoop();
340             heapBaseMinAddressTestNoCoop();
341             sharingTestNoCoop();
342         }
343     }
344 }
--- EOF ---