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 50 // Returns true if we are to test the narrow klass base; we only do this on 51 // platforms where we can be reasonably shure that we get reproducable placement). 52 static boolean testNarrowKlassBase() { 53 if (Platform.isWindows()) { 54 return false; 55 } 56 return true; 57 58 } 59 60 // Returns true if the output indicates that the ccs is reserved anywhere. 61 static boolean isCCSReservedAnywhere(OutputAnalyzer output) { 62 if (output.getOutput().contains(reserveCCSAnywhere)) { 63 return true; 64 } else { 65 return false; 66 } 67 } 68 69 // CDS off, small heap, ccs size default (1G) 70 // A small heap should allow us to place the ccs within the lower 32G and thus allow zero based encoding. 71 public static void smallHeapTest() throws Exception { 72 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 73 "-XX:+UnlockDiagnosticVMOptions", 74 "-XX:SharedBaseAddress=8g", 75 "-Xmx128m", 76 logging_option, 77 "-Xshare:off", 78 "-XX:+VerifyBeforeGC", "-version"); 79 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 80 if (testNarrowKlassBase() && !isCCSReservedAnywhere(output)) { 81 output.shouldContain("Narrow klass base: 0x0000000000000000"); 82 } 83 output.shouldHaveExitValue(0); 84 } 85 86 // CDS off, small heap, ccs size explicitely set to 1G 87 // A small heap should allow us to place the ccs within the lower 32G and thus allow zero based encoding. 88 public static void smallHeapTestWith1G() throws Exception { 89 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 90 "-XX:+UnlockDiagnosticVMOptions", 91 "-XX:CompressedClassSpaceSize=1g", 92 "-Xmx128m", 93 logging_option, 94 "-Xshare:off", 95 "-XX:+VerifyBeforeGC", "-version"); 96 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 97 if (testNarrowKlassBase() && !isCCSReservedAnywhere(output)) { 98 output.shouldContain("Narrow klass base: 0x0000000000000000, Narrow klass shift: 3"); 99 } 100 output.shouldHaveExitValue(0); 101 } 102 103 // CDS off, a very large heap, ccs size left to 1G default. 104 // We expect the ccs to be mapped somewhere far beyond the heap, such that it is not possible 105 // to use zero based encoding. 106 public static void largeHeapTest() throws Exception { 107 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 108 "-XX:+UnlockDiagnosticVMOptions", 109 "-XX:+UnlockExperimentalVMOptions", 110 "-Xmx30g", 111 logging_option, 112 "-Xshare:off", 113 "-XX:+VerifyBeforeGC", "-version"); 114 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 115 if (testNarrowKlassBase() && !Platform.isPPC() && !Platform.isOSX() && !isCCSReservedAnywhere(output)) { 116 // PPC: in most cases the heap cannot be placed below 32g so there 117 // is room for ccs and narrow klass base will be 0x0. Exception: 118 // Linux 4.1.42 or earlier (see ELF_ET_DYN_BASE in JDK-8244847). 119 // For simplicity we exclude PPC. 120 // OSX: similar. 121 output.shouldNotContain("Narrow klass base: 0x0000000000000000"); 122 output.shouldContain("Narrow klass shift: 0"); 123 } 124 output.shouldHaveExitValue(0); 125 } 126 127 // Settings as in largeHeapTest() except for max heap size. We make max heap 128 // size even larger such that it cannot fit into lower 32G but not too large 129 // for compressed oops. 130 // We expect a zerobased ccs. 131 public static void largeHeapAbove32GTest() throws Exception { 132 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 133 "-XX:+UnlockDiagnosticVMOptions", 134 "-XX:+UnlockExperimentalVMOptions", 135 "-Xmx31g", 136 logging_option, 137 "-Xshare:off", 138 "-XX:+VerifyBeforeGC", "-version"); 139 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 140 if (testNarrowKlassBase()) { 141 if (!(Platform.isAArch64() && Platform.isOSX()) && !isCCSReservedAnywhere(output)) { // see JDK-8262895 142 output.shouldContain("Narrow klass base: 0x0000000000000000"); 143 if (!Platform.isAArch64() && !Platform.isPPC() && !Platform.isOSX()) { 144 output.shouldContain("Narrow klass shift: 0"); 145 } 146 } 147 } 148 output.shouldHaveExitValue(0); 149 } 150 151 // Using large paged heap, metaspace uses small pages. 152 public static void largePagesForHeapTest() throws Exception { 153 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 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.createLimitedTestJavaProcessBuilder( 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.createLimitedTestJavaProcessBuilder( 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.createLimitedTestJavaProcessBuilder( 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 public static void smallHeapTestNoCoop() throws Exception { 213 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 214 "-XX:-UseCompressedOops", 215 "-XX:+UseCompressedClassPointers", 216 "-XX:+UnlockDiagnosticVMOptions", 217 "-XX:SharedBaseAddress=8g", 218 "-Xmx128m", 219 "-Xlog:gc+metaspace=trace", 220 "-Xshare:off", 221 "-Xlog:cds=trace", 222 "-XX:+VerifyBeforeGC", "-version"); 223 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 224 if (!isCCSReservedAnywhere(output)) { 225 output.shouldContain("Narrow klass base: 0x0000000000000000"); 226 } 227 output.shouldHaveExitValue(0); 228 } 229 230 public static void smallHeapTestWith1GNoCoop() throws Exception { 231 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 232 "-XX:-UseCompressedOops", 233 "-XX:+UseCompressedClassPointers", 234 "-XX:+UnlockDiagnosticVMOptions", 235 "-XX:CompressedClassSpaceSize=1g", 236 "-Xmx128m", 237 "-Xlog:gc+metaspace=trace", 238 "-Xshare:off", 239 "-Xlog:cds=trace", 240 "-XX:+VerifyBeforeGC", "-version"); 241 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 242 if (!isCCSReservedAnywhere(output)) { 243 output.shouldContain("Narrow klass base: 0x0000000000000000"); 244 } 245 if (!Platform.isAArch64() && !Platform.isPPC()) { 246 // Currently relax this test for Aarch64 and ppc. 247 output.shouldContain("Narrow klass shift: 0"); 248 } 249 output.shouldHaveExitValue(0); 250 } 251 252 public static void largeHeapTestNoCoop() throws Exception { 253 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 254 "-XX:-UseCompressedOops", 255 "-XX:+UseCompressedClassPointers", 256 "-XX:+UnlockDiagnosticVMOptions", 257 "-XX:+UnlockExperimentalVMOptions", 258 "-Xmx30g", 259 "-Xlog:gc+metaspace=trace", 260 "-Xshare:off", 261 "-Xlog:cds=trace", 262 "-XX:+VerifyBeforeGC", "-version"); 263 OutputAnalyzer output = new OutputAnalyzer(pb.start()); 264 if (!isCCSReservedAnywhere(output)) { 265 output.shouldContain("Narrow klass base: 0x0000000000000000"); 266 } 267 if (!Platform.isAArch64() && !Platform.isPPC()) { 268 // Currently relax this test for Aarch64 and ppc. 269 output.shouldContain("Narrow klass shift: 0"); 270 } 271 output.shouldHaveExitValue(0); 272 } 273 274 public static void largePagesTestNoCoop() throws Exception { 275 ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( 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.createLimitedTestJavaProcessBuilder( 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.createLimitedTestJavaProcessBuilder( 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.createLimitedTestJavaProcessBuilder( 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 smallHeapTestNoCoop(); 350 smallHeapTestWith1GNoCoop(); 351 largeHeapTestNoCoop(); 352 largePagesTestNoCoop(); 353 heapBaseMinAddressTestNoCoop(); 354 sharingTestNoCoop(); 355 } 356 }