1 /* 2 * Copyright (c) 2021, 2025, 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 compiler.lib.ir_framework; 25 26 import compiler.lib.ir_framework.driver.FlagVMProcess; 27 import compiler.lib.ir_framework.driver.TestVMException; 28 import compiler.lib.ir_framework.driver.TestVMProcess; 29 import compiler.lib.ir_framework.driver.irmatching.IRMatcher; 30 import compiler.lib.ir_framework.driver.irmatching.IRViolationException; 31 import compiler.lib.ir_framework.driver.irmatching.Matchable; 32 import compiler.lib.ir_framework.driver.irmatching.parser.TestClassParser; 33 import compiler.lib.ir_framework.shared.*; 34 import compiler.lib.ir_framework.test.TestVM; 35 import jdk.test.lib.Platform; 36 import jdk.test.lib.Utils; 37 import jdk.test.lib.helpers.ClassFileInstaller; 38 import jdk.test.whitebox.WhiteBox; 39 40 import java.io.PrintWriter; 41 import java.io.StringWriter; 42 import java.lang.reflect.Method; 43 import java.net.MalformedURLException; 44 import java.net.URL; 45 import java.net.URLClassLoader; 46 import java.nio.file.Path; 47 import java.util.*; 48 import java.util.stream.Collectors; 49 50 /** 51 * This class represents the main entry point to the test framework whose main purpose is to perform regex-based checks on 52 * the C2 IR shape emitted by the VM flags {@code -XX:+PrintIdeal} and {@code -XX:+PrintOptoAssembly}. The framework can 53 * also be used for other non-IR matching (and non-compiler) tests by providing easy to use annotations for commonly used 54 * testing patterns and compiler control flags. 55 * <p> 56 * The framework offers various annotations to control how your test code should be invoked and being checked. There are 57 * three kinds of tests depending on how much control is needed over the test invocation: 58 * <b>Base tests</b> (see {@link Test}), <b>checked tests</b> (see {@link Check}), and <b>custom run tests</b> 59 * (see {@link Run}). Each type of test needs to define a unique <i>test method</i> that specifies a {@link Test @Test} 60 * annotation which represents the test code that is eventually executed by the test framework. More information about 61 * the usage and how to write different tests can be found in {@link Test}, {@link Check}, and {@link Run}. 62 * <p> 63 * Each test method can specify an arbitrary number of IR rules. This is done by using {@link IR @IR} annotations which 64 * can define regex strings that are matched on the output of {@code -XX:+PrintIdeal} and {@code -XX:+PrintOptoAssembly}. 65 * The matching is done after the test method was (optionally) warmed up and compiled. More information about the usage 66 * and how to write different IR rules can be found at {@link IR}. 67 * <p> 68 * This framework should be used with the following JTreg setup in your Test.java file in package <i>some.package</i>: 69 * <pre> 70 * {@literal @}library /test/lib 71 * {@literal @}run driver some.package.Test 72 * </pre> 73 * Note that even though the framework uses the Whitebox API internally, it is not required to build and enabel it in the 74 * JTreg test if the test itself is not utilizing any Whitebox features directly. 75 * <p> 76 * To specify additional flags, use {@link #runWithFlags(String...)}, {@link #addFlags(String...)}, or 77 * {@link #addScenarios(Scenario...)} where the scenarios can also be used to run different flag combinations 78 * (instead of specifying multiple JTreg {@code @run} entries). 79 * <p> 80 * After annotating your test code with the framework specific annotations, the framework needs to be invoked from the 81 * {@code main()} method of your JTreg test. There are two ways to do so. The first way is by calling the various 82 * {@code runXX()} methods of {@link TestFramework}. The second way, which gives more control, is to create a new 83 * {@code TestFramework} builder object on which {@link #start()} needs to be eventually called to start the testing. 84 * <p> 85 * The framework is called from the <i>driver VM</i> in which the JTreg test is initially run by specifying {@code 86 * @run driver} in the JTreg header. This strips all additionally specified JTreg VM and Javaoptions. 87 * The framework creates a new <i>flag VM</i> with all these flags added again in order to figure out which flags are 88 * required to run the tests specified in the test class (e.g. {@code -XX:+PrintIdeal} and {@code -XX:+PrintOptoAssembly} 89 * for IR matching). 90 * <p> 91 * After the flag VM terminates, it starts a new <i>test VM</i> which performs the execution of the specified 92 * tests in the test class as described in {@link Test}, {@link Check}, and {@link Run}. 93 * <p> 94 * In a last step, once the test VM has terminated without exceptions, IR matching is performed if there are any IR 95 * rules and if no VM flags disable it (e.g. not running with {@code -Xint}, see {@link IR} for more details). 96 * The IR regex matching is done on the output of {@code -XX:+PrintIdeal} and {@code -XX:+PrintOptoAssembly} by parsing 97 * the hotspot_pid file of the test VM. Failing IR rules are reported by throwing a {@link IRViolationException}. 98 * 99 * @see Test 100 * @see Check 101 * @see Run 102 * @see IR 103 */ 104 public class TestFramework { 105 /** 106 * JTreg can define additional VM (-Dtest.vm.opts) and Javaoptions (-Dtest.java.opts) flags. IR verification is only 107 * performed when all these additional JTreg flags (does not include additionally added framework and scenario flags 108 * by user code) are whitelisted. 109 * 110 * <p> 111 * A flag is whitelisted if it is a property flag (starting with -D), -ea, -esa, or if the flag name contains any of 112 * the entries of this list as a substring (partial match). 113 */ 114 public static final Set<String> JTREG_WHITELIST_FLAGS = new HashSet<>( 115 Arrays.asList( 116 // The following substrings are part of more than one VM flag 117 "RAM", 118 "Heap", 119 "Trace", 120 "Print", 121 "Verify", 122 "UseNewCode", 123 "Xmn", 124 "Xms", 125 "Xmx", 126 "Xss", 127 // The following substrings are only part of one VM flag (=exact match) 128 "CreateCoredumpOnCrash", 129 "IgnoreUnrecognizedVMOptions", 130 "UnlockDiagnosticVMOptions", 131 "UnlockExperimentalVMOptions", 132 "BackgroundCompilation", 133 "Xbatch", 134 "TieredCompilation", 135 "CompileThreshold", 136 "Xmixed", 137 "server", 138 "AlignVector", 139 "UseAVX", 140 "UseSSE", 141 "UseSVE", 142 "Xlog", 143 "LogCompilation", 144 "UseCompactObjectHeaders", 145 "UseFMA", 146 // Riscv 147 "UseRVV", 148 "UseZbb", 149 "UseZfh", 150 "UseZicond", 151 "UseZvbb" 152 ) 153 ); 154 155 public static final boolean VERBOSE = Boolean.getBoolean("Verbose"); 156 public static final boolean PRINT_RULE_MATCHING_TIME = Boolean.getBoolean("PrintRuleMatchingTime"); 157 public static final boolean TESTLIST = !System.getProperty("Test", "").isEmpty(); 158 public static final boolean EXCLUDELIST = !System.getProperty("Exclude", "").isEmpty(); 159 private static final boolean REPORT_STDOUT = Boolean.getBoolean("ReportStdout"); 160 // Only used for internal testing and should not be used for normal user testing. 161 162 private static final String RERUN_HINT = """ 163 ############################################################# 164 - To only run the failed tests use -DTest, -DExclude, 165 and/or -DScenarios. 166 - To also get the standard output of the test VM run with 167 -DReportStdout=true or for even more fine-grained logging 168 use -DVerbose=true. 169 ############################################################# 170 """ + System.lineSeparator(); 171 172 private boolean irVerificationPossible = Boolean.parseBoolean(System.getProperty("VerifyIR", "true")); 173 private boolean shouldVerifyIR; // Should we perform IR matching? 174 private static boolean toggleBool; 175 176 private final Class<?> testClass; 177 private Set<Class<?>> helperClasses; 178 private List<Scenario> scenarios; 179 private Set<Integer> scenarioIndices; 180 private List<String> flags; 181 private int defaultWarmup = -1; 182 private boolean testClassesOnBootClassPath; 183 private boolean isAllowNotCompilable = false; 184 185 /* 186 * Public interface methods 187 */ 188 189 /** 190 * Creates an instance acting as a builder to test the class from which this constructor was invoked from. 191 * Use this constructor if you want to use multiple run options (flags, helper classes, scenarios). 192 * Use the associated add methods ({@link #addFlags(String...)}, {@link #addScenarios(Scenario...)}, 193 * {@link #addHelperClasses(Class...)}) to set up everything and then start the testing by invoking {@link #start()}. 194 */ 195 public TestFramework() { 196 this(StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass()); 197 } 198 199 /** 200 * Creates an instance acting as a builder to test {@code testClass}. 201 * Use this constructor if you want to use multiple run options (flags, helper classes, scenarios). 202 * Use the associated add methods ({@link #addFlags(String...)}, {@link #addScenarios(Scenario...)}, 203 * {@link #addHelperClasses(Class...)}) to set up everything and then start the testing by invoking {@link #start()}. 204 * 205 * @param testClass the class to be tested by the framework. 206 * @see #TestFramework() 207 */ 208 public TestFramework(Class<?> testClass) { 209 TestRun.check(testClass != null, "Test class cannot be null"); 210 this.testClass = testClass; 211 if (VERBOSE) { 212 System.out.println("Test class: " + testClass); 213 } 214 } 215 216 /** 217 * Tests the class from which this method was invoked from. 218 */ 219 public static void run() { 220 StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); 221 run(walker.getCallerClass()); 222 } 223 224 /** 225 * Tests {@code testClass}. 226 * 227 * @param testClass the class to be tested by the framework. 228 * @see #run() 229 */ 230 public static void run(Class<?> testClass) { 231 TestFramework framework = new TestFramework(testClass); 232 framework.start(); 233 } 234 235 /** 236 * Tests the class from which this method was invoked from. The test VM is called with the specified {@code flags}. 237 * <ul> 238 * <li><p>The {@code flags} override any set VM or Javaoptions flags by JTreg by default.<p> 239 * Use {@code -DPreferCommandLineFlags=true} if you want to prefer the JTreg VM and Javaoptions flags over 240 * the specified {@code flags} of this method.</li> 241 * <li><p>If you want to run your entire JTreg test with additional flags, use this method.</li> 242 * <li><p>If you want to run your entire JTreg test with additional flags but for another test class then the one 243 * from which this method was called from, use {@link #addFlags(String...)}, use this method.</li> 244 * <li><p>If you want to run your JTreg test with multiple flag combinations, use 245 * {@link #addScenarios(Scenario...)}</li> 246 * </ul> 247 * 248 * @param flags VM flags to be used for the test VM. 249 */ 250 public static void runWithFlags(String... flags) { 251 StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); 252 TestFramework framework = new TestFramework(walker.getCallerClass()); 253 framework.addFlags(flags); 254 framework.start(); 255 } 256 257 /** 258 * Add VM flags to be used for the test VM. These flags override any VM or Javaoptions set by JTreg by default.<p> 259 * Use {@code -DPreferCommandLineFlags=true} if you want to prefer the VM or Javaoptions over the scenario flags. 260 * 261 * <p> 262 * The testing can be started by invoking {@link #start()} 263 * 264 * @param flags VM options to be applied to the test VM. 265 * @return the same framework instance. 266 */ 267 public TestFramework addFlags(String... flags) { 268 TestRun.check(flags != null && Arrays.stream(flags).noneMatch(Objects::isNull), "A flag cannot be null"); 269 if (this.flags == null) { 270 this.flags = new ArrayList<>(); 271 } 272 this.flags.addAll(Arrays.asList(flags)); 273 return this; 274 } 275 276 /** 277 * Add helper classes that can specify additional compile command annotations ({@link ForceCompile @ForceCompile}, 278 * {@link DontCompile @DontCompile}, {@link ForceInline @ForceInline}, {@link DontInline @DontInline}) to be applied 279 * while testing {@code testClass} (also see description of {@link TestFramework}). 280 * 281 * <p> 282 * Duplicates in {@code helperClasses} are ignored. If a class is used by the test class that does not specify any 283 * compile command annotations, you do not need to include it with this method. If no helper class specifies any 284 * compile commands, you do not need to call this method at all. 285 * 286 * <p> 287 * The testing can be started by invoking {@link #start()}. 288 * 289 * @param helperClasses helper classes containing compile command annotations ({@link ForceCompile}, 290 * {@link DontCompile}, {@link ForceInline}, {@link DontInline}) to be applied 291 * while testing {@code testClass} (also see description of {@link TestFramework}). 292 * @return the same framework instance. 293 */ 294 public TestFramework addHelperClasses(Class<?>... helperClasses) { 295 TestRun.check(helperClasses != null && Arrays.stream(helperClasses).noneMatch(Objects::isNull), 296 "A Helper class cannot be null"); 297 if (this.helperClasses == null) { 298 this.helperClasses = new HashSet<>(); 299 } 300 301 this.helperClasses.addAll(Arrays.asList(helperClasses)); 302 return this; 303 } 304 305 /** 306 * Add scenarios to be used for the test VM. A test VM is called for each scenario in {@code scenarios} by using the 307 * specified VM flags in the scenario. The scenario flags override any flags set by {@link #addFlags(String...)} 308 * and thus also override any VM or Javaoptions set by JTreg by default.<p> 309 * Use {@code -DPreferCommandLineFlags=true} if you want to prefer the VM and Javaoptions over the scenario flags. 310 * 311 * <p> 312 * The testing can be started by invoking {@link #start()} 313 * 314 * @param scenarios scenarios which specify specific flags for the test VM. 315 * @return the same framework instance. 316 */ 317 public TestFramework addScenarios(Scenario... scenarios) { 318 TestFormat.checkAndReport(scenarios != null && Arrays.stream(scenarios).noneMatch(Objects::isNull), 319 "A scenario cannot be null"); 320 if (this.scenarios == null) { 321 this.scenarios = new ArrayList<>(); 322 this.scenarioIndices = new HashSet<>(); 323 } 324 325 for (Scenario scenario : scenarios) { 326 int scenarioIndex = scenario.getIndex(); 327 TestFormat.checkNoThrow(scenarioIndices.add(scenarioIndex), 328 "Cannot define two scenarios with the same index " + scenarioIndex); 329 this.scenarios.add(scenario); 330 } 331 TestFormat.throwIfAnyFailures(); 332 return this; 333 } 334 335 /** 336 * Add test classes to boot classpath. This adds all classes found on path {@link jdk.test.lib.Utils#TEST_CLASSES} 337 * to the boot classpath with "-Xbootclasspath/a". This is useful when trying to run tests in a privileged mode. 338 */ 339 public TestFramework addTestClassesToBootClassPath() { 340 this.testClassesOnBootClassPath = true; 341 return this; 342 } 343 344 /** 345 * Start the testing of the implicitly (by {@link #TestFramework()}) or explicitly (by {@link #TestFramework(Class)}) 346 * set test class. 347 */ 348 public void start() { 349 if (shouldInstallWhiteBox()) { 350 installWhiteBox(); 351 } 352 checkIRRuleCompilePhasesFormat(); 353 disableIRVerificationIfNotFeasible(); 354 355 if (scenarios == null) { 356 try { 357 start(null); 358 } catch (TestVMException e) { 359 System.err.println(System.lineSeparator() + e.getExceptionInfo() + RERUN_HINT); 360 throw e; 361 } catch (IRViolationException e) { 362 System.out.println(e.getCompilations()); 363 System.err.println(System.lineSeparator() + e.getExceptionInfo() + System.lineSeparator() + RERUN_HINT); 364 throw e; 365 } 366 } else { 367 startWithScenarios(); 368 } 369 } 370 371 private void checkIRRuleCompilePhasesFormat() { 372 for (Method method : testClass.getDeclaredMethods()) { 373 for (IR irAnno : method.getAnnotationsByType(IR.class)) { 374 TestFormat.checkNoThrow(irAnno.phase().length > 0, 375 "@IR rule " + irAnno + " must specify a non-empty list of compile " + 376 "phases \"phase\" at " + method); 377 } 378 } 379 TestFormat.throwIfAnyFailures(); 380 } 381 382 /** 383 * Try to load the Whitebox class from the user directory with a custom class loader. If the user has already built the 384 * Whitebox, we can load it. Otherwise, the framework needs to install it. 385 * 386 * @return true if the framework needs to install the Whitebox 387 */ 388 private boolean shouldInstallWhiteBox() { 389 try { 390 URL url = Path.of(System.getProperty("user.dir")).toUri().toURL(); 391 URLClassLoader userDirClassLoader = 392 URLClassLoader.newInstance(new URL[] {url}, TestFramework.class.getClassLoader().getParent()); 393 Class.forName(WhiteBox.class.getName(), false, userDirClassLoader); 394 } catch (MalformedURLException e) { 395 throw new TestFrameworkException("corrupted user.dir property", e); 396 } catch (ClassNotFoundException e) { 397 // We need to manually install the WhiteBox if we cannot load the WhiteBox class from the user directory. 398 // This happens when the user test does not explicitly install the WhiteBox as part of the test. 399 return true; 400 } 401 return false; 402 } 403 404 /** 405 * Set a new default warm-up (overriding the framework default of 2000 at 406 * {@link TestVM#WARMUP_ITERATIONS}) to be applied for all tests that do not specify an explicit 407 * warm-up with {@link Warmup @Warmup}. 408 * 409 * @param defaultWarmup a new non-negative default warm-up. 410 * @return the same framework instance. 411 */ 412 public TestFramework setDefaultWarmup(int defaultWarmup) { 413 TestFormat.checkAndReport(defaultWarmup >= 0, "Cannot specify a negative default warm-up"); 414 this.defaultWarmup = defaultWarmup; 415 return this; 416 } 417 418 /** 419 * In rare cases, methods may not be compilable because of a compilation bailout. By default, this leads to a 420 * test failure. However, if such cases are expected in multiple methods in a test class, this flag can be set to 421 * true, which allows any test to pass even if there is a compilation bailout. If only selected methods are prone 422 * to bail out, it is preferred to use {@link Test#allowNotCompilable()} instead for more fine-grained control. 423 * By setting this flag, any associated {@link IR} rule of a test is only executed if the test method was compiled, 424 * and else it is ignored silently. 425 */ 426 public TestFramework allowNotCompilable() { 427 this.isAllowNotCompilable = true; 428 return this; 429 } 430 431 /** 432 * Get the VM output of the test VM. Use {@code -DVerbose=true} to enable more debug information. If scenarios 433 * were run, use {@link Scenario#getTestVMOutput()}. 434 * 435 * @return the last test VM output. 436 */ 437 public static String getLastTestVMOutput() { 438 return TestVMProcess.getLastTestVMOutput(); 439 } 440 441 /* 442 * The following methods are only intended to be called from actual @Test methods and not from the main() method of 443 * a JTreg test. Calling these methods from main() results in a linking exception (Whitebox not yet loaded and enabled). 444 */ 445 446 /** 447 * Compile {@code m} at compilation level {@code compLevel}. {@code m} is first enqueued and might not be compiled, 448 * yet, upon returning from this method. 449 * 450 * @param m the method to be compiled. 451 * @param compLevel the (valid) compilation level at which the method should be compiled. 452 * @throws TestRunException if compilation level is {@link CompLevel#SKIP} or {@link CompLevel#WAIT_FOR_COMPILATION}. 453 */ 454 public static void compile(Method m, CompLevel compLevel) { 455 TestVM.compile(m, compLevel); 456 } 457 458 /** 459 * Deoptimize {@code m}. 460 * 461 * @param m the method to be deoptimized. 462 */ 463 public static void deoptimize(Method m) { 464 TestVM.deoptimize(m); 465 } 466 467 /** 468 * Returns a boolean indicating if {@code m} is compiled at any level. 469 * 470 * @param m the method to be checked. 471 * @return {@code true} if {@code m} is compiled at any level; 472 * {@code false} otherwise. 473 */ 474 public static boolean isCompiled(Method m) { 475 return TestVM.isCompiled(m); 476 } 477 478 /** 479 * Returns a boolean indicating if {@code m} is compiled with C1. 480 * 481 * @param m the method to be checked. 482 * @return {@code true} if {@code m} is compiled with C1; 483 * {@code false} otherwise. 484 */ 485 public static boolean isC1Compiled(Method m) { 486 return TestVM.isC1Compiled(m); 487 } 488 489 /** 490 * Returns a boolean indicating if {@code m} is compiled with C2. 491 * 492 * @param m the method to be checked. 493 * @return {@code true} if {@code m} is compiled with C2; 494 * {@code false} otherwise. 495 */ 496 public static boolean isC2Compiled(Method m) { 497 return TestVM.isC2Compiled(m); 498 } 499 500 /** 501 * Returns a boolean indicating if {@code m} is compiled at the specified {@code compLevel}. 502 * 503 * @param m the method to be checked. 504 * @param compLevel the compilation level. 505 * @return {@code true} if {@code m} is compiled at {@code compLevel}; 506 * {@code false} otherwise. 507 */ 508 public static boolean isCompiledAtLevel(Method m, CompLevel compLevel) { 509 return TestVM.isCompiledAtLevel(m, compLevel); 510 } 511 512 /** 513 * Checks if {@code m} is compiled at any level. 514 * 515 * @param m the method to be checked. 516 * @throws TestRunException if {@code m} is not compiled at any level. 517 */ 518 public static void assertCompiled(Method m) { 519 TestVM.assertCompiled(m); 520 } 521 522 /** 523 * Checks if {@code m} is not compiled at any level. 524 * 525 * @param m the method to be checked. 526 * @throws TestRunException if {@code m} is compiled at any level. 527 */ 528 public static void assertNotCompiled(Method m) { 529 TestVM.assertNotCompiled(m); 530 } 531 532 /** 533 * Verifies that {@code m} is compiled with C1. 534 * 535 * @param m the method to be verified. 536 * @throws TestRunException if {@code m} is not compiled with C1. 537 */ 538 public static void assertCompiledByC1(Method m) { 539 TestVM.assertCompiledByC1(m); 540 } 541 542 /** 543 * Verifies that {@code m} is compiled with C2. 544 * 545 * @param m the method to be checked. 546 * @throws TestRunException if {@code m} is not compiled with C2. 547 */ 548 public static void assertCompiledByC2(Method m) { 549 TestVM.assertCompiledByC2(m); 550 } 551 552 /** 553 * Verifies that {@code m} is compiled at the specified {@code compLevel}. 554 * 555 * @param m the method to be checked. 556 * @param compLevel the compilation level. 557 * @throws TestRunException if {@code m} is not compiled at {@code compLevel}. 558 */ 559 public static void assertCompiledAtLevel(Method m, CompLevel compLevel) { 560 TestVM.assertCompiledAtLevel(m, compLevel); 561 } 562 563 /** 564 * Verifies that {@code m} was deoptimized after being C1 compiled. 565 * 566 * @param m the method to be checked. 567 * @throws TestRunException if {@code m} is was not deoptimized after being C1 compiled. 568 */ 569 public static void assertDeoptimizedByC1(Method m) { 570 TestVM.assertDeoptimizedByC1(m); 571 } 572 573 /** 574 * Verifies that {@code m} was deoptimized after being C2 compiled. 575 * 576 * @param m the method to be checked. 577 * @throws TestRunException if {@code m} is was not deoptimized after being C2 compiled. 578 */ 579 public static void assertDeoptimizedByC2(Method m) { 580 TestVM.assertDeoptimizedByC2(m); 581 } 582 583 /** 584 * Returns a different boolean each time this method is invoked (switching between {@code false} and {@code true}). 585 * The very first invocation returns {@code false}. Note that this method could be used by different tests and 586 * thus the first invocation for a test could be {@code true} or {@code false} depending on how many times 587 * other tests have already invoked this method. 588 * 589 * @return an inverted boolean of the result of the last invocation of this method. 590 */ 591 public static boolean toggleBoolean() { 592 toggleBool = !toggleBool; 593 return toggleBool; 594 } 595 596 /* 597 * End of public interface methods 598 */ 599 600 /** 601 * Used to move Whitebox class to the right folder in the JTreg test 602 */ 603 private void installWhiteBox() { 604 try { 605 ClassFileInstaller.main(WhiteBox.class.getName()); 606 } catch (Exception e) { 607 throw new Error("failed to install whitebox classes", e); 608 } 609 } 610 611 /** 612 * Disable IR verification completely in certain cases. 613 */ 614 private void disableIRVerificationIfNotFeasible() { 615 if (!irVerificationPossible) { 616 return; 617 } 618 619 boolean debugTest = Platform.isDebugBuild(); 620 boolean intTest = !Platform.isInt(); 621 boolean compTest = !Platform.isComp(); 622 boolean irTest = hasIRAnnotations(); 623 // No IR verification is done if additional non-whitelisted JTreg VM or Javaoptions flag is specified. 624 List<String> nonWhiteListedFlags = anyNonWhitelistedJTregVMAndJavaOptsFlags(); 625 boolean nonWhiteListedTest = nonWhiteListedFlags.isEmpty(); 626 627 irVerificationPossible = debugTest && intTest && compTest && irTest && nonWhiteListedTest; 628 if (irVerificationPossible) { 629 return; 630 } 631 632 System.out.println("IR verification disabled due to the following reason(s):"); 633 if (!debugTest) { 634 System.out.println("- Not running a debug build (required for PrintIdeal and PrintOptoAssembly)"); 635 } 636 if (!intTest) { 637 System.out.println("- Running with -Xint (no compilations)"); 638 } 639 if (!compTest) { 640 System.out.println("- Running with -Xcomp (use warm-up of 0 instead)"); 641 } 642 if (!irTest) { 643 System.out.println("- Test " + testClass + " not specifying any @IR annotations"); 644 } 645 if (!nonWhiteListedTest) { 646 System.out.println("- Using non-whitelisted JTreg VM or Javaoptions flag(s):"); 647 nonWhiteListedFlags.forEach((f) -> System.out.println(" - " + f)); 648 } 649 650 System.out.println(""); 651 } 652 653 /** 654 * For scenarios: Run the tests with the scenario settings and collect all exceptions to be able to run all 655 * scenarios without prematurely throwing an exception. Format violations, however, are wrong for all scenarios 656 * and thus is reported immediately on the first scenario execution. 657 */ 658 private void startWithScenarios() { 659 Map<Scenario, Exception> exceptionMap = new TreeMap<>(Comparator.comparingInt(Scenario::getIndex)); 660 for (Scenario scenario : scenarios) { 661 try { 662 start(scenario); 663 } catch (TestFormatException e) { 664 // Test format violation is wrong for all the scenarios. Only report once. 665 throw e; 666 } catch (Exception e) { 667 exceptionMap.put(scenario, e); 668 } 669 } 670 if (!exceptionMap.isEmpty()) { 671 reportScenarioFailures(exceptionMap); 672 } 673 } 674 675 private void reportScenarioFailures(Map<Scenario, Exception> exceptionMap) { 676 String failedScenarios = "The following scenarios have failed: #" 677 + exceptionMap.keySet().stream() 678 .map(s -> String.valueOf(s.getIndex())) 679 .collect(Collectors.joining(", #")); 680 StringBuilder builder = new StringBuilder(failedScenarios); 681 builder.append(System.lineSeparator()).append(System.lineSeparator()); 682 for (Map.Entry<Scenario, Exception> entry : exceptionMap.entrySet()) { 683 Exception e = entry.getValue(); 684 Scenario scenario = entry.getKey(); 685 String errorMsg = ""; 686 if (scenario != null) { 687 errorMsg = getScenarioTitleAndFlags(scenario); 688 } 689 if (e instanceof IRViolationException irException) { 690 // For IR violations, only show the actual violations and not the (uninteresting) stack trace. 691 if (scenario != null) { 692 System.out.println("Scenario #" + scenario.getIndex()); 693 } 694 System.out.println(irException.getCompilations()); 695 builder.append(errorMsg).append(System.lineSeparator()).append(irException.getExceptionInfo()); 696 } else if (e instanceof TestVMException testVMException) { 697 builder.append(errorMsg).append(System.lineSeparator()).append(testVMException.getExceptionInfo()); 698 } else { 699 // Print stack trace otherwise 700 StringWriter errors = new StringWriter(); 701 e.printStackTrace(new PrintWriter(errors)); 702 builder.append(errors); 703 } 704 builder.append(System.lineSeparator()); 705 } 706 System.err.println(builder); 707 if (!VERBOSE && !REPORT_STDOUT && !TESTLIST && !EXCLUDELIST) { 708 // Provide a hint to the user how to get additional output/debugging information. 709 System.err.println(RERUN_HINT); 710 } 711 throw new TestRunException(failedScenarios + ". Please check stderr for more information."); 712 } 713 714 private static String getScenarioTitleAndFlags(Scenario scenario) { 715 StringBuilder builder = new StringBuilder(); 716 String title = "Scenario #" + scenario.getIndex(); 717 builder.append(title).append(System.lineSeparator()).append("=".repeat(title.length())) 718 .append(System.lineSeparator()); 719 builder.append("Scenario flags: [").append(String.join(", ", scenario.getFlags())).append("]") 720 .append(System.lineSeparator()); 721 return builder.toString(); 722 } 723 724 /** 725 * Execute a separate "flag" VM with White Box access to determine all test VM flags. The flag VM sends an encoding of 726 * all required flags for the test VM to the driver VM over a socket. Once the flag VM exits, this driver VM parses the 727 * test VM flags, which also determine if IR matching should be done, and then starts the test VM to execute all tests. 728 */ 729 private void start(Scenario scenario) { 730 if (scenario != null && !scenario.isEnabled()) { 731 System.out.println("Disabled scenario #" + scenario.getIndex() + "! This scenario is not present in set flag " + 732 "-DScenarios and is therefore not executed."); 733 return; 734 } 735 shouldVerifyIR = irVerificationPossible; 736 try { 737 // Use TestFramework flags and scenario flags for new VMs. 738 List<String> additionalFlags = new ArrayList<>(); 739 if (flags != null) { 740 additionalFlags.addAll(flags); 741 } 742 if (scenario != null) { 743 List<String> scenarioFlags = scenario.getFlags(); 744 String scenarioFlagsString = scenarioFlags.isEmpty() ? "" : " - [" + String.join(", ", scenarioFlags) + "]"; 745 System.out.println("Scenario #" + scenario.getIndex() + scenarioFlagsString + ":"); 746 additionalFlags.addAll(scenarioFlags); 747 } 748 String frameworkAndScenarioFlags = additionalFlags.isEmpty() ? 749 "" : " - [" + String.join(", ", additionalFlags) + "]"; 750 751 if (shouldVerifyIR) { 752 // Only need to use flag VM if an IR verification is possibly done. 753 System.out.println("Run Flag VM:"); 754 FlagVMProcess flagVMProcess = new FlagVMProcess(testClass, additionalFlags); 755 shouldVerifyIR = flagVMProcess.shouldVerifyIR(); 756 if (shouldVerifyIR) { 757 // Add more flags for the test VM which are required to do IR verification. 758 additionalFlags.addAll(flagVMProcess.getTestVMFlags()); 759 } // else: Flag VM found a reason to not do IR verification. 760 } else { 761 System.out.println("Skip Flag VM due to not performing IR verification."); 762 } 763 764 System.out.println("Run Test VM" + frameworkAndScenarioFlags + ":"); 765 runTestVM(additionalFlags); 766 } finally { 767 if (scenario != null) { 768 scenario.setTestVMOutput(TestVMProcess.getLastTestVMOutput()); 769 } 770 System.out.println(); 771 } 772 } 773 774 private boolean hasIRAnnotations() { 775 return Arrays.stream(testClass.getDeclaredMethods()).anyMatch(m -> m.getAnnotationsByType(IR.class).length > 0); 776 } 777 778 private List<String> anyNonWhitelistedJTregVMAndJavaOptsFlags() { 779 List<String> flags = Arrays.stream(Utils.getTestJavaOpts()) 780 .map(s -> s.replaceFirst("-XX:[+|-]?|-(?=[^D|^e])", "")) 781 .collect(Collectors.toList()); 782 List<String> nonWhiteListedFlags = new ArrayList(); 783 for (String flag : flags) { 784 // Property flags (prefix -D), -ea and -esa are whitelisted. 785 if (!flag.startsWith("-D") && !flag.startsWith("-e") && JTREG_WHITELIST_FLAGS.stream().noneMatch(flag::contains)) { 786 // Found VM flag that is not whitelisted 787 nonWhiteListedFlags.add(flag); 788 } 789 } 790 return nonWhiteListedFlags; 791 } 792 793 private void runTestVM(List<String> additionalFlags) { 794 TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup, 795 isAllowNotCompilable, testClassesOnBootClassPath); 796 if (shouldVerifyIR) { 797 try { 798 TestClassParser testClassParser = new TestClassParser(testClass, isAllowNotCompilable); 799 Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), 800 testVMProcess.getIrEncoding()); 801 IRMatcher matcher = new IRMatcher(testClassMatchable); 802 matcher.match(); 803 } catch (IRViolationException e) { 804 e.addCommandLine(testVMProcess.getCommandLine()); 805 throw e; 806 } 807 } else { 808 System.out.println("IR verification disabled either due to no @IR annotations, through explicitly setting " + 809 "-DVerify=false, due to not running a debug build, using a non-whitelisted JTreg VM or " + 810 "Javaopts flag like -Xint, or running the test VM with other VM flags added by user code " + 811 "that make the IR verification impossible (e.g. -XX:-UseCompile, " + 812 "-XX:TieredStopAtLevel=[1,2,3], etc.)."); 813 } 814 } 815 816 public static void check(boolean test, String failureMessage) { 817 if (!test) { 818 throw new TestFrameworkException(failureMessage); 819 } 820 } 821 }