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