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