1 /*
  2  * Copyright (c) 2021, 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 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                     "UseZbb",
143                     "UseRVV",
144                     "Xlog",
145                     "LogCompilation",
146                     "UseCompactObjectHeaders"
147             )
148     );
149 
150     public static final boolean VERBOSE = Boolean.getBoolean("Verbose");
151     public static final boolean TESTLIST = !System.getProperty("Test", "").isEmpty();
152     public static final boolean EXCLUDELIST = !System.getProperty("Exclude", "").isEmpty();
153     private static final boolean REPORT_STDOUT = Boolean.getBoolean("ReportStdout");
154     // Only used for internal testing and should not be used for normal user testing.
155 
156     private static final String RERUN_HINT = """
157                                                #############################################################
158                                                 - To only run the failed tests use -DTest, -DExclude,
159                                                   and/or -DScenarios.
160                                                 - To also get the standard output of the test VM run with
161                                                   -DReportStdout=true or for even more fine-grained logging
162                                                   use -DVerbose=true.
163                                                #############################################################
164                                              """ + System.lineSeparator();
165 
166     private boolean irVerificationPossible = Boolean.parseBoolean(System.getProperty("VerifyIR", "true"));
167     private boolean shouldVerifyIR; // Should we perform IR matching?
168     private static boolean toggleBool;
169 
170     private final Class<?> testClass;
171     private Set<Class<?>> helperClasses;
172     private List<Scenario> scenarios;
173     private Set<Integer> scenarioIndices;
174     private List<String> flags;
175     private int defaultWarmup = -1;
176 
177     /*
178      * Public interface methods
179      */
180 
181     /**
182      * Creates an instance acting as a builder to test the class from which this constructor was invoked from.
183      * Use this constructor if you want to use multiple run options (flags, helper classes, scenarios).
184      * Use the associated add methods ({@link #addFlags(String...)}, {@link #addScenarios(Scenario...)},
185      * {@link #addHelperClasses(Class...)}) to set up everything and then start the testing by invoking {@link #start()}.
186      */
187     public TestFramework() {
188         this(StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass());
189     }
190 
191     /**
192      * Creates an instance acting as a builder to test {@code testClass}.
193      * Use this constructor if you want to use multiple run options (flags, helper classes, scenarios).
194      * Use the associated add methods ({@link #addFlags(String...)}, {@link #addScenarios(Scenario...)},
195      * {@link #addHelperClasses(Class...)}) to set up everything and then start the testing by invoking {@link #start()}.
196      *
197      * @param testClass the class to be tested by the framework.
198      * @see #TestFramework()
199      */
200     public TestFramework(Class<?> testClass) {
201         TestRun.check(testClass != null, "Test class cannot be null");
202         this.testClass = testClass;
203         if (VERBOSE) {
204             System.out.println("Test class: " + testClass);
205         }
206     }
207 
208     /**
209      * Tests the class from which this method was invoked from.
210      */
211     public static void run() {
212         StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
213         run(walker.getCallerClass());
214     }
215 
216     /**
217      * Tests {@code testClass}.
218      *
219      * @param testClass the class to be tested by the framework.
220      * @see #run()
221      */
222     public static void run(Class<?> testClass) {
223         TestFramework framework = new TestFramework(testClass);
224         framework.start();
225     }
226 
227     /**
228      * Tests the class from which this method was invoked from. The test VM is called with the specified {@code flags}.
229      * <ul>
230      *     <li><p>The {@code flags} override any set VM or Javaoptions flags by JTreg by default.<p>
231      *            Use {@code -DPreferCommandLineFlags=true} if you want to prefer the JTreg VM and  Javaoptions flags over
232      *            the specified {@code flags} of this method.</li>
233      *     <li><p>If you want to run your entire JTreg test with additional flags, use this method.</li>
234      *     <li><p>If you want to run your entire JTreg test with additional flags but for another test class then the one
235      *            from which this method was called from, use {@link #addFlags(String...)}, use this method.</li>
236      *     <li><p>If you want to run your JTreg test with multiple flag combinations, use
237      *            {@link #addScenarios(Scenario...)}</li>
238      * </ul>
239      *
240      * @param flags VM flags to be used for the test VM.
241      */
242     public static void runWithFlags(String... flags) {
243         StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
244         TestFramework framework = new TestFramework(walker.getCallerClass());
245         framework.addFlags(flags);
246         framework.start();
247     }
248 
249     /**
250      * Add VM flags to be used for the test VM. These flags override any VM or Javaoptions set by JTreg by default.<p>
251      * Use {@code -DPreferCommandLineFlags=true} if you want to prefer the VM or Javaoptions over the scenario flags.
252      *
253      * <p>
254      * The testing can be started by invoking {@link #start()}
255      *
256      * @param flags VM options to be applied to the test VM.
257      * @return the same framework instance.
258      */
259     public TestFramework addFlags(String... flags) {
260         TestRun.check(flags != null && Arrays.stream(flags).noneMatch(Objects::isNull), "A flag cannot be null");
261         if (this.flags == null) {
262             this.flags = new ArrayList<>();
263         }
264         this.flags.addAll(Arrays.asList(flags));
265         return this;
266     }
267 
268     /**
269      * Add helper classes that can specify additional compile command annotations ({@link ForceCompile @ForceCompile},
270      * {@link DontCompile @DontCompile}, {@link ForceInline @ForceInline}, {@link DontInline @DontInline}) to be applied
271      * while testing {@code testClass} (also see description of {@link TestFramework}).
272      *
273      * <p>
274      * Duplicates in {@code helperClasses} are ignored. If a class is used by the test class that does not specify any
275      * compile command annotations, you do not need to include it with this method. If no helper class specifies any
276      * compile commands, you do not need to call this method at all.
277      *
278      * <p>
279      * The testing can be started by invoking {@link #start()}.
280      *
281      * @param helperClasses helper classes containing compile command annotations ({@link ForceCompile},
282      *                      {@link DontCompile}, {@link ForceInline}, {@link DontInline}) to be applied
283      *                      while testing {@code testClass} (also see description of {@link TestFramework}).
284      * @return the same framework instance.
285      */
286     public TestFramework addHelperClasses(Class<?>... helperClasses) {
287         TestRun.check(helperClasses != null && Arrays.stream(helperClasses).noneMatch(Objects::isNull),
288                       "A Helper class cannot be null");
289         if (this.helperClasses == null) {
290             this.helperClasses = new HashSet<>();
291         }
292 
293         this.helperClasses.addAll(Arrays.asList(helperClasses));
294         return this;
295     }
296 
297     /**
298      * Add scenarios to be used for the test VM. A test VM is called for each scenario in {@code scenarios} by using the
299      * specified VM flags in the scenario. The scenario flags override any flags set by {@link #addFlags(String...)}
300      * and thus also override any VM or Javaoptions set by JTreg by default.<p>
301      * Use {@code -DPreferCommandLineFlags=true} if you want to prefer the VM and Javaoptions over the scenario flags.
302      *
303      * <p>
304      * The testing can be started by invoking {@link #start()}
305      *
306      * @param scenarios scenarios which specify specific flags for the test VM.
307      * @return the same framework instance.
308      */
309     public TestFramework addScenarios(Scenario... scenarios) {
310         TestFormat.checkAndReport(scenarios != null && Arrays.stream(scenarios).noneMatch(Objects::isNull),
311                                   "A scenario cannot be null");
312         if (this.scenarios == null) {
313             this.scenarios = new ArrayList<>();
314             this.scenarioIndices = new HashSet<>();
315         }
316 
317         for (Scenario scenario : scenarios) {
318             int scenarioIndex = scenario.getIndex();
319             TestFormat.checkNoThrow(scenarioIndices.add(scenarioIndex),
320                              "Cannot define two scenarios with the same index " + scenarioIndex);
321             this.scenarios.add(scenario);
322         }
323         TestFormat.throwIfAnyFailures();
324         return this;
325     }
326 
327     /**
328      * Start the testing of the implicitly (by {@link #TestFramework()}) or explicitly (by {@link #TestFramework(Class)})
329      * set test class.
330      */
331     public void start() {
332         if (shouldInstallWhiteBox()) {
333             installWhiteBox();
334         }
335         checkIRRuleCompilePhasesFormat();
336         disableIRVerificationIfNotFeasible();
337 
338         if (scenarios == null) {
339             try {
340                 start(null);
341             } catch (TestVMException e) {
342                 System.err.println(System.lineSeparator() + e.getExceptionInfo() + RERUN_HINT);
343                 throw e;
344             } catch (IRViolationException e) {
345                 System.out.println(e.getCompilations());
346                 System.err.println(System.lineSeparator() + e.getExceptionInfo() + System.lineSeparator() + RERUN_HINT);
347                 throw e;
348             }
349         } else {
350             startWithScenarios();
351         }
352     }
353 
354     private void checkIRRuleCompilePhasesFormat() {
355         for (Method method : testClass.getDeclaredMethods()) {
356             for (IR irAnno : method.getAnnotationsByType(IR.class)) {
357                 TestFormat.checkNoThrow(irAnno.phase().length > 0,
358                                         "@IR rule " + irAnno + " must specify a non-empty list of compile " +
359                                         "phases \"phase\" at " + method);
360             }
361         }
362         TestFormat.throwIfAnyFailures();
363     }
364 
365     /**
366      * Try to load the Whitebox class from the user directory with a custom class loader. If the user has already built the
367      * Whitebox, we can load it. Otherwise, the framework needs to install it.
368      *
369      * @return true if the framework needs to install the Whitebox
370      */
371     private boolean shouldInstallWhiteBox() {
372         try {
373             URL url = Path.of(System.getProperty("user.dir")).toUri().toURL();
374             URLClassLoader userDirClassLoader =
375                     URLClassLoader.newInstance(new URL[] {url}, TestFramework.class.getClassLoader().getParent());
376             Class.forName(WhiteBox.class.getName(), false, userDirClassLoader);
377         } catch (MalformedURLException e) {
378             throw new TestFrameworkException("corrupted user.dir property", e);
379         } catch (ClassNotFoundException e) {
380             // We need to manually install the WhiteBox if we cannot load the WhiteBox class from the user directory.
381             // This happens when the user test does not explicitly install the WhiteBox as part of the test.
382             return true;
383         }
384         return false;
385     }
386 
387     /**
388      * Set a new default warm-up (overriding the framework default of 2000 at
389      * {@link TestVM#WARMUP_ITERATIONS}) to be applied for all tests that do not specify an explicit
390      * warm-up with {@link Warmup @Warmup}.
391      *
392      * @param defaultWarmup a new non-negative default warm-up.
393      * @return the same framework instance.
394      */
395     public TestFramework setDefaultWarmup(int defaultWarmup) {
396         TestFormat.checkAndReport(defaultWarmup >= 0, "Cannot specify a negative default warm-up");
397         this.defaultWarmup = defaultWarmup;
398         return this;
399     }
400 
401     /**
402      * Get the VM output of the test VM. Use {@code -DVerbose=true} to enable more debug information. If scenarios
403      * were run, use {@link Scenario#getTestVMOutput()}.
404      *
405      * @return the last test VM output.
406      */
407     public static String getLastTestVMOutput() {
408         return TestVMProcess.getLastTestVMOutput();
409     }
410 
411     /*
412      * The following methods are only intended to be called from actual @Test methods and not from the main() method of
413      * a JTreg test. Calling these methods from main() results in a linking exception (Whitebox not yet loaded and enabled).
414      */
415 
416     /**
417      * Compile {@code m} at compilation level {@code compLevel}. {@code m} is first enqueued and might not be compiled,
418      * yet, upon returning from this method.
419      *
420      * @param m the method to be compiled.
421      * @param compLevel the (valid) compilation level at which the method should be compiled.
422      * @throws TestRunException if compilation level is {@link CompLevel#SKIP} or {@link CompLevel#WAIT_FOR_COMPILATION}.
423      */
424     public static void compile(Method m, CompLevel compLevel) {
425         TestVM.compile(m, compLevel);
426     }
427 
428     /**
429      * Deoptimize {@code m}.
430      *
431      * @param m the method to be deoptimized.
432      */
433     public static void deoptimize(Method m) {
434         TestVM.deoptimize(m);
435     }
436 
437     /**
438      * Returns a boolean indicating if {@code m} is compiled at any level.
439      *
440      * @param m the method to be checked.
441      * @return {@code true} if {@code m} is compiled at any level;
442      *         {@code false} otherwise.
443      */
444     public static boolean isCompiled(Method m) {
445         return TestVM.isCompiled(m);
446     }
447 
448     /**
449      * Returns a boolean indicating if {@code m} is compiled with C1.
450      *
451      * @param m the method to be checked.
452      * @return {@code true} if {@code m} is compiled with C1;
453      *         {@code false} otherwise.
454      */
455     public static boolean isC1Compiled(Method m) {
456         return TestVM.isC1Compiled(m);
457     }
458 
459     /**
460      * Returns a boolean indicating if {@code m} is compiled with C2.
461      *
462      * @param m the method to be checked.
463      * @return {@code true} if {@code m} is compiled with C2;
464      *         {@code false} otherwise.
465      */
466     public static boolean isC2Compiled(Method m) {
467         return TestVM.isC2Compiled(m);
468     }
469 
470     /**
471      * Returns a boolean indicating if {@code m} is compiled at the specified {@code compLevel}.
472      *
473      * @param m the method to be checked.
474      * @param compLevel the compilation level.
475      * @return {@code true} if {@code m} is compiled at {@code compLevel};
476      *         {@code false} otherwise.
477      */
478     public static boolean isCompiledAtLevel(Method m, CompLevel compLevel) {
479         return TestVM.isCompiledAtLevel(m, compLevel);
480     }
481 
482     /**
483      * Checks if {@code m} is compiled at any level.
484      *
485      * @param m the method to be checked.
486      * @throws TestRunException if {@code m} is not compiled at any level.
487      */
488     public static void assertCompiled(Method m) {
489         TestVM.assertCompiled(m);
490     }
491 
492     /**
493      * Checks if {@code m} is not compiled at any level.
494      *
495      * @param m the method to be checked.
496      * @throws TestRunException if {@code m} is compiled at any level.
497      */
498     public static void assertNotCompiled(Method m) {
499         TestVM.assertNotCompiled(m);
500     }
501 
502     /**
503      * Verifies that {@code m} is compiled with C1.
504      *
505      * @param m the method to be verified.
506      * @throws TestRunException if {@code m} is not compiled with C1.
507      */
508     public static void assertCompiledByC1(Method m) {
509         TestVM.assertCompiledByC1(m);
510     }
511 
512     /**
513      * Verifies that {@code m} is compiled with C2.
514      *
515      * @param m the method to be checked.
516      * @throws TestRunException if {@code m} is not compiled with C2.
517      */
518     public static void assertCompiledByC2(Method m) {
519         TestVM.assertCompiledByC2(m);
520     }
521 
522     /**
523      * Verifies that {@code m} is compiled at the specified {@code compLevel}.
524      *
525      * @param m the method to be checked.
526      * @param compLevel the compilation level.
527      * @throws TestRunException if {@code m} is not compiled at {@code compLevel}.
528      */
529     public static void assertCompiledAtLevel(Method m, CompLevel compLevel) {
530         TestVM.assertCompiledAtLevel(m, compLevel);
531     }
532 
533     /**
534      * Verifies that {@code m} was deoptimized after being C1 compiled.
535      *
536      * @param m the method to be checked.
537      * @throws TestRunException if {@code m} is was not deoptimized after being C1 compiled.
538      */
539     public static void assertDeoptimizedByC1(Method m) {
540         TestVM.assertDeoptimizedByC1(m);
541     }
542 
543     /**
544      * Verifies that {@code m} was deoptimized after being C2 compiled.
545      *
546      * @param m the method to be checked.
547      * @throws TestRunException if {@code m} is was not deoptimized after being C2 compiled.
548      */
549     public static void assertDeoptimizedByC2(Method m) {
550         TestVM.assertDeoptimizedByC2(m);
551     }
552 
553     /**
554      * Returns a different boolean each time this method is invoked (switching between {@code false} and {@code true}).
555      * The very first invocation returns {@code false}. Note that this method could be used by different tests and
556      * thus the first invocation for a test could be {@code true} or {@code false} depending on how many times
557      * other tests have already invoked this method.
558      *
559      * @return an inverted boolean of the result of the last invocation of this method.
560      */
561     public static boolean toggleBoolean() {
562         toggleBool = !toggleBool;
563         return toggleBool;
564     }
565 
566     /*
567      * End of public interface methods
568      */
569 
570     /**
571      * Used to move Whitebox class to the right folder in the JTreg test
572      */
573     private void installWhiteBox() {
574         try {
575             ClassFileInstaller.main(WhiteBox.class.getName());
576         } catch (Exception e) {
577             throw new Error("failed to install whitebox classes", e);
578         }
579     }
580 
581     /**
582      * Disable IR verification completely in certain cases.
583      */
584     private void disableIRVerificationIfNotFeasible() {
585         if (irVerificationPossible) {
586             irVerificationPossible = Platform.isDebugBuild() && !Platform.isInt() && !Platform.isComp();
587             if (!irVerificationPossible) {
588                 System.out.println("IR verification disabled due to not running a debug build (required for PrintIdeal" +
589                                    "and PrintOptoAssembly), running with -Xint, or -Xcomp (use warm-up of 0 instead)");
590                 return;
591             }
592 
593             irVerificationPossible = hasIRAnnotations();
594             if (!irVerificationPossible) {
595                 System.out.println("IR verification disabled due to test " + testClass + " not specifying any @IR annotations");
596                 return;
597             }
598 
599             // No IR verification is done if additional non-whitelisted JTreg VM or Javaoptions flag is specified.
600             irVerificationPossible = onlyWhitelistedJTregVMAndJavaOptsFlags();
601             if (!irVerificationPossible) {
602                 System.out.println("IR verification disabled due to using non-whitelisted JTreg VM or Javaoptions flag(s)."
603                                    + System.lineSeparator());
604             }
605         }
606     }
607 
608     /**
609      * For scenarios: Run the tests with the scenario settings and collect all exceptions to be able to run all
610      * scenarios without prematurely throwing an exception. Format violations, however, are wrong for all scenarios
611      * and thus is reported immediately on the first scenario execution.
612      */
613     private void startWithScenarios() {
614         Map<Scenario, Exception> exceptionMap = new TreeMap<>(Comparator.comparingInt(Scenario::getIndex));
615         for (Scenario scenario : scenarios) {
616             try {
617                 start(scenario);
618             } catch (TestFormatException e) {
619                 // Test format violation is wrong for all the scenarios. Only report once.
620                 throw e;
621             } catch (Exception e) {
622                 exceptionMap.put(scenario, e);
623             }
624         }
625         if (!exceptionMap.isEmpty()) {
626             reportScenarioFailures(exceptionMap);
627         }
628     }
629 
630     private void reportScenarioFailures(Map<Scenario, Exception> exceptionMap) {
631         String failedScenarios = "The following scenarios have failed: #"
632                                  + exceptionMap.keySet().stream()
633                                                .map(s -> String.valueOf(s.getIndex()))
634                                                .collect(Collectors.joining(", #"));
635         StringBuilder builder = new StringBuilder(failedScenarios);
636         builder.append(System.lineSeparator()).append(System.lineSeparator());
637         for (Map.Entry<Scenario, Exception> entry : exceptionMap.entrySet()) {
638             Exception e = entry.getValue();
639             Scenario scenario = entry.getKey();
640             String errorMsg = "";
641             if (scenario != null) {
642                 errorMsg = getScenarioTitleAndFlags(scenario);
643             }
644             if (e instanceof IRViolationException irException) {
645                 // For IR violations, only show the actual violations and not the (uninteresting) stack trace.
646                 if (scenario != null) {
647                     System.out.println("Scenario #" + scenario.getIndex());
648                 }
649                 System.out.println(irException.getCompilations());
650                 builder.append(errorMsg).append(System.lineSeparator()).append(irException.getExceptionInfo());
651             } else if (e instanceof TestVMException testVMException) {
652                 builder.append(errorMsg).append(System.lineSeparator()).append(testVMException.getExceptionInfo());
653             } else {
654                 // Print stack trace otherwise
655                 StringWriter errors = new StringWriter();
656                 e.printStackTrace(new PrintWriter(errors));
657                 builder.append(errors);
658             }
659             builder.append(System.lineSeparator());
660         }
661         System.err.println(builder);
662         if (!VERBOSE && !REPORT_STDOUT && !TESTLIST && !EXCLUDELIST) {
663             // Provide a hint to the user how to get additional output/debugging information.
664             System.err.println(RERUN_HINT);
665         }
666         throw new TestRunException(failedScenarios + ". Please check stderr for more information.");
667     }
668 
669     private static String getScenarioTitleAndFlags(Scenario scenario) {
670         StringBuilder builder = new StringBuilder();
671         String title = "Scenario #" + scenario.getIndex();
672         builder.append(title).append(System.lineSeparator()).append("=".repeat(title.length()))
673                .append(System.lineSeparator());
674         builder.append("Scenario flags: [").append(String.join(", ", scenario.getFlags())).append("]")
675                .append(System.lineSeparator());
676         return builder.toString();
677     }
678 
679     /**
680      * Execute a separate "flag" VM with White Box access to determine all test VM flags. The flag VM sends an encoding of
681      * all required flags for the test VM to the driver VM over a socket. Once the flag VM exits, this driver VM parses the
682      * test VM flags, which also determine if IR matching should be done, and then starts the test VM to execute all tests.
683      */
684     private void start(Scenario scenario) {
685         if (scenario != null && !scenario.isEnabled()) {
686             System.out.println("Disabled scenario #" + scenario.getIndex() + "! This scenario is not present in set flag " +
687                                "-DScenarios and is therefore not executed.");
688             return;
689         }
690         shouldVerifyIR = irVerificationPossible;
691         try {
692             // Use TestFramework flags and scenario flags for new VMs.
693             List<String> additionalFlags = new ArrayList<>();
694             if (flags != null) {
695                 additionalFlags.addAll(flags);
696             }
697             if (scenario != null) {
698                 List<String> scenarioFlags = scenario.getFlags();
699                 String scenarioFlagsString = scenarioFlags.isEmpty() ? "" : " - [" + String.join(", ", scenarioFlags) + "]";
700                 System.out.println("Scenario #" + scenario.getIndex() + scenarioFlagsString + ":");
701                 additionalFlags.addAll(scenarioFlags);
702             }
703             String frameworkAndScenarioFlags = additionalFlags.isEmpty() ?
704                     "" : " - [" + String.join(", ", additionalFlags) + "]";
705 
706             if (shouldVerifyIR) {
707                 // Only need to use flag VM if an IR verification is possibly done.
708                 System.out.println("Run Flag VM:");
709                 FlagVMProcess flagVMProcess = new FlagVMProcess(testClass, additionalFlags);
710                 shouldVerifyIR = flagVMProcess.shouldVerifyIR();
711                 if (shouldVerifyIR) {
712                     // Add more flags for the test VM which are required to do IR verification.
713                     additionalFlags.addAll(flagVMProcess.getTestVMFlags());
714                 } // else: Flag VM found a reason to not do IR verification.
715             } else {
716                 System.out.println("Skip Flag VM due to not performing IR verification.");
717             }
718 
719             System.out.println("Run Test VM" + frameworkAndScenarioFlags + ":");
720             runTestVM(additionalFlags);
721         } finally {
722             if (scenario != null) {
723                 scenario.setTestVMOutput(TestVMProcess.getLastTestVMOutput());
724             }
725             System.out.println();
726         }
727     }
728 
729     private boolean hasIRAnnotations() {
730         return Arrays.stream(testClass.getDeclaredMethods()).anyMatch(m -> m.getAnnotationsByType(IR.class).length > 0);
731     }
732 
733     private boolean onlyWhitelistedJTregVMAndJavaOptsFlags() {
734         List<String> flags = Arrays.stream(Utils.getTestJavaOpts())
735                                    .map(s -> s.replaceFirst("-XX:[+|-]?|-(?=[^D|^e])", ""))
736                                    .collect(Collectors.toList());
737         for (String flag : flags) {
738             // Property flags (prefix -D), -ea and -esa are whitelisted.
739             if (!flag.startsWith("-D") && !flag.startsWith("-e") && JTREG_WHITELIST_FLAGS.stream().noneMatch(flag::contains)) {
740                 // Found VM flag that is not whitelisted
741                 return false;
742             }
743         }
744         return true;
745     }
746 
747     private void runTestVM(List<String> additionalFlags) {
748         TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup);
749         if (shouldVerifyIR) {
750             try {
751                 TestClassParser testClassParser = new TestClassParser(testClass);
752                 Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(),
753                                                                      testVMProcess.getIrEncoding());
754                 IRMatcher matcher = new IRMatcher(testClassMatchable);
755                 matcher.match();
756             } catch (IRViolationException e) {
757                 e.addCommandLine(testVMProcess.getCommandLine());
758                 throw e;
759             }
760         } else {
761             System.out.println("IR verification disabled either due to no @IR annotations, through explicitly setting " +
762                                "-DVerify=false, due to not running a debug build, using a non-whitelisted JTreg VM or " +
763                                "Javaopts flag like -Xint, or running the test VM with other VM flags added by user code " +
764                                "that make the IR verification impossible (e.g. -XX:-UseCompile, " +
765                                "-XX:TieredStopAtLevel=[1,2,3], etc.).");
766         }
767     }
768 
769     public static void check(boolean test, String failureMessage) {
770         if (!test) {
771             throw new TestFrameworkException(failureMessage);
772         }
773     }
774 }