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