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 }