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             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     final public TestFramework addCrossProductScenarios(Set<String>... flagSets) {
368         TestFormat.checkAndReport(flagSets != null &&
369                                   Arrays.stream(flagSets).noneMatch(Objects::isNull) &&
370                                   Arrays.stream(flagSets).flatMap(Set::stream).noneMatch(Objects::isNull),
371                                   "Flags must not be null");
372         if (flagSets.length == 0) {
373             return this;
374         }
375 
376         int initIdx = 0;
377         if (this.scenarioIndices != null && !this.scenarioIndices.isEmpty()) {
378             initIdx = this.scenarioIndices.stream().max(Comparator.comparingInt(Integer::intValue)).get() + 1;
379         }
380         AtomicInteger idx = new AtomicInteger(initIdx);
381 
382         Stream<List<String>> crossProduct = Arrays.stream(flagSets)
383             .reduce(
384                 Stream.of(Collections.emptyList()), // Initialize Stream<List<String>> acc with a Stream containing an empty list of Strings.
385                 (Stream<List<String>> acc, Set<String> set) ->
386                     acc.flatMap(lAcc -> // For each List<String>> lAcc in acc...
387                         set.stream().map(flag -> { // ...and each flag in the current set...
388                             List<String> newList = new ArrayList<>(lAcc); // ...create a new list containing lAcc...
389                             newList.add(flag); // ...and append the flag.
390                             return newList;
391                         }) // This results in one List<List<String>> for each lAcc...
392                     ), // ...that get flattened into one big List<List<String>>.
393                 Stream::concat); // combiner; if any reduction steps are executed in parallel, just concat two streams.
394 
395         Scenario[] newScenarios = crossProduct
396             .map(flags -> new Scenario( // For each List<String> flags in crossProduct create a new Scenario.
397                 idx.getAndIncrement(),
398                 flags.stream() // Process flags
399                      .map(s -> Set.of(s.split("[ ]"))) // Split multiple flags in the same string into separate strings.
400                      .flatMap(Collection::stream) // Flatten the Stream<List<String>> into Stream<String>>.
401                      .filter(s -> !s.isEmpty()) // Remove empty string flags.
402                      .toList()
403                      .toArray(new String[0])))
404             .toList().toArray(new Scenario[0]);
405         return addScenarios(newScenarios);
406     }
407 
408     /**
409      * Add test classes to boot classpath. This adds all classes found on path {@link jdk.test.lib.Utils#TEST_CLASSES}
410      * to the boot classpath with "-Xbootclasspath/a". This is useful when trying to run tests in a privileged mode.
411      */
412     public TestFramework addTestClassesToBootClassPath() {
413         this.testClassesOnBootClassPath = true;
414         return this;
415     }
416 
417     /**
418      * Start the testing of the implicitly (by {@link #TestFramework()}) or explicitly (by {@link #TestFramework(Class)})
419      * set test class.
420      */
421     public void start() {
422         if (shouldInstallWhiteBox()) {
423             installWhiteBox();
424         }
425         checkCompatibleFlags();
426         checkIRRuleCompilePhasesFormat();
427         disableIRVerificationIfNotFeasible();
428 
429         if (scenarios == null) {
430             try {
431                 start(null);
432             } catch (TestVMException e) {
433                 System.err.println(System.lineSeparator() + e.getExceptionInfo() + RERUN_HINT);
434                 throw e;
435             } catch (IRViolationException e) {
436                 System.out.println(e.getCompilations());
437                 System.err.println(System.lineSeparator() + e.getExceptionInfo() + System.lineSeparator() + RERUN_HINT);
438                 throw e;
439             }
440         } else {
441             startWithScenarios();
442         }
443     }
444 
445     private void checkIRRuleCompilePhasesFormat() {
446         for (Method method : testClass.getDeclaredMethods()) {
447             for (IR irAnno : method.getAnnotationsByType(IR.class)) {
448                 TestFormat.checkNoThrow(irAnno.phase().length > 0,
449                                         "@IR rule " + irAnno + " must specify a non-empty list of compile " +
450                                         "phases \"phase\" at " + method);
451             }
452         }
453         TestFormat.throwIfAnyFailures();
454     }
455 
456     /**
457      * Try to load the Whitebox class from the user directory with a custom class loader. If the user has already built the
458      * Whitebox, we can load it. Otherwise, the framework needs to install it.
459      *
460      * @return true if the framework needs to install the Whitebox
461      */
462     private boolean shouldInstallWhiteBox() {
463         try {
464             URL url = Path.of(System.getProperty("user.dir")).toUri().toURL();
465             URLClassLoader userDirClassLoader =
466                     URLClassLoader.newInstance(new URL[] {url}, TestFramework.class.getClassLoader().getParent());
467             Class.forName(WhiteBox.class.getName(), false, userDirClassLoader);
468         } catch (MalformedURLException e) {
469             throw new TestFrameworkException("corrupted user.dir property", e);
470         } catch (ClassNotFoundException e) {
471             // We need to manually install the WhiteBox if we cannot load the WhiteBox class from the user directory.
472             // This happens when the user test does not explicitly install the WhiteBox as part of the test.
473             return true;
474         }
475         return false;
476     }
477 
478     /**
479      * Set a new default warm-up (overriding the framework default of 2000 at
480      * {@link TestVM#WARMUP_ITERATIONS}) to be applied for all tests that do not specify an explicit
481      * warm-up with {@link Warmup @Warmup}.
482      *
483      * @param defaultWarmup a new non-negative default warm-up.
484      * @return the same framework instance.
485      */
486     public TestFramework setDefaultWarmup(int defaultWarmup) {
487         TestFormat.checkAndReport(defaultWarmup >= 0, "Cannot specify a negative default warm-up");
488         this.defaultWarmup = defaultWarmup;
489         return this;
490     }
491 
492     /**
493      * In rare cases, methods may not be compilable because of a compilation bailout. By default, this leads to a
494      * test failure. However, if such cases are expected in multiple methods in a test class, this flag can be set to
495      * true, which allows any test to pass even if there is a compilation bailout. If only selected methods are prone
496      * to bail out, it is preferred to use {@link Test#allowNotCompilable()} instead for more fine-grained control.
497      * By setting this flag, any associated {@link IR} rule of a test is only executed if the test method was compiled,
498      * and else it is ignored silently.
499      */
500     public TestFramework allowNotCompilable() {
501         this.isAllowNotCompilable = true;
502         return this;
503     }
504 
505     /**
506      * Get the VM output of the test VM. Use {@code -DVerbose=true} to enable more debug information. If scenarios
507      * were run, use {@link Scenario#getTestVMOutput()}.
508      *
509      * @return the last test VM output.
510      */
511     public static String getLastTestVMOutput() {
512         return TestVMProcess.getLastTestVMOutput();
513     }
514 
515     /*
516      * The following methods are only intended to be called from actual @Test methods and not from the main() method of
517      * a JTreg test. Calling these methods from main() results in a linking exception (Whitebox not yet loaded and enabled).
518      */
519 
520     /**
521      * Compile {@code m} at compilation level {@code compLevel}. {@code m} is first enqueued and might not be compiled,
522      * yet, upon returning from this method.
523      *
524      * @param m the method to be compiled.
525      * @param compLevel the (valid) compilation level at which the method should be compiled.
526      * @throws TestRunException if compilation level is {@link CompLevel#SKIP} or {@link CompLevel#WAIT_FOR_COMPILATION}.
527      */
528     public static void compile(Method m, CompLevel compLevel) {
529         TestVM.compile(m, compLevel);
530     }
531 
532     /**
533      * Deoptimize {@code m}.
534      *
535      * @param m the method to be deoptimized.
536      */
537     public static void deoptimize(Method m) {
538         TestVM.deoptimize(m);
539     }
540 
541     /**
542      * Returns a boolean indicating if {@code m} is compiled at any level.
543      *
544      * @param m the method to be checked.
545      * @return {@code true} if {@code m} is compiled at any level;
546      *         {@code false} otherwise.
547      */
548     public static boolean isCompiled(Method m) {
549         return TestVM.isCompiled(m);
550     }
551 
552     /**
553      * Returns a boolean indicating if {@code m} is compiled with C1.
554      *
555      * @param m the method to be checked.
556      * @return {@code true} if {@code m} is compiled with C1;
557      *         {@code false} otherwise.
558      */
559     public static boolean isC1Compiled(Method m) {
560         return TestVM.isC1Compiled(m);
561     }
562 
563     /**
564      * Returns a boolean indicating if {@code m} is compiled with C2.
565      *
566      * @param m the method to be checked.
567      * @return {@code true} if {@code m} is compiled with C2;
568      *         {@code false} otherwise.
569      */
570     public static boolean isC2Compiled(Method m) {
571         return TestVM.isC2Compiled(m);
572     }
573 
574     /**
575      * Returns a boolean indicating if {@code m} is compiled at the specified {@code compLevel}.
576      *
577      * @param m the method to be checked.
578      * @param compLevel the compilation level.
579      * @return {@code true} if {@code m} is compiled at {@code compLevel};
580      *         {@code false} otherwise.
581      */
582     public static boolean isCompiledAtLevel(Method m, CompLevel compLevel) {
583         return TestVM.isCompiledAtLevel(m, compLevel);
584     }
585 
586     /**
587      * Checks if {@code m} is compiled at any level.
588      *
589      * @param m the method to be checked.
590      * @throws TestRunException if {@code m} is not compiled at any level.
591      */
592     public static void assertCompiled(Method m) {
593         TestVM.assertCompiled(m);
594     }
595 
596     /**
597      * Checks if {@code m} is not compiled at any level.
598      *
599      * @param m the method to be checked.
600      * @throws TestRunException if {@code m} is compiled at any level.
601      */
602     public static void assertNotCompiled(Method m) {
603         TestVM.assertNotCompiled(m);
604     }
605 
606     /**
607      * Verifies that {@code m} is compiled with C1.
608      *
609      * @param m the method to be verified.
610      * @throws TestRunException if {@code m} is not compiled with C1.
611      */
612     public static void assertCompiledByC1(Method m) {
613         TestVM.assertCompiledByC1(m);
614     }
615 
616     /**
617      * Verifies that {@code m} is compiled with C2.
618      *
619      * @param m the method to be checked.
620      * @throws TestRunException if {@code m} is not compiled with C2.
621      */
622     public static void assertCompiledByC2(Method m) {
623         TestVM.assertCompiledByC2(m);
624     }
625 
626     /**
627      * Verifies that {@code m} is compiled at the specified {@code compLevel}.
628      *
629      * @param m the method to be checked.
630      * @param compLevel the compilation level.
631      * @throws TestRunException if {@code m} is not compiled at {@code compLevel}.
632      */
633     public static void assertCompiledAtLevel(Method m, CompLevel compLevel) {
634         TestVM.assertCompiledAtLevel(m, compLevel);
635     }
636 
637     /**
638      * Verifies that {@code m} was deoptimized after being C1 compiled.
639      *
640      * @param m the method to be checked.
641      * @throws TestRunException if {@code m} is was not deoptimized after being C1 compiled.
642      */
643     public static void assertDeoptimizedByC1(Method m) {
644         TestVM.assertDeoptimizedByC1(m);
645     }
646 
647     /**
648      * Verifies that {@code m} was deoptimized after being C2 compiled.
649      *
650      * @param m the method to be checked.
651      * @throws TestRunException if {@code m} is was not deoptimized after being C2 compiled.
652      */
653     public static void assertDeoptimizedByC2(Method m) {
654         TestVM.assertDeoptimizedByC2(m);
655     }
656 












