1 /*
2  * Copyright (c) 2013, 2020, 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).
testNarrowKlassBase()46     static boolean testNarrowKlassBase() {
47         if (Platform.isWindows() || Platform.isPPC()) {
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.
smallHeapTest()56     public static void smallHeapTest() throws Exception {
57         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
58             "-XX:+UnlockDiagnosticVMOptions",
59             "-XX:SharedBaseAddress=8g",
60             "-Xmx128m",
61             logging_option,
62             "-Xshare:off",
63             "-XX:+VerifyBeforeGC", "-version");
64         OutputAnalyzer output = new OutputAnalyzer(pb.start());
65         if (testNarrowKlassBase()) {
66             output.shouldContain("Narrow klass base: 0x0000000000000000");
67         }
68         output.shouldHaveExitValue(0);
69     }
70 
71     // CDS off, small heap, ccs size explicitely set to 1G
72     // A small heap should allow us to place the ccs within the lower 32G and thus allow zero based encoding.
smallHeapTestWith1G()73     public static void smallHeapTestWith1G() throws Exception {
74         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
75             "-XX:+UnlockDiagnosticVMOptions",
76             "-XX:CompressedClassSpaceSize=1g",
77             "-Xmx128m",
78             logging_option,
79             "-Xshare:off",
80             "-XX:+VerifyBeforeGC", "-version");
81         OutputAnalyzer output = new OutputAnalyzer(pb.start());
82         if (testNarrowKlassBase()) {
83             output.shouldContain("Narrow klass base: 0x0000000000000000, Narrow klass shift: 3");
84         }
85         output.shouldHaveExitValue(0);
86     }
87 
88     // CDS off, a very large heap, ccs size left to 1G default.
89     // We expect the ccs to be mapped somewhere far beyond the heap, such that it is not possible
90     // to use zero based encoding.
largeHeapTest()91     public static void largeHeapTest() throws Exception {
92         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
93             "-XX:+UnlockDiagnosticVMOptions",
94             "-XX:+UnlockExperimentalVMOptions",
95             "-Xmx30g",
96             "-XX:-UseAOT", // AOT explicitly set klass shift to 3.
97             logging_option,
98             "-Xshare:off",
99             "-XX:+VerifyBeforeGC", "-version");
100         OutputAnalyzer output = new OutputAnalyzer(pb.start());
101         if (testNarrowKlassBase()) {
102             output.shouldNotContain("Narrow klass base: 0x0000000000000000");
103             output.shouldContain("Narrow klass shift: 0");
104         }
105         output.shouldHaveExitValue(0);
106     }
107 
108     // Using large paged heap, metaspace uses small pages.
largePagesForHeapTest()109     public static void largePagesForHeapTest() throws Exception {
110         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
111                 "-XX:+UnlockDiagnosticVMOptions",
112                 "-Xmx128m",
113                 "-XX:+UseLargePages",
114                 logging_option,
115                 "-XX:+VerifyBeforeGC", "-version");
116         OutputAnalyzer output = new OutputAnalyzer(pb.start());
117         if (testNarrowKlassBase()) {
118             output.shouldContain("Narrow klass base:");
119         }
120         output.shouldHaveExitValue(0);
121     }
122 
123     // Using large pages for heap and metaspace.
124     // Note that this is still unexciting since the compressed class space always uses small pages;
125     // UseLargePagesInMetaspace only affects non-class metaspace.
largePagesForHeapAndMetaspaceTest()126     public static void largePagesForHeapAndMetaspaceTest() throws Exception {
127         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
128             "-XX:+UnlockDiagnosticVMOptions",
129             "-Xmx128m",
130             "-XX:+UseLargePages", "-XX:+UseLargePagesInMetaspace",
131             logging_option,
132             "-XX:+VerifyBeforeGC", "-version");
133         OutputAnalyzer output = new OutputAnalyzer(pb.start());
134         if (testNarrowKlassBase()) {
135             output.shouldContain("Narrow klass base:");
136         }
137         output.shouldHaveExitValue(0);
138     }
139 
heapBaseMinAddressTest()140     public static void heapBaseMinAddressTest() throws Exception {
141         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
142             "-XX:HeapBaseMinAddress=1m",
143             "-Xlog:gc+heap+coops=debug",
144             "-version");
145         OutputAnalyzer output = new OutputAnalyzer(pb.start());
146         output.shouldContain("HeapBaseMinAddress must be at least");
147         output.shouldHaveExitValue(0);
148     }
149 
sharingTest()150     public static void sharingTest() throws Exception {
151         // Test small heaps
152         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
153             "-XX:+UnlockDiagnosticVMOptions",
154             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
155             "-Xmx128m",
156             "-XX:SharedBaseAddress=8g",
157             "-XX:+VerifyBeforeGC",
158             "-Xshare:dump",
159             "-Xlog:cds,gc+heap+coops=debug");
160         OutputAnalyzer output = new OutputAnalyzer(pb.start());
161         if (output.firstMatch("Shared spaces are not supported in this VM") != null) {
162             return;
163         }
164         try {
165           output.shouldContain("Loading classes to share");
166           output.shouldHaveExitValue(0);
167 
168           pb = ProcessTools.createJavaProcessBuilder(
169             "-XX:+UnlockDiagnosticVMOptions",
170             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
171             "-Xmx128m",
172             "-XX:SharedBaseAddress=8g",
173             "-Xlog:gc+heap+coops=debug",
174             "-Xshare:on",
175             "-version");
176           output = new OutputAnalyzer(pb.start());
177           output.shouldContain("sharing");
178           output.shouldHaveExitValue(0);
179 
180         } catch (RuntimeException e) {
181           output.shouldContain("Unable to use shared archive");
182           output.shouldHaveExitValue(1);
183         }
184     }
185 
smallHeapTestNoCoop()186     public static void smallHeapTestNoCoop() throws Exception {
187         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
188             "-XX:-UseCompressedOops",
189             "-XX:+UseCompressedClassPointers",
190             "-XX:+UnlockDiagnosticVMOptions",
191             "-XX:SharedBaseAddress=8g",
192             "-Xmx128m",
193             "-Xlog:gc+metaspace=trace",
194             "-Xshare:off",
195             "-Xlog:cds=trace",
196             "-XX:+VerifyBeforeGC", "-version");
197         OutputAnalyzer output = new OutputAnalyzer(pb.start());
198         output.shouldContain("Narrow klass base: 0x0000000000000000");
199         output.shouldHaveExitValue(0);
200     }
201 
smallHeapTestWith1GNoCoop()202     public static void smallHeapTestWith1GNoCoop() throws Exception {
203         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
204             "-XX:-UseCompressedOops",
205             "-XX:+UseCompressedClassPointers",
206             "-XX:+UnlockDiagnosticVMOptions",
207             "-XX:CompressedClassSpaceSize=1g",
208             "-Xmx128m",
209             "-Xlog:gc+metaspace=trace",
210             "-Xshare:off",
211             "-Xlog:cds=trace",
212             "-XX:+VerifyBeforeGC", "-version");
213         OutputAnalyzer output = new OutputAnalyzer(pb.start());
214         output.shouldContain("Narrow klass base: 0x0000000000000000");
215         if (!Platform.isAArch64()) {
216             // Currently relax this test for Aarch64.
217             output.shouldContain("Narrow klass shift: 0");
218         }
219         output.shouldHaveExitValue(0);
220     }
221 
largeHeapTestNoCoop()222     public static void largeHeapTestNoCoop() throws Exception {
223         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
224             "-XX:-UseCompressedOops",
225             "-XX:+UseCompressedClassPointers",
226             "-XX:+UnlockDiagnosticVMOptions",
227             "-XX:+UnlockExperimentalVMOptions",
228             "-Xmx30g",
229             "-XX:-UseAOT", // AOT explicitly set klass shift to 3.
230             "-Xlog:gc+metaspace=trace",
231             "-Xshare:off",
232             "-Xlog:cds=trace",
233             "-XX:+VerifyBeforeGC", "-version");
234         OutputAnalyzer output = new OutputAnalyzer(pb.start());
235         output.shouldContain("Narrow klass base: 0x0000000000000000");
236         if (!Platform.isAArch64()) {
237             // Currently relax this test for Aarch64.
238             output.shouldContain("Narrow klass shift: 0");
239         }
240         output.shouldHaveExitValue(0);
241     }
242 
largePagesTestNoCoop()243     public static void largePagesTestNoCoop() throws Exception {
244         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
245             "-XX:-UseCompressedOops",
246             "-XX:+UseCompressedClassPointers",
247             "-XX:+UnlockDiagnosticVMOptions",
248             "-Xmx128m",
249             "-XX:+UseLargePages",
250             "-Xlog:gc+metaspace=trace",
251             "-XX:+VerifyBeforeGC", "-version");
252         OutputAnalyzer output = new OutputAnalyzer(pb.start());
253         output.shouldContain("Narrow klass base:");
254         output.shouldHaveExitValue(0);
255     }
256 
heapBaseMinAddressTestNoCoop()257     public static void heapBaseMinAddressTestNoCoop() throws Exception {
258         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
259             "-XX:-UseCompressedOops",
260             "-XX:+UseCompressedClassPointers",
261             "-XX:HeapBaseMinAddress=1m",
262             "-Xlog:gc+heap+coops=debug",
263             "-version");
264         OutputAnalyzer output = new OutputAnalyzer(pb.start());
265         output.shouldContain("HeapBaseMinAddress must be at least");
266         output.shouldHaveExitValue(0);
267     }
268 
sharingTestNoCoop()269     public static void sharingTestNoCoop() throws Exception {
270         // Test small heaps
271         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
272             "-XX:-UseCompressedOops",
273             "-XX:+UseCompressedClassPointers",
274             "-XX:+UnlockDiagnosticVMOptions",
275             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
276             "-Xmx128m",
277             "-XX:SharedBaseAddress=8g",
278             "-XX:+VerifyBeforeGC",
279             "-Xshare:dump",
280             "-Xlog:cds,gc+heap+coops=debug");
281         OutputAnalyzer output = new OutputAnalyzer(pb.start());
282         if (output.firstMatch("Shared spaces are not supported in this VM") != null) {
283             return;
284         }
285         try {
286           output.shouldContain("Loading classes to share");
287           output.shouldHaveExitValue(0);
288 
289           pb = ProcessTools.createJavaProcessBuilder(
290             "-XX:-UseCompressedOops",
291             "-XX:+UseCompressedClassPointers",
292             "-XX:+UnlockDiagnosticVMOptions",
293             "-XX:SharedArchiveFile=./CompressedClassPointers.jsa",
294             "-Xmx128m",
295             "-XX:SharedBaseAddress=8g",
296             "-Xlog:gc+heap+coops=debug",
297             "-Xshare:on",
298             "-version");
299           output = new OutputAnalyzer(pb.start());
300           output.shouldContain("sharing");
301           output.shouldHaveExitValue(0);
302 
303         } catch (RuntimeException e) {
304           output.shouldContain("Unable to use shared archive");
305           output.shouldHaveExitValue(1);
306         }
307     }
308 
main(String[] args)309     public static void main(String[] args) throws Exception {
310         smallHeapTest();
311         smallHeapTestWith1G();
312         largeHeapTest();
313         largePagesForHeapTest();
314         largePagesForHeapAndMetaspaceTest();
315         heapBaseMinAddressTest();
316         sharingTest();
317 
318         if (!Platform.isOSX()) {
319             // Testing compressed class pointers without compressed oops.
320             // This is only possible if the platform supports it. Notably,
321             // on macOS, when compressed oops is disabled and the heap is
322             // given an arbitrary address, that address occasionally collides
323             // with where we would ideally have placed the compressed class
324             // space. Therefore, macOS is omitted for now.
325             smallHeapTestNoCoop();
326             smallHeapTestWith1GNoCoop();
327             largeHeapTestNoCoop();
328             largePagesTestNoCoop();
329             heapBaseMinAddressTestNoCoop();
330             sharingTestNoCoop();
331         }
332     }
333 }
334