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