657     /**
658      * Returns a different boolean each time this method is invoked (switching between {@code false} and {@code true}).
659      * The very first invocation returns {@code false}. Note that this method could be used by different tests and
660      * thus the first invocation for a test could be {@code true} or {@code false} depending on how many times
661      * other tests have already invoked this method.
662      *
663      * @return an inverted boolean of the result of the last invocation of this method.
664      */
665     public static boolean toggleBoolean() {
666         toggleBool = !toggleBool;
667         return toggleBool;
668     }
669 
670     /*
671      * End of public interface methods
672      */
673 
674     /**
675      * Used to move Whitebox class to the right folder in the JTreg test
676      */
677     private void installWhiteBox() {
678         try {
679             ClassFileInstaller.main(WhiteBox.class.getName());
680         } catch (Exception e) {
681             throw new Error("failed to install whitebox classes", e);
682         }
683     }
684 
685     /**
686      * Disable IR verification completely in certain cases.
687      */
688     private void disableIRVerificationIfNotFeasible() {
689         if (!irVerificationPossible) {
690             return;
691         }
692 
693         boolean debugTest = Platform.isDebugBuild();
694         boolean intTest = !Platform.isInt();
695         boolean compTest = !Platform.isComp();
696         boolean irTest = hasIRAnnotations();
697         // No IR verification is done if additional non-whitelisted JTreg VM or Javaoptions flag is specified.
698         List<String> nonWhiteListedFlags = anyNonWhitelistedJTregVMAndJavaOptsFlags();
699         boolean nonWhiteListedTest = nonWhiteListedFlags.isEmpty();
700 
701         irVerificationPossible = debugTest && intTest && compTest && irTest && nonWhiteListedTest;
702         if (irVerificationPossible) {
703             return;
704         }
705 
706         System.out.println("IR verification disabled due to the following reason(s):");
707         if (!debugTest) {
708             System.out.println("- Not running a debug build (required for PrintIdeal and PrintOptoAssembly)");
709         }
710         if (!intTest) {
711             System.out.println("- Running with -Xint (no compilations)");
712         }
713         if (!compTest) {
714             System.out.println("- Running with -Xcomp (use warm-up of 0 instead)");
715         }
716         if (!irTest) {
717             System.out.println("- Test " + testClass + " not specifying any @IR annotations");
718         }
719         if (!nonWhiteListedTest) {
720             System.out.println("- Using non-whitelisted JTreg VM or Javaoptions flag(s):");
721             nonWhiteListedFlags.forEach((f) -> System.out.println("  - " + f));
722         }
723 
724         System.out.println("");
725     }
726 
727     /**
728      * For scenarios: Run the tests with the scenario settings and collect all exceptions to be able to run all
729      * scenarios without prematurely throwing an exception. Format violations, however, are wrong for all scenarios
730      * and thus is reported immediately on the first scenario execution.
731      */
732     private void startWithScenarios() {
733         Map<Scenario, Exception> exceptionMap = new TreeMap<>(Comparator.comparingInt(Scenario::getIndex));
734         for (Scenario scenario : scenarios) {
735             try {
736                 start(scenario);
737             } catch (TestFormatException e) {
738                 // Test format violation is wrong for all the scenarios. Only report once.
739                 throw e;
740             } catch (Exception e) {
741                 exceptionMap.put(scenario, e);
742             }
743         }
744         if (!exceptionMap.isEmpty()) {
745             reportScenarioFailures(exceptionMap);
746         }
747     }
748 
749     private void reportScenarioFailures(Map<Scenario, Exception> exceptionMap) {
750         String failedScenarios = "The following scenarios have failed: #"
751                                  + exceptionMap.keySet().stream()
752                                                .map(s -> String.valueOf(s.getIndex()))
753                                                .collect(Collectors.joining(", #"));
754         StringBuilder builder = new StringBuilder(failedScenarios);
755         builder.append(System.lineSeparator()).append(System.lineSeparator());
756         for (Map.Entry<Scenario, Exception> entry : exceptionMap.entrySet()) {
757             Exception e = entry.getValue();
758             Scenario scenario = entry.getKey();
759             String errorMsg = "";
760             if (scenario != null) {
761                 errorMsg = getScenarioTitleAndFlags(scenario);
762             }
763             if (e instanceof IRViolationException irException) {
764                 // For IR violations, only show the actual violations and not the (uninteresting) stack trace.
765                 if (scenario != null) {
766                     System.out.println("Scenario #" + scenario.getIndex());
767                 }
768                 System.out.println(irException.getCompilations());
769                 builder.append(errorMsg).append(System.lineSeparator()).append(irException.getExceptionInfo());
770             } else if (e instanceof TestVMException testVMException) {
771                 builder.append(errorMsg).append(System.lineSeparator()).append(testVMException.getExceptionInfo());
772             } else {
773                 // Print stack trace otherwise
774                 StringWriter errors = new StringWriter();
775                 e.printStackTrace(new PrintWriter(errors));
776                 builder.append(errors);
777             }
778             builder.append(System.lineSeparator());
779         }
780         System.err.println(builder);
781         if (!VERBOSE && !REPORT_STDOUT && !TESTLIST && !EXCLUDELIST) {
782             // Provide a hint to the user how to get additional output/debugging information.
783             System.err.println(RERUN_HINT);
784         }
785         throw new TestRunException(failedScenarios + ". Please check stderr for more information.");
786     }
787 
788     private static String getScenarioTitleAndFlags(Scenario scenario) {
789         StringBuilder builder = new StringBuilder();
790         String title = "Scenario #" + scenario.getIndex();
791         builder.append(title).append(System.lineSeparator()).append("=".repeat(title.length()))
792                .append(System.lineSeparator());
793         builder.append("Scenario flags: [").append(String.join(", ", scenario.getFlags())).append("]")
794                .append(System.lineSeparator());
795         return builder.toString();
796     }
797 
798     /**
799      * Execute a separate "flag" VM with White Box access to determine all test VM flags. The flag VM sends an encoding of
800      * all required flags for the test VM to the driver VM over a socket. Once the flag VM exits, this driver VM parses the
801      * test VM flags, which also determine if IR matching should be done, and then starts the test VM to execute all tests.
802      */
803     private void start(Scenario scenario) {
804         if (scenario != null && !scenario.isEnabled()) {
805             System.out.println("Disabled scenario #" + scenario.getIndex() + "! This scenario is not present in set flag " +
806                                "-DScenarios and is therefore not executed.");
807             return;
808         }
809         shouldVerifyIR = irVerificationPossible;
810         try {
811             // Use TestFramework flags and scenario flags for new VMs.
812             List<String> additionalFlags = new ArrayList<>();
813             if (flags != null) {
814                 additionalFlags.addAll(flags);
815             }
816             if (scenario != null) {
817                 List<String> scenarioFlags = scenario.getFlags();
818                 String scenarioFlagsString = scenarioFlags.isEmpty() ? "" : " - [" + String.join(", ", scenarioFlags) + "]";
819                 System.out.println("Scenario #" + scenario.getIndex() + scenarioFlagsString + ":");
820                 additionalFlags.addAll(scenarioFlags);
821             }
822             String frameworkAndScenarioFlags = additionalFlags.isEmpty() ?
823                     "" : " - [" + String.join(", ", additionalFlags) + "]";
824 
825             if (shouldVerifyIR) {
826                 // Only need to use flag VM if an IR verification is possibly done.
827                 System.out.println("Run Flag VM:");
828                 FlagVMProcess flagVMProcess = new FlagVMProcess(testClass, additionalFlags);
829                 shouldVerifyIR = flagVMProcess.shouldVerifyIR();
830                 if (shouldVerifyIR) {
831                     // Add more flags for the test VM which are required to do IR verification.
832                     additionalFlags.addAll(flagVMProcess.getTestVMFlags());
833                 } // else: Flag VM found a reason to not do IR verification.
834             } else {
835                 System.out.println("Skip Flag VM due to not performing IR verification.");
836             }
837 
838             System.out.println("Run Test VM" + frameworkAndScenarioFlags + ":");
839             runTestVM(additionalFlags);
840         } finally {
841             if (scenario != null) {
842                 scenario.setTestVMOutput(TestVMProcess.getLastTestVMOutput());
843             }
844             System.out.println();
845         }
846     }
847 
848     private boolean hasIRAnnotations() {
849         return Arrays.stream(testClass.getDeclaredMethods()).anyMatch(m -> m.getAnnotationsByType(IR.class).length > 0);
850     }
851 
852     private void checkCompatibleFlags() {
853         for (String flag : Utils.getTestJavaOpts()) {
854             if (flag.contains("-agentpath")) {
855                 throw new SkippedException("Can't run test with agent.");
856             }
857         }
858     }
859 
860     private List<String> anyNonWhitelistedJTregVMAndJavaOptsFlags() {
861         List<String> flags = Arrays.stream(Utils.getTestJavaOpts())
862                                    .map(s -> s.replaceFirst("-XX:[+|-]?|-(?=[^D|^e])", ""))
863                                    .collect(Collectors.toList());
864         List<String> nonWhiteListedFlags = new ArrayList();
865         for (String flag : flags) {
866             if (flag.contains("agentpath")) {
867                 throw new SkippedException("Can't run test with -javaagent");
868             }
869             // Property flags (prefix -D), -ea and -esa are whitelisted.
870             if (!flag.startsWith("-D") && !flag.startsWith("-e") && JTREG_WHITELIST_FLAGS.stream().noneMatch(flag::contains)) {
871                 // Found VM flag that is not whitelisted
872                 nonWhiteListedFlags.add(flag);
873             }
874         }
875         return nonWhiteListedFlags;
876     }
877 
878     private void runTestVM(List<String> additionalFlags) {
879         TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup,
880                                                         isAllowNotCompilable, testClassesOnBootClassPath);
881         if (shouldVerifyIR) {
882             try {
883                 TestClassParser testClassParser = new TestClassParser(testClass, isAllowNotCompilable);
884                 Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(),
885                                                                      testVMProcess.getIrEncoding());
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 }
--- EOF ---