1 /* 2 * Copyright (c) 2016, 2024, 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 package requires; 25 26 import java.io.BufferedInputStream; 27 import java.io.FileInputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.File; 31 import java.nio.charset.Charset; 32 import java.nio.file.Files; 33 import java.nio.file.Path; 34 import java.nio.file.Paths; 35 import java.nio.file.StandardOpenOption; 36 import java.time.Instant; 37 import java.util.ArrayList; 38 import java.util.Collections; 39 import java.util.HashMap; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.Properties; 43 import java.util.Set; 44 import java.util.concurrent.Callable; 45 import java.util.concurrent.TimeUnit; 46 import java.util.function.Predicate; 47 import java.util.function.Supplier; 48 import java.util.regex.Matcher; 49 import java.util.regex.Pattern; 50 import java.util.stream.Stream; 51 52 import jdk.internal.foreign.CABI; 53 import jdk.test.whitebox.code.Compiler; 54 import jdk.test.whitebox.cpuinfo.CPUInfo; 55 import jdk.test.whitebox.gc.GC; 56 import jdk.test.whitebox.WhiteBox; 57 import jdk.test.lib.Platform; 58 import jdk.test.lib.Container; 59 60 /** 61 * The Class to be invoked by jtreg prior Test Suite execution to 62 * collect information about VM. 63 * Do not use any APIs that may not be available in all target VMs. 64 * Properties set by this Class will be available in the @requires expressions. 65 */ 66 public class VMProps implements Callable<Map<String, String>> { 67 // value known to jtreg as an indicator of error state 68 private static final String ERROR_STATE = "__ERROR__"; 69 70 private static final String GC_PREFIX = "-XX:+Use"; 71 private static final String GC_SUFFIX = "GC"; 72 73 private static final WhiteBox WB = WhiteBox.getWhiteBox(); 74 75 private static class SafeMap { 76 private final Map<String, String> map = new HashMap<>(); 77 78 public void put(String key, Supplier<String> s) { 79 String value; 80 try { 81 value = s.get(); 82 } catch (Throwable t) { 83 System.err.println("failed to get value for " + key); 84 t.printStackTrace(System.err); 85 value = ERROR_STATE + t; 86 } 87 map.put(key, value); 88 } 89 } 90 91 /** 92 * Collects information about VM properties. 93 * This method will be invoked by jtreg. 94 * 95 * @return Map of property-value pairs. 96 */ 97 @Override 98 public Map<String, String> call() { 99 log("Entering call()"); 100 SafeMap map = new SafeMap(); 101 map.put("vm.flavor", this::vmFlavor); 102 map.put("vm.compMode", this::vmCompMode); 103 map.put("vm.bits", this::vmBits); 104 map.put("vm.flightRecorder", this::vmFlightRecorder); 105 map.put("vm.simpleArch", this::vmArch); 106 map.put("vm.debug", this::vmDebug); 107 map.put("vm.jvmci", this::vmJvmci); 108 map.put("vm.jvmci.enabled", this::vmJvmciEnabled); 109 map.put("vm.emulatedClient", this::vmEmulatedClient); 110 // vm.hasSA is "true" if the VM contains the serviceability agent 111 // and jhsdb. 112 map.put("vm.hasSA", this::vmHasSA); 113 // vm.hasJFR is "true" if JFR is included in the build of the VM and 114 // so tests can be executed. 115 map.put("vm.hasJFR", this::vmHasJFR); 116 map.put("vm.hasDTrace", this::vmHasDTrace); 117 map.put("vm.jvmti", this::vmHasJVMTI); 118 map.put("vm.cpu.features", this::cpuFeatures); 119 map.put("vm.pageSize", this::vmPageSize); 120 map.put("vm.rtm.cpu", this::vmRTMCPU); 121 map.put("vm.rtm.compiler", this::vmRTMCompiler); 122 // vm.cds is true if the VM is compiled with cds support. 123 map.put("vm.cds", this::vmCDS); 124 map.put("vm.cds.custom.loaders", this::vmCDSForCustomLoaders); 125 map.put("vm.cds.supports.aot.class.linking", this::vmCDSSupportsAOTClassLinking); 126 map.put("vm.cds.write.archived.java.heap", this::vmCDSCanWriteArchivedJavaHeap); 127 map.put("vm.continuations", this::vmContinuations); 128 // vm.graal.enabled is true if Graal is used as JIT 129 map.put("vm.graal.enabled", this::isGraalEnabled); 130 // jdk.hasLibgraal is true if the libgraal shared library file is present 131 map.put("jdk.hasLibgraal", this::hasLibgraal); 132 map.put("vm.libgraal.jit", this::isLibgraalJIT); 133 map.put("vm.compiler1.enabled", this::isCompiler1Enabled); 134 map.put("vm.compiler2.enabled", this::isCompiler2Enabled); 135 map.put("docker.support", this::dockerSupport); 136 map.put("systemd.support", this::systemdSupport); 137 map.put("vm.musl", this::isMusl); 138 map.put("release.implementor", this::implementor); 139 map.put("jdk.containerized", this::jdkContainerized); 140 map.put("vm.flagless", this::isFlagless); 141 map.put("jdk.foreign.linker", this::jdkForeignLinker); 142 vmGC(map); // vm.gc.X = true/false 143 vmGCforCDS(map); // may set vm.gc 144 vmOptFinalFlags(map); 145 146 dump(map.map); 147 log("Leaving call()"); 148 return map.map; 149 } 150 151 /** 152 * Print a stack trace before returning error state; 153 * Used by the various helper functions which parse information from 154 * VM properties in the case where they don't find an expected property 155 * or a property doesn't conform to an expected format. 156 * 157 * @return {@link #ERROR_STATE} 158 */ 159 private String errorWithMessage(String message) { 160 new Exception(message).printStackTrace(); 161 return ERROR_STATE + message; 162 } 163 164 /** 165 * @return vm.simpleArch value of "os.simpleArch" property of tested JDK. 166 */ 167 protected String vmArch() { 168 String arch = System.getProperty("os.arch"); 169 if (arch.equals("x86_64") || arch.equals("amd64")) { 170 return "x64"; 171 } else if (arch.contains("86")) { 172 return "x86"; 173 } else { 174 return arch; 175 } 176 } 177 178 /** 179 * @return VM type value extracted from the "java.vm.name" property. 180 */ 181 protected String vmFlavor() { 182 // E.g. "Java HotSpot(TM) 64-Bit Server VM" 183 String vmName = System.getProperty("java.vm.name"); 184 if (vmName == null) { 185 return errorWithMessage("Can't get 'java.vm.name' property"); 186 } 187 188 Pattern startP = Pattern.compile(".* (\\S+) VM"); 189 Matcher m = startP.matcher(vmName); 190 if (m.matches()) { 191 return m.group(1).toLowerCase(); 192 } 193 return errorWithMessage("Can't get VM flavor from 'java.vm.name'"); 194 } 195 196 /** 197 * @return VM compilation mode extracted from the "java.vm.info" property. 198 */ 199 protected String vmCompMode() { 200 // E.g. "mixed mode" 201 String vmInfo = System.getProperty("java.vm.info"); 202 if (vmInfo == null) { 203 return errorWithMessage("Can't get 'java.vm.info' property"); 204 } 205 vmInfo = vmInfo.toLowerCase(); 206 if (vmInfo.contains("mixed mode")) { 207 return "Xmixed"; 208 } else if (vmInfo.contains("compiled mode")) { 209 return "Xcomp"; 210 } else if (vmInfo.contains("interpreted mode")) { 211 return "Xint"; 212 } else { 213 return errorWithMessage("Can't get compilation mode from 'java.vm.info'"); 214 } 215 } 216 217 /** 218 * @return VM bitness, the value of the "sun.arch.data.model" property. 219 */ 220 protected String vmBits() { 221 String dataModel = System.getProperty("sun.arch.data.model"); 222 if (dataModel != null) { 223 return dataModel; 224 } else { 225 return errorWithMessage("Can't get 'sun.arch.data.model' property"); 226 } 227 } 228 229 /** 230 * @return "true" if Flight Recorder is enabled, "false" if is disabled. 231 */ 232 protected String vmFlightRecorder() { 233 Boolean isFlightRecorder = WB.getBooleanVMFlag("FlightRecorder"); 234 String startFROptions = WB.getStringVMFlag("StartFlightRecording"); 235 if (isFlightRecorder != null && isFlightRecorder) { 236 return "true"; 237 } 238 if (startFROptions != null && !startFROptions.isEmpty()) { 239 return "true"; 240 } 241 return "false"; 242 } 243 244 /** 245 * @return debug level value extracted from the "jdk.debug" property. 246 */ 247 protected String vmDebug() { 248 String debug = System.getProperty("jdk.debug"); 249 if (debug != null) { 250 return "" + debug.contains("debug"); 251 } else { 252 return errorWithMessage("Can't get 'jdk.debug' property"); 253 } 254 } 255 256 /** 257 * @return true if VM supports JVMCI and false otherwise 258 */ 259 protected String vmJvmci() { 260 // builds with jvmci have this flag 261 if (WB.getBooleanVMFlag("EnableJVMCI") == null) { 262 return "false"; 263 } 264 265 // Not all GCs have full JVMCI support 266 if (!WB.isJVMCISupportedByGC()) { 267 return "false"; 268 } 269 270 // Interpreted mode cannot enable JVMCI 271 if (vmCompMode().equals("Xint")) { 272 return "false"; 273 } 274 275 return "true"; 276 } 277 278 279 /** 280 * @return true if JVMCI is enabled 281 */ 282 protected String vmJvmciEnabled() { 283 // builds with jvmci have this flag 284 if ("false".equals(vmJvmci())) { 285 return "false"; 286 } 287 288 return "" + Compiler.isJVMCIEnabled(); 289 } 290 291 292 /** 293 * @return true if VM runs in emulated-client mode and false otherwise. 294 */ 295 protected String vmEmulatedClient() { 296 String vmInfo = System.getProperty("java.vm.info"); 297 if (vmInfo == null) { 298 return errorWithMessage("Can't get 'java.vm.info' property"); 299 } 300 return "" + vmInfo.contains(" emulated-client"); 301 } 302 303 /** 304 * @return supported CPU features 305 */ 306 protected String cpuFeatures() { 307 return CPUInfo.getFeatures().toString(); 308 } 309 310 /** 311 * For all existing GC sets vm.gc.X property. 312 * Example vm.gc.G1=true means: 313 * VM supports G1 314 * User either set G1 explicitely (-XX:+UseG1GC) or did not set any GC 315 * G1 can be selected, i.e. it doesn't conflict with other VM flags 316 * 317 * @param map - property-value pairs 318 */ 319 protected void vmGC(SafeMap map) { 320 var isJVMCIEnabled = Compiler.isJVMCIEnabled(); 321 Predicate<GC> vmGCProperty = (GC gc) -> (gc.isSupported() 322 && (!isJVMCIEnabled || gc.isSupportedByJVMCICompiler()) 323 && (gc.isSelected() || GC.isSelectedErgonomically())); 324 for (GC gc: GC.values()) { 325 map.put("vm.gc." + gc.name(), () -> "" + vmGCProperty.test(gc)); 326 } 327 328 // Special handling for ZGC modes 329 var vmGCZ = vmGCProperty.test(GC.Z); 330 var genZ = WB.getBooleanVMFlag("ZGenerational"); 331 var genZIsDefault = WB.isDefaultVMFlag("ZGenerational"); 332 // vm.gc.ZGenerational=true means: 333 // vm.gc.Z is true and ZGenerational is either explicitly true, or default 334 map.put("vm.gc.ZGenerational", () -> "" + (vmGCZ && (genZ || genZIsDefault))); 335 // vm.gc.ZSinglegen=true means: 336 // vm.gc.Z is true and ZGenerational is either explicitly false, or default 337 map.put("vm.gc.ZSinglegen", () -> "" + (vmGCZ && (!genZ || genZIsDefault))); 338 } 339 340 /** 341 * "jtreg -vmoptions:-Dtest.cds.runtime.options=..." can be used to specify 342 * the GC type to be used when running with a CDS archive. Set "vm.gc" accordingly, 343 * so that tests that need to explicitly choose the GC type can be excluded 344 * with "@requires vm.gc == null". 345 * 346 * @param map - property-value pairs 347 */ 348 protected void vmGCforCDS(SafeMap map) { 349 if (!GC.isSelectedErgonomically()) { 350 // The GC has been explicitly specified on the command line, so 351 // jtreg will set the "vm.gc" property. Let's not interfere with it. 352 return; 353 } 354 355 String jtropts = System.getProperty("test.cds.runtime.options"); 356 if (jtropts != null) { 357 for (String opt : jtropts.split(",")) { 358 if (opt.startsWith(GC_PREFIX) && opt.endsWith(GC_SUFFIX)) { 359 String gc = opt.substring(GC_PREFIX.length(), opt.length() - GC_SUFFIX.length()); 360 map.put("vm.gc", () -> gc); 361 } 362 } 363 } 364 } 365 366 /** 367 * Selected final flag. 368 * 369 * @param map - property-value pairs 370 * @param flagName - flag name 371 */ 372 private void vmOptFinalFlag(SafeMap map, String flagName) { 373 map.put("vm.opt.final." + flagName, 374 () -> String.valueOf(WB.getBooleanVMFlag(flagName))); 375 } 376 377 /** 378 * Selected sets of final flags. 379 * 380 * @param map - property-value pairs 381 */ 382 protected void vmOptFinalFlags(SafeMap map) { 383 vmOptFinalFlag(map, "ClassUnloading"); 384 vmOptFinalFlag(map, "ClassUnloadingWithConcurrentMark"); 385 vmOptFinalFlag(map, "CriticalJNINatives"); 386 vmOptFinalFlag(map, "EnableJVMCI"); 387 vmOptFinalFlag(map, "EliminateAllocations"); 388 vmOptFinalFlag(map, "UnlockExperimentalVMOptions"); 389 vmOptFinalFlag(map, "UseCompressedOops"); 390 vmOptFinalFlag(map, "UseLargePages"); 391 vmOptFinalFlag(map, "UseVectorizedMismatchIntrinsic"); 392 vmOptFinalFlag(map, "ZGenerational"); 393 } 394 395 /** 396 * @return "true" if VM has a serviceability agent. 397 */ 398 protected String vmHasSA() { 399 return "" + Platform.hasSA(); 400 } 401 402 /** 403 * @return "true" if the VM is compiled with Java Flight Recorder (JFR) 404 * support. 405 */ 406 protected String vmHasJFR() { 407 return "" + WB.isJFRIncluded(); 408 } 409 410 /** 411 * @return "true" if the VM is compiled with JVMTI 412 */ 413 protected String vmHasJVMTI() { 414 return "" + WB.isJVMTIIncluded(); 415 } 416 417 /** 418 * @return "true" if the VM is compiled with DTrace 419 */ 420 protected String vmHasDTrace() { 421 return "" + WB.isDTraceIncluded(); 422 } 423 424 /** 425 * @return "true" if compiler in use supports RTM and "false" otherwise. 426 * Note: Lightweight locking does not support RTM (for now). 427 */ 428 protected String vmRTMCompiler() { 429 boolean isRTMCompiler = false; 430 431 if (Compiler.isC2Enabled() && 432 (Platform.isX86() || Platform.isX64() || Platform.isPPC()) && 433 is_LM_LIGHTWEIGHT().equals("false")) { 434 isRTMCompiler = true; 435 } 436 return "" + isRTMCompiler; 437 } 438 439 /** 440 * @return true if VM runs RTM supported CPU and false otherwise. 441 */ 442 protected String vmRTMCPU() { 443 return "" + CPUInfo.hasFeature("rtm"); 444 } 445 446 /** 447 * Check for CDS support. 448 * 449 * @return true if CDS is supported by the VM to be tested. 450 */ 451 protected String vmCDS() { 452 return "" + WB.isCDSIncluded(); 453 } 454 455 /** 456 * Check for CDS support for custom loaders. 457 * 458 * @return true if CDS provides support for customer loader in the VM to be tested. 459 */ 460 protected String vmCDSForCustomLoaders() { 461 return "" + ("true".equals(vmCDS()) && Platform.areCustomLoadersSupportedForCDS()); 462 } 463 464 /** 465 * @return true if this VM can write Java heap objects into the CDS archive 466 */ 467 protected String vmCDSCanWriteArchivedJavaHeap() { 468 return "" + ("true".equals(vmCDS()) && WB.canWriteJavaHeapArchive() 469 && isCDSRuntimeOptionsCompatible()); 470 } 471 472 /** 473 * @return true if this VM can support the -XX:AOTClassLinking option 474 */ 475 protected String vmCDSSupportsAOTClassLinking() { 476 // Currently, the VM supports AOTClassLinking as long as it's able to write archived java heap. 477 return vmCDSCanWriteArchivedJavaHeap(); 478 } 479 480 /** 481 * @return true if the VM options specified via the "test.cds.runtime.options" 482 * property is compatible with writing Java heap objects into the CDS archive 483 */ 484 protected boolean isCDSRuntimeOptionsCompatible() { 485 String jtropts = System.getProperty("test.cds.runtime.options"); 486 if (jtropts == null) { 487 return true; 488 } 489 String CCP_DISABLED = "-XX:-UseCompressedClassPointers"; 490 String G1GC_ENABLED = "-XX:+UseG1GC"; 491 String PARALLELGC_ENABLED = "-XX:+UseParallelGC"; 492 String SERIALGC_ENABLED = "-XX:+UseSerialGC"; 493 for (String opt : jtropts.split(",")) { 494 if (opt.equals(CCP_DISABLED)) { 495 return false; 496 } 497 if (opt.startsWith(GC_PREFIX) && opt.endsWith(GC_SUFFIX) && 498 !opt.equals(G1GC_ENABLED) && !opt.equals(PARALLELGC_ENABLED) && !opt.equals(SERIALGC_ENABLED)) { 499 return false; 500 } 501 } 502 return true; 503 } 504 505 /** 506 * @return "true" if this VM supports continuations. 507 */ 508 protected String vmContinuations() { 509 if (WB.getBooleanVMFlag("VMContinuations")) { 510 return "true"; 511 } else { 512 return "false"; 513 } 514 } 515 516 /** 517 * @return System page size in bytes. 518 */ 519 protected String vmPageSize() { 520 return "" + WB.getVMPageSize(); 521 } 522 523 /** 524 * @return LockingMode. 525 */ 526 protected String vmLockingMode() { 527 return "" + WB.getIntVMFlag("LockingMode"); 528 } 529 530 /** 531 * @return "true" if LockingMode == 0 (LM_MONITOR) 532 */ 533 protected String is_LM_MONITOR() { 534 return "" + vmLockingMode().equals("0"); 535 } 536 537 /** 538 * @return "true" if LockingMode == 1 (LM_LEGACY) 539 */ 540 protected String is_LM_LEGACY() { 541 return "" + vmLockingMode().equals("1"); 542 } 543 544 /** 545 * @return "true" if LockingMode == 2 (LM_LIGHTWEIGHT) 546 */ 547 protected String is_LM_LIGHTWEIGHT() { 548 return "" + vmLockingMode().equals("2"); 549 } 550 551 /** 552 * Check if Graal is used as JIT compiler. 553 * 554 * @return true if Graal is used as JIT compiler. 555 */ 556 protected String isGraalEnabled() { 557 return "" + Compiler.isGraalEnabled(); 558 } 559 560 /** 561 * Check if the libgraal shared library file is present. 562 * 563 * @return true if the libgraal shared library file is present. 564 */ 565 protected String hasLibgraal() { 566 return "" + WB.hasLibgraal(); 567 } 568 569 /** 570 * Check if libgraal is used as JIT compiler. 571 * 572 * @return true if libgraal is used as JIT compiler. 573 */ 574 protected String isLibgraalJIT() { 575 return "" + Compiler.isLibgraalJIT(); 576 } 577 578 /** 579 * Check if Compiler1 is present. 580 * 581 * @return true if Compiler1 is used as JIT compiler, either alone or as part of the tiered system. 582 */ 583 protected String isCompiler1Enabled() { 584 return "" + Compiler.isC1Enabled(); 585 } 586 587 /** 588 * Check if Compiler2 is present. 589 * 590 * @return true if Compiler2 is used as JIT compiler, either alone or as part of the tiered system. 591 */ 592 protected String isCompiler2Enabled() { 593 return "" + Compiler.isC2Enabled(); 594 } 595 596 /** 597 * A simple check for docker support 598 * 599 * @return true if docker is supported in a given environment 600 */ 601 protected String dockerSupport() { 602 log("Entering dockerSupport()"); 603 604 boolean isSupported = false; 605 if (Platform.isLinux()) { 606 // currently docker testing is only supported for Linux, 607 // on certain platforms 608 609 String arch = System.getProperty("os.arch"); 610 611 if (Platform.isX64()) { 612 isSupported = true; 613 } else if (Platform.isAArch64()) { 614 isSupported = true; 615 } else if (Platform.isS390x()) { 616 isSupported = true; 617 } else if (arch.equals("ppc64le")) { 618 isSupported = true; 619 } 620 } 621 622 log("dockerSupport(): platform check: isSupported = " + isSupported); 623 624 if (isSupported) { 625 try { 626 isSupported = checkProgramSupport("checkDockerSupport()", Container.ENGINE_COMMAND); 627 } catch (Exception e) { 628 isSupported = false; 629 } 630 } 631 632 log("dockerSupport(): returning isSupported = " + isSupported); 633 return "" + isSupported; 634 } 635 636 /** 637 * A simple check for systemd support 638 * 639 * @return true if systemd is supported in a given environment 640 */ 641 protected String systemdSupport() { 642 log("Entering systemdSupport()"); 643 644 boolean isSupported = Platform.isLinux(); 645 if (isSupported) { 646 try { 647 isSupported = checkProgramSupport("checkSystemdSupport()", "systemd-run"); 648 } catch (Exception e) { 649 isSupported = false; 650 } 651 } 652 653 log("systemdSupport(): returning isSupported = " + isSupported); 654 return "" + isSupported; 655 } 656 657 // Configures process builder to redirect process stdout and stderr to a file. 658 // Returns file names for stdout and stderr. 659 private Map<String, String> redirectOutputToLogFile(String msg, ProcessBuilder pb, String fileNameBase) { 660 Map<String, String> result = new HashMap<>(); 661 String timeStamp = Instant.now().toString().replace(":", "-").replace(".", "-"); 662 663 String stdoutFileName = String.format("./%s-stdout--%s.log", fileNameBase, timeStamp); 664 pb.redirectOutput(new File(stdoutFileName)); 665 log(msg + ": child process stdout redirected to " + stdoutFileName); 666 result.put("stdout", stdoutFileName); 667 668 String stderrFileName = String.format("./%s-stderr--%s.log", fileNameBase, timeStamp); 669 pb.redirectError(new File(stderrFileName)); 670 log(msg + ": child process stderr redirected to " + stderrFileName); 671 result.put("stderr", stderrFileName); 672 673 return result; 674 } 675 676 private void printLogfileContent(Map<String, String> logFileNames) { 677 logFileNames.entrySet().stream() 678 .forEach(entry -> 679 { 680 log("------------- " + entry.getKey()); 681 try { 682 Files.lines(Path.of(entry.getValue())) 683 .forEach(line -> log(line)); 684 } catch (IOException ie) { 685 log("Exception while reading file: " + ie); 686 } 687 log("-------------"); 688 }); 689 } 690 691 private boolean checkProgramSupport(String logString, String cmd) throws IOException, InterruptedException { 692 log(logString + ": entering"); 693 ProcessBuilder pb = new ProcessBuilder("which", cmd); 694 Map<String, String> logFileNames = 695 redirectOutputToLogFile(logString + ": which " + cmd, 696 pb, "which-cmd"); 697 Process p = pb.start(); 698 p.waitFor(10, TimeUnit.SECONDS); 699 int exitValue = p.exitValue(); 700 701 log(String.format("%s: exitValue = %s, pid = %s", logString, exitValue, p.pid())); 702 if (exitValue != 0) { 703 printLogfileContent(logFileNames); 704 } 705 706 return (exitValue == 0); 707 } 708 709 /** 710 * Checks musl libc. 711 * 712 * @return true if musl libc is used. 713 */ 714 protected String isMusl() { 715 return Boolean.toString(WB.getLibcName().contains("musl")); 716 } 717 718 private String implementor() { 719 try (InputStream in = new BufferedInputStream(new FileInputStream( 720 System.getProperty("java.home") + "/release"))) { 721 Properties properties = new Properties(); 722 properties.load(in); 723 String implementorProperty = properties.getProperty("IMPLEMENTOR"); 724 if (implementorProperty != null) { 725 return implementorProperty.replace("\"", ""); 726 } 727 return errorWithMessage("Can't get 'IMPLEMENTOR' property from 'release' file"); 728 } catch (IOException e) { 729 e.printStackTrace(); 730 return errorWithMessage("Failed to read 'release' file " + e); 731 } 732 } 733 734 private String jdkContainerized() { 735 String isEnabled = System.getenv("TEST_JDK_CONTAINERIZED"); 736 return "" + "true".equalsIgnoreCase(isEnabled); 737 } 738 739 /** 740 * Checks if we are in <i>almost</i> out-of-box configuration, i.e. the flags 741 * which JVM is started with don't affect its behavior "significantly". 742 * {@code TEST_VM_FLAGLESS} enviroment variable can be used to force this 743 * method to return true or false and allow or reject any flags. 744 * 745 * @return true if there are no JVM flags 746 */ 747 private String isFlagless() { 748 boolean result = true; 749 String flagless = System.getenv("TEST_VM_FLAGLESS"); 750 if (flagless != null) { 751 return "" + "true".equalsIgnoreCase(flagless); 752 } 753 754 List<String> allFlags = allFlags().toList(); 755 756 // check -XX flags 757 var ignoredXXFlags = Set.of( 758 // added by run-test framework 759 "MaxRAMPercentage", 760 // added by test environment 761 "CreateCoredumpOnCrash" 762 ); 763 result &= allFlags.stream() 764 .filter(s -> s.startsWith("-XX:")) 765 // map to names: 766 // remove -XX: 767 .map(s -> s.substring(4)) 768 // remove +/- from bool flags 769 .map(s -> s.charAt(0) == '+' || s.charAt(0) == '-' ? s.substring(1) : s) 770 // remove =.* from others 771 .map(s -> s.contains("=") ? s.substring(0, s.indexOf('=')) : s) 772 // skip known-to-be-there flags 773 .filter(s -> !ignoredXXFlags.contains(s)) 774 .findAny() 775 .isEmpty(); 776 777 // check -X flags 778 var ignoredXFlags = Set.of( 779 // default, yet still seen to be explicitly set 780 "mixed", 781 // -XmxmNNNm added by run-test framework for non-hotspot tests 782 "mx" 783 ); 784 result &= allFlags.stream() 785 .filter(s -> s.startsWith("-X") && !s.startsWith("-XX:")) 786 // map to names: 787 // remove -X 788 .map(s -> s.substring(2)) 789 // remove :.* from flags with values 790 .map(s -> s.contains(":") ? s.substring(0, s.indexOf(':')) : s) 791 // remove size like 4G, 768m which might be set for non-hotspot tests 792 .map(s -> s.replaceAll("(\\d+)[mMgGkK]", "")) 793 // skip known-to-be-there flags 794 .filter(s -> !ignoredXFlags.contains(s)) 795 .findAny() 796 .isEmpty(); 797 798 return "" + result; 799 } 800 801 private Stream<String> allFlags() { 802 return Stream.of((System.getProperty("test.vm.opts", "") + " " + System.getProperty("test.java.opts", "")).trim().split("\\s+")); 803 } 804 805 /* 806 * A string indicating the foreign linker that is currently being used. See jdk.internal.foreign.CABI 807 * for valid values. 808 * 809 * "FALLBACK" and "UNSUPPORTED" are special values. The former indicates the fallback linker is 810 * being used. The latter indicates an unsupported platform. 811 */ 812 private String jdkForeignLinker() { 813 return String.valueOf(CABI.current()); 814 } 815 816 /** 817 * Dumps the map to the file if the file name is given as the property. 818 * This functionality could be helpful to know context in the real 819 * execution. 820 * 821 * @param map 822 */ 823 protected static void dump(Map<String, String> map) { 824 String dumpFileName = System.getProperty("vmprops.dump"); 825 if (dumpFileName == null) { 826 return; 827 } 828 List<String> lines = new ArrayList<>(); 829 map.forEach((k, v) -> lines.add(k + ":" + v)); 830 Collections.sort(lines); 831 try { 832 Files.write(Paths.get(dumpFileName), lines, 833 StandardOpenOption.APPEND, StandardOpenOption.CREATE); 834 } catch (IOException e) { 835 throw new RuntimeException("Failed to dump properties into '" 836 + dumpFileName + "'", e); 837 } 838 } 839 840 /** 841 * Log diagnostic message. 842 * 843 * @param msg 844 */ 845 protected static void log(String msg) { 846 // Always log to a file. 847 logToFile(msg); 848 849 // Also log to stderr; guarded by property to avoid excessive verbosity. 850 // By jtreg design stderr produced here will be visible 851 // in the output of a parent process. Note: stdout should not be used 852 // for logging as jtreg parses that output directly and only echoes it 853 // in the event of a failure. 854 if (Boolean.getBoolean("jtreg.log.vmprops")) { 855 System.err.println("VMProps: " + msg); 856 } 857 } 858 859 /** 860 * Log diagnostic message to a file. 861 * 862 * @param msg 863 */ 864 protected static void logToFile(String msg) { 865 String fileName = "./vmprops.log"; 866 try { 867 Files.writeString(Paths.get(fileName), msg + "\n", Charset.forName("ISO-8859-1"), 868 StandardOpenOption.APPEND, StandardOpenOption.CREATE); 869 } catch (IOException e) { 870 throw new RuntimeException("Failed to log into '" + fileName + "'", e); 871 } 872 } 873 874 /** 875 * This method is for the testing purpose only. 876 * 877 * @param args 878 */ 879 public static void main(String args[]) { 880 Map<String, String> map = new VMProps().call(); 881 map.forEach((k, v) -> System.out.println(k + ": '" + v + "'")); 882 } 883 }