1 /*
   2  * Copyright (c) 2017, 2019, 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.valhalla.valuetypes;
  25 
  26 import compiler.whitebox.CompilerWhiteBoxTest;
  27 import jdk.test.lib.Asserts;
  28 import jdk.test.lib.management.InputArguments;
  29 import jdk.test.lib.Platform;
  30 import jdk.test.lib.process.ProcessTools;
  31 import jdk.test.lib.process.OutputAnalyzer;
  32 import jdk.test.lib.Utils;
  33 import sun.hotspot.WhiteBox;
  34 
  35 import java.lang.annotation.Retention;
  36 import java.lang.annotation.RetentionPolicy;
  37 import java.lang.annotation.Repeatable;
  38 import java.lang.invoke.*;
  39 import java.lang.reflect.Method;
  40 import java.util.ArrayList;
  41 import java.util.Arrays;
  42 import java.util.Hashtable;
  43 import java.util.LinkedHashMap;
  44 import java.util.List;
  45 import java.util.Map;
  46 import java.util.regex.Matcher;
  47 import java.util.regex.Pattern;
  48 import java.util.TreeMap;
  49 
  50 // Mark method as test
  51 @Retention(RetentionPolicy.RUNTIME)
  52 @Repeatable(Tests.class)
  53 @interface Test {
  54     // Regular expression used to match forbidden IR nodes
  55     // in the C2 IR emitted for this test.
  56     String failOn() default "";
  57     // Regular expressions used to match and count IR nodes.
  58     String[] match() default { };
  59     int[] matchCount() default { };
  60     int compLevel() default ValueTypeTest.COMP_LEVEL_ANY;
  61     int valid() default ValueTypeTest.AllFlags;
  62 }
  63 
  64 @Retention(RetentionPolicy.RUNTIME)
  65 @interface Tests {
  66     Test[] value();
  67 }
  68 
  69 // Force method inlining during compilation
  70 @Retention(RetentionPolicy.RUNTIME)
  71 @interface ForceInline { }
  72 
  73 // Prevent method inlining during compilation
  74 @Retention(RetentionPolicy.RUNTIME)
  75 @interface DontInline { }
  76 
  77 // Prevent method compilation
  78 @Retention(RetentionPolicy.RUNTIME)
  79 @interface DontCompile { }
  80 
  81 // Force method compilation
  82 @Retention(RetentionPolicy.RUNTIME)
  83 @interface ForceCompile {
  84     int compLevel() default ValueTypeTest.COMP_LEVEL_ANY;
  85 }
  86 
  87 // Number of warmup iterations
  88 @Retention(RetentionPolicy.RUNTIME)
  89 @interface Warmup {
  90     int value();
  91 }
  92 
  93 // Do not enqueue the test method for compilation immediately after warmup loops have finished. Instead
  94 // let the test method be compiled with on-stack-replacement.
  95 @Retention(RetentionPolicy.RUNTIME)
  96 @interface OSRCompileOnly {}
  97 
  98 // Skip this test temporarily for C1 testing
  99 @Retention(RetentionPolicy.RUNTIME)
 100 @interface TempSkipForC1 {
 101     String reason() default "";
 102 }
 103 
 104 public abstract class ValueTypeTest {
 105     protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
 106 
 107     protected static final int COMP_LEVEL_ANY               = -2;
 108     protected static final int COMP_LEVEL_ALL               = -2;
 109     protected static final int COMP_LEVEL_AOT               = -1;
 110     protected static final int COMP_LEVEL_NONE              =  0;
 111     protected static final int COMP_LEVEL_SIMPLE            =  1;     // C1
 112     protected static final int COMP_LEVEL_LIMITED_PROFILE   =  2;     // C1, invocation & backedge counters
 113     protected static final int COMP_LEVEL_FULL_PROFILE      =  3;     // C1, invocation & backedge counters + mdo
 114     protected static final int COMP_LEVEL_FULL_OPTIMIZATION =  4;     // C2 or JVMCI
 115 
 116     protected static final boolean TieredCompilation = (Boolean)WHITE_BOX.getVMFlag("TieredCompilation");
 117     protected static final long TieredStopAtLevel = (Long)WHITE_BOX.getVMFlag("TieredStopAtLevel");
 118     static final boolean TEST_C1 = TieredStopAtLevel < COMP_LEVEL_FULL_OPTIMIZATION;
 119 
 120     // Should we execute tests that assume (ValueType[] <: Object[])?
 121     static final boolean ENABLE_VALUE_ARRAY_COVARIANCE = Boolean.getBoolean("ValueArrayCovariance");
 122 
 123     // Random test values
 124     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
 125     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
 126 
 127     // User defined settings
 128     protected static final boolean XCOMP = Platform.isComp();
 129     private static final boolean PRINT_GRAPH = true;
 130     protected static final boolean VERBOSE = Boolean.parseBoolean(System.getProperty("Verbose", "false"));
 131     private static final boolean PRINT_TIMES = Boolean.parseBoolean(System.getProperty("PrintTimes", "false"));
 132     private static       boolean VERIFY_IR = Boolean.parseBoolean(System.getProperty("VerifyIR", "true")) && !XCOMP;
 133     private static final boolean VERIFY_VM = Boolean.parseBoolean(System.getProperty("VerifyVM", "false"));
 134     private static final String SCENARIOS = System.getProperty("Scenarios", "");
 135     private static final String TESTLIST = System.getProperty("Testlist", "");
 136     private static final String EXCLUDELIST = System.getProperty("Exclude", "");
 137     private static final int WARMUP = Integer.parseInt(System.getProperty("Warmup", "251"));
 138     private static final boolean DUMP_REPLAY = Boolean.parseBoolean(System.getProperty("DumpReplay", "false"));
 139     protected static final boolean FLIP_C1_C2 = Boolean.parseBoolean(System.getProperty("FlipC1C2", "false"));
 140     protected static final boolean GCAfter = Boolean.parseBoolean(System.getProperty("GCAfter", "false"));
 141     private static final int OSRTestTimeOut = Integer.parseInt(System.getProperty("OSRTestTimeOut", "-1"));
 142 
 143     // "jtreg -DXcomp=true" runs all the scenarios with -Xcomp. This is faster than "jtreg -javaoptions:-Xcomp".
 144     protected static final boolean RUN_SCENARIOS_WITH_XCOMP = Boolean.parseBoolean(System.getProperty("Xcomp", "false"));
 145 
 146     // Pre-defined settings
 147     private static final String[] defaultFlags = {
 148         "-XX:-BackgroundCompilation",
 149         "-XX:CompileCommand=quiet",
 150         "-XX:CompileCommand=compileonly,java.lang.invoke.*::*",
 151         "-XX:CompileCommand=compileonly,java.lang.Long::sum",
 152         "-XX:CompileCommand=compileonly,java.lang.Object::<init>",
 153         "-XX:CompileCommand=inline,compiler.valhalla.valuetypes.MyValue*::<init>",
 154         "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.*::*"};
 155     private static final String[] printFlags = {
 156         "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintOptoAssembly"};
 157     private static final String[] verifyFlags = {
 158         "-XX:+VerifyOops", "-XX:+VerifyStack", "-XX:+VerifyLastFrame", "-XX:+VerifyBeforeGC", "-XX:+VerifyAfterGC",
 159         "-XX:+VerifyDuringGC", "-XX:+VerifyAdapterSharing"};
 160 
 161     protected static final int ValueTypePassFieldsAsArgsOn = 0x1;
 162     protected static final int ValueTypePassFieldsAsArgsOff = 0x2;
 163     protected static final int ValueTypeArrayFlattenOn = 0x4;
 164     protected static final int ValueTypeArrayFlattenOff = 0x8;
 165     protected static final int ValueTypeReturnedAsFieldsOn = 0x10;
 166     protected static final int ValueTypeReturnedAsFieldsOff = 0x20;
 167     protected static final int AlwaysIncrementalInlineOn = 0x40;
 168     protected static final int AlwaysIncrementalInlineOff = 0x80;
 169     protected static final int G1GCOn = 0x100;
 170     protected static final int G1GCOff = 0x200;
 171     static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | ValueTypeReturnedAsFieldsOn;
 172     protected static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
 173     protected static final boolean ValueTypeArrayFlatten = (WHITE_BOX.getIntxVMFlag("ValueArrayElemMaxFlatSize") == -1); // FIXME - fix this if default of ValueArrayElemMaxFlatSize is changed
 174     protected static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields");
 175     protected static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline");
 176     protected static final boolean G1GC = (Boolean)WHITE_BOX.getVMFlag("UseG1GC");
 177     protected static final boolean VerifyOops = (Boolean)WHITE_BOX.getVMFlag("VerifyOops");
 178 
 179     protected static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
 180     protected static final boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
 181     protected static final boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
 182 
 183     // Regular expressions used to match nodes in the PrintIdeal output
 184     protected static final String START = "(\\d+\\t(.*";
 185     protected static final String MID = ".*)+\\t===.*";
 186     protected static final String END = ")|";
 187     // Generic allocation
 188     protected static final String ALLOC_G  = "(.*call,static  wrapper for: _new_instance_Java" + END;
 189     protected static final String ALLOCA_G = "(.*call,static  wrapper for: _new_array_Java" + END;
 190     // Value type allocation
 191     protected static final String ALLOC  = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END;
 192     protected static final String ALLOCA = "(.*precise klass \\[Lcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END;
 193     protected static final String LOAD   = START + "Load(B|S|I|L|F|D|P|N)" + MID + "@compiler/valhalla/valuetypes/MyValue.*" + END;
 194     protected static final String LOADK  = START + "LoadK" + MID + END;
 195     protected static final String STORE  = START + "Store(B|C|S|I|L|F|D|P|N)" + MID + "@compiler/valhalla/valuetypes/MyValue.*" + END;
 196     protected static final String LOOP   = START + "Loop" + MID + "" + END;
 197     protected static final String COUNTEDLOOP = START + "CountedLoop\\b" + MID + "" + END;
 198     protected static final String TRAP   = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END;
 199     protected static final String RETURN = START + "Return" + MID + "returns" + END;
 200     protected static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END;
 201     protected static final String NPE = START + "CallStaticJava" + MID + "null_check" + END;
 202     protected static final String CALL = START + "CallStaticJava" + MID + END;
 203     protected static final String STOREVALUETYPEFIELDS = START + "CallStaticJava" + MID + "store_value_type_fields" + END;
 204     protected static final String SCOBJ = "(.*# ScObj.*" + END;
 205     protected static final String LOAD_UNKNOWN_VALUE = "(.*call_leaf,runtime  load_unknown_value.*" + END;
 206     protected static final String STORE_UNKNOWN_VALUE = "(.*call_leaf,runtime  store_unknown_value.*" + END;
 207     protected static final String VALUE_ARRAY_NULL_GUARD = "(.*call,static  wrapper for: uncommon_trap.*reason='null_check' action='none'.*" + END;
 208     protected static final String STORAGE_PROPERTY_CLEARING = "(.*((int:536870911)|(salq.*3\\R.*sarq.*3)).*" + END;
 209 
 210     public static String[] concat(String prefix[], String... extra) {
 211         ArrayList<String> list = new ArrayList<String>();
 212         if (prefix != null) {
 213             for (String s : prefix) {
 214                 list.add(s);
 215             }
 216         }
 217         if (extra != null) {
 218             for (String s : extra) {
 219                 list.add(s);
 220             }
 221         }
 222 
 223         return list.toArray(new String[list.size()]);
 224     }
 225 
 226     /**
 227      * Override getNumScenarios and getVMParameters if you want to run with more than
 228      * the 6 built-in scenarios
 229      */
 230     public int getNumScenarios() {
 231         return 6;
 232     }
 233 
 234     /**
 235      * VM paramaters for the 5 built-in test scenarios. If your test needs to append
 236      * extra parameters for (some of) these scenarios, override getExtraVMParameters().
 237      */
 238     public String[] getVMParameters(int scenario) {
 239         switch (scenario) {
 240         case 0: return new String[] {
 241                 "-XX:+AlwaysIncrementalInline",
 242                 "-XX:ValueArrayElemMaxFlatOops=5",
 243                 "-XX:ValueArrayElemMaxFlatSize=-1",
 244                 "-XX:ValueFieldMaxFlatSize=-1",
 245                 "-XX:+ValueTypePassFieldsAsArgs",
 246                 "-XX:+ValueTypeReturnedAsFields"};
 247         case 1: return new String[] {
 248                 "-XX:-UseCompressedOops",
 249                 "-XX:ValueArrayElemMaxFlatOops=5",
 250                 "-XX:ValueArrayElemMaxFlatSize=-1",
 251                 "-XX:ValueFieldMaxFlatSize=-1",
 252                 "-XX:-ValueTypePassFieldsAsArgs",
 253                 "-XX:-ValueTypeReturnedAsFields"};
 254         case 2: return new String[] {
 255                 "-XX:-UseCompressedOops",
 256                 "-XX:ValueArrayElemMaxFlatOops=0",
 257                 "-XX:ValueArrayElemMaxFlatSize=0",
 258                 "-XX:ValueFieldMaxFlatSize=-1",
 259                 "-XX:+ValueTypePassFieldsAsArgs",
 260                 "-XX:+ValueTypeReturnedAsFields",
 261                 "-XX:+StressValueTypeReturnedAsFields"};
 262         case 3: return new String[] {
 263                 "-DVerifyIR=false",
 264                 "-XX:+AlwaysIncrementalInline",
 265                 "-XX:ValueArrayElemMaxFlatOops=0",
 266                 "-XX:ValueArrayElemMaxFlatSize=0",
 267                 "-XX:ValueFieldMaxFlatSize=0",
 268                 "-XX:+ValueTypePassFieldsAsArgs",
 269                 "-XX:+ValueTypeReturnedAsFields"};
 270         case 4: return new String[] {
 271                 "-DVerifyIR=false",
 272                 "-XX:ValueArrayElemMaxFlatOops=-1",
 273                 "-XX:ValueArrayElemMaxFlatSize=-1",
 274                 "-XX:ValueFieldMaxFlatSize=0",
 275                 "-XX:+ValueTypePassFieldsAsArgs",
 276                 "-XX:-ValueTypeReturnedAsFields",
 277                 "-XX:-ReduceInitialCardMarks"};
 278         case 5: return new String[] {
 279                 "-XX:+AlwaysIncrementalInline",
 280                 "-XX:ValueArrayElemMaxFlatOops=5",
 281                 "-XX:ValueArrayElemMaxFlatSize=-1",
 282                 "-XX:ValueFieldMaxFlatSize=-1",
 283                 "-XX:-ValueTypePassFieldsAsArgs",
 284                 "-XX:-ValueTypeReturnedAsFields"};
 285         }
 286         return null;
 287     }
 288 
 289     /**
 290      * Override this method and return a non-null reason if the given scenario should be
 291      * ignored (due to an existing bug, etc).
 292      */
 293     String isScenarioIgnored(int scenario) {
 294         return null;
 295     }
 296 
 297     /**
 298      * Override this method to provide extra parameters for selected scenarios
 299      */
 300     public String[] getExtraVMParameters(int scenario) {
 301         return null;
 302     }
 303 
 304     public static void main(String[] args) throws Throwable {
 305         if (args.length != 1) {
 306             throw new RuntimeException("Usage: @run main/othervm/timeout=120 -Xbootclasspath/a:." +
 307                                        " -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions" +
 308                                        " -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI" +
 309                                        " compiler.valhalla.valuetypes.ValueTypeTest <YourTestMainClass>");
 310         }
 311         String testMainClassName = args[0];
 312         Class testMainClass = Class.forName(testMainClassName);
 313         ValueTypeTest test = (ValueTypeTest)testMainClass.newInstance();
 314         List<String> scenarios = null;
 315         if (!SCENARIOS.isEmpty()) {
 316            scenarios = Arrays.asList(SCENARIOS.split(","));
 317         }
 318         for (int i=0; i<test.getNumScenarios(); i++) {
 319             String reason;
 320             if ((reason = test.isScenarioIgnored(i)) != null) {
 321                 System.out.println("Scenario #" + i + " is ignored: " + reason);
 322             } else if (scenarios != null && !scenarios.contains(Integer.toString(i))) {
 323                 System.out.println("Scenario #" + i + " is skipped due to -Dscenarios=" + SCENARIOS);
 324             } else {
 325                 System.out.println("Scenario #" + i + " -------- ");
 326                 String[] cmds = InputArguments.getVmInputArgs();
 327                 if (RUN_SCENARIOS_WITH_XCOMP) {
 328                     cmds = concat(cmds, "-Xcomp");
 329                 }
 330                 cmds = concat(cmds, test.getVMParameters(i));
 331                 cmds = concat(cmds, test.getExtraVMParameters(i));
 332                 cmds = concat(cmds, testMainClassName);
 333 
 334                 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds);
 335                 String output = oa.getOutput();
 336                 oa.shouldHaveExitValue(0);
 337                 System.out.println(output);
 338             }
 339         }
 340     }
 341 
 342     // To exclude test cases, use -DExclude=<case1>,<case2>,...
 343     // Each case can be just the method name, or can be <class>.<method>. The latter form is useful
 344     // when you are running several tests at the same time.
 345     //
 346     // jtreg -DExclude=test12 TestArrays.java
 347     // jtreg -DExclude=test34 TestLWorld.java
 348     // -- or --
 349     // jtreg -DExclude=TestArrays.test12,TestLWorld.test34 TestArrays.java TestLWorld.java
 350     //
 351     private List<String> buildExcludeList() {
 352         List<String> exclude = null;
 353         String classPrefix = getClass().getSimpleName() + ".";
 354         if (!EXCLUDELIST.isEmpty()) {
 355             exclude = new ArrayList(Arrays.asList(EXCLUDELIST.split(",")));
 356             for (int i = exclude.size() - 1; i >= 0; i--) {
 357                 String ex = exclude.get(i);
 358                 if (ex.indexOf(".") > 0) {
 359                     if (ex.startsWith(classPrefix)) {
 360                         ex = ex.substring(classPrefix.length());
 361                         exclude.set(i, ex);
 362                     } else {
 363                         exclude.remove(i);
 364                     }
 365                 }
 366             }
 367         }
 368         return exclude;
 369     }
 370 
 371     protected ValueTypeTest() {
 372         List<String> list = null;
 373         if (!TESTLIST.isEmpty()) {
 374            list = Arrays.asList(TESTLIST.split(","));
 375         }
 376         List<String> exclude = buildExcludeList();
 377 
 378         // Gather all test methods and put them in Hashtable
 379         for (Method m : getClass().getDeclaredMethods()) {
 380             Test[] annos = m.getAnnotationsByType(Test.class);
 381             if (annos.length != 0 &&
 382                 ((list == null || list.contains(m.getName())) && (exclude == null || !exclude.contains(m.getName())))) {
 383                 tests.put(getClass().getSimpleName() + "::" + m.getName(), m);
 384             }
 385         }
 386     }
 387 
 388     protected void run(String[] args, Class<?>... classes) throws Throwable {
 389         if (args.length == 0) {
 390             // Spawn a new VM instance
 391             execute_vm();
 392         } else {
 393             // Execute tests in the VM spawned by the above code.
 394             Asserts.assertTrue(args.length == 1 && args[0].equals("run"), "must be");
 395             run(classes);
 396         }
 397     }
 398 
 399     private void execute_vm() throws Throwable {
 400         Asserts.assertFalse(tests.isEmpty(), "no tests to execute");
 401         String[] vmInputArgs = InputArguments.getVmInputArgs();
 402         for (String arg : vmInputArgs) {
 403             if (arg.startsWith("-XX:CompileThreshold")) {
 404                 // Disable IR verification if non-default CompileThreshold is set
 405                 VERIFY_IR = false;
 406             }
 407         }
 408         // Each VM is launched with flags in this order, so the later ones can override the earlier one:
 409         //     VERIFY_IR/VERIFY_VM flags specified below
 410         //     vmInputArgs, which consists of:
 411         //        @run options
 412         //        getVMParameters()
 413         //        getExtraVMParameters()
 414         //     defaultFlags
 415         String cmds[] = null;
 416         if (VERIFY_IR) {
 417             // Add print flags for IR verification
 418             cmds = concat(cmds, printFlags);
 419             // Always trap for exception throwing to not confuse IR verification
 420             cmds = concat(cmds, "-XX:-OmitStackTraceInFastThrow");
 421         }
 422         if (VERIFY_VM) {
 423             cmds = concat(cmds, verifyFlags);
 424         }
 425         cmds = concat(cmds, vmInputArgs);
 426         cmds = concat(cmds, defaultFlags);
 427 
 428         // Run tests in own process and verify output
 429         cmds = concat(cmds, getClass().getName(), "run");
 430         OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds);
 431         // If ideal graph printing is enabled/supported, verify output
 432         String output = oa.getOutput();
 433         oa.shouldHaveExitValue(0);
 434         if (VERIFY_IR) {
 435             if (output.contains("PrintIdeal enabled")) {
 436                 parseOutput(output);
 437             } else {
 438                 System.out.println(output);
 439                 System.out.println("WARNING: IR verification failed! Running with -Xint, -Xcomp or release build?");
 440             }
 441         }
 442     }
 443 
 444     private void parseOutput(String output) throws Exception {
 445         Pattern comp_re = Pattern.compile("\\n\\s+\\d+\\s+\\d+\\s+(%| )(s| )(!| )b(n| )\\s+\\d?\\s+\\S+\\.(?<name>[^.]+::\\S+)\\s+(?<osr>@ \\d+\\s+)?[(]\\d+ bytes[)]");
 446         Matcher m = comp_re.matcher(output);
 447         Map<String,String> compilations = new LinkedHashMap<>();
 448         int prev = 0;
 449         String methodName = null;
 450         while (m.find()) {
 451             if (prev == 0) {
 452                 // Print header
 453                 System.out.print(output.substring(0, m.start()+1));
 454             } else if (methodName != null) {
 455                 compilations.put(methodName, output.substring(prev, m.start()+1));
 456             }
 457             if (m.group("osr") != null) {
 458                 methodName = null;
 459             } else {
 460                 methodName = m.group("name");
 461             }
 462             prev = m.end();
 463         }
 464         if (prev == 0) {
 465             // Print header
 466             System.out.print(output);
 467         } else if (methodName != null) {
 468             compilations.put(methodName, output.substring(prev));
 469         }
 470         // Iterate over compilation output
 471         for (String testName : compilations.keySet()) {
 472             Method test = tests.get(testName);
 473             if (test == null) {
 474                 // Skip helper methods
 475                 continue;
 476             }
 477             String graph = compilations.get(testName);
 478             if (PRINT_GRAPH) {
 479                 System.out.println("\nGraph for " + testName + "\n" + graph);
 480             }
 481             // Parse graph using regular expressions to determine if it contains forbidden nodes
 482             Test[] annos = test.getAnnotationsByType(Test.class);
 483             Test anno = null;
 484             for (Test a : annos) {
 485                 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) {
 486                     assert anno == null;
 487                     anno = a;
 488                 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) {
 489                     assert anno == null;
 490                     anno = a;
 491                 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) {
 492                     assert anno == null;
 493                     anno = a;
 494                 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) {
 495                     assert anno == null;
 496                     anno = a;
 497                 } else if ((a.valid() & ValueTypeReturnedAsFieldsOn) != 0 && ValueTypeReturnedAsFields) {
 498                     assert anno == null;
 499                     anno = a;
 500                 } else if ((a.valid() & ValueTypeReturnedAsFieldsOff) != 0 && !ValueTypeReturnedAsFields) {
 501                     assert anno == null;
 502                     anno = a;
 503                 } else if ((a.valid() & AlwaysIncrementalInlineOn) != 0 && AlwaysIncrementalInline) {
 504                     assert anno == null;
 505                     anno = a;
 506                 } else if ((a.valid() & AlwaysIncrementalInlineOff) != 0 && !AlwaysIncrementalInline) {
 507                     assert anno == null;
 508                     anno = a;
 509                 } else if ((a.valid() & G1GCOn) != 0 && G1GC) {
 510                     assert anno == null;
 511                     anno = a;
 512                 } else if ((a.valid() & G1GCOff) != 0 && !G1GC) {
 513                     assert anno == null;
 514                     anno = a;
 515                 }
 516             }
 517             assert anno != null;
 518             String regexFail = anno.failOn();
 519             if (!regexFail.isEmpty()) {
 520                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
 521                 Matcher matcher = pattern.matcher(graph);
 522                 boolean found = matcher.find();
 523                 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : ""));
 524             }
 525             String[] regexMatch = anno.match();
 526             int[] matchCount = anno.matchCount();
 527             for (int i = 0; i < regexMatch.length; ++i) {
 528                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
 529                 Matcher matcher = pattern.matcher(graph);
 530                 int count = 0;
 531                 String nodes = "";
 532                 while (matcher.find()) {
 533                     count++;
 534                     nodes += matcher.group() + "\n";
 535                 }
 536 
 537                 if (TieredCompilation) {
 538                     // FIXME: TestLWorld.test88 fails with "expected 4 to equal 2". See JDK-8230925
 539                     continue;
 540                 }
 541 
 542                 if (matchCount[i] < 0) {
 543                     Asserts.assertLTE(Math.abs(matchCount[i]), count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes);
 544                 } else {
 545                     Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes);
 546                 }
 547             }
 548             tests.remove(testName);
 549             System.out.println(testName + " passed");
 550         }
 551         // Check if all tests were compiled
 552         if (tests.size() != 0) {
 553             for (String name : tests.keySet()) {
 554                 System.out.println("Test '" + name + "' not compiled!");
 555             }
 556             throw new RuntimeException("Not all tests were compiled");
 557         }
 558     }
 559 
 560     private void setup(Class<?> clazz) {
 561         if (XCOMP) {
 562             // Don't control compilation if -Xcomp is enabled
 563             return;
 564         }
 565         if (DUMP_REPLAY) {
 566             // Generate replay compilation files
 567             String directive = "[{ match: \"*.*\", DumpReplay: true }]";
 568             if (WHITE_BOX.addCompilerDirective(directive) != 1) {
 569                 throw new RuntimeException("Failed to add compiler directive");
 570             }
 571         }
 572 
 573         Method[] methods = clazz.getDeclaredMethods();
 574         for (Method m : methods) {
 575             if (m.isAnnotationPresent(Test.class)) {
 576                 // Don't inline tests
 577                 WHITE_BOX.testSetDontInlineMethod(m, true);
 578             }
 579             if (m.isAnnotationPresent(DontCompile.class)) {
 580                 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true);
 581                 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false);
 582                 WHITE_BOX.testSetDontInlineMethod(m, true);
 583             } else if (m.isAnnotationPresent(ForceCompile.class)) {
 584                 int compLevel = getCompLevel(m.getAnnotation(ForceCompile.class));
 585                 enqueueMethodForCompilation(m, compLevel);
 586             }
 587             if (m.isAnnotationPresent(ForceInline.class)) {
 588                 WHITE_BOX.testSetForceInlineMethod(m, true);
 589             } else if (m.isAnnotationPresent(DontInline.class)) {
 590                 WHITE_BOX.testSetDontInlineMethod(m, true);
 591             }
 592         }
 593 
 594         // Compile class initializers
 595         int compLevel = getCompLevel(null);
 596         WHITE_BOX.enqueueInitializerForCompilation(clazz, compLevel);
 597     }
 598 
 599     private void run(Class<?>... classes) throws Exception {
 600         if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
 601             System.out.println("PrintIdeal enabled");
 602         }
 603         System.out.format("rI = %d, rL = %d\n", rI, rL);
 604 
 605         setup(getClass());
 606         for (Class<?> clazz : classes) {
 607             setup(clazz);
 608         }
 609 
 610         // Execute tests
 611         TreeMap<Long, String> durations = (PRINT_TIMES || VERBOSE) ? new TreeMap<Long, String>() : null;
 612         for (Method test : tests.values()) {
 613             if (VERBOSE) {
 614                 System.out.println("Starting " + test.getName());
 615             }
 616             TempSkipForC1 c1skip = test.getAnnotation(TempSkipForC1.class);
 617             if (TEST_C1 && c1skip != null) {
 618                 System.out.println("Skipped " + test.getName() + " for C1 testing: " + c1skip.reason());
 619                 continue;
 620             }
 621             long startTime = System.nanoTime();
 622             Method verifier = getClass().getMethod(test.getName() + "_verifier", boolean.class);
 623             // Warmup using verifier method
 624             Warmup anno = test.getAnnotation(Warmup.class);
 625             int warmup = anno == null ? WARMUP : anno.value();
 626             for (int i = 0; i < warmup; ++i) {
 627                 verifier.invoke(this, true);
 628             }
 629             boolean osrOnly = (test.getAnnotation(OSRCompileOnly.class) != null);
 630 
 631             // C1 generates a lot of code when VerifyOops is enabled and may run out of space (for a small
 632             // number of test cases).
 633             boolean maybeCodeBufferOverflow = (TEST_C1 && VerifyOops);
 634 
 635             if (osrOnly) {
 636                 long started = System.currentTimeMillis();
 637                 boolean stateCleared = false;
 638                 for (;;)  {
 639                     long elapsed = System.currentTimeMillis() - started;
 640                     if (maybeCodeBufferOverflow && elapsed > 5000 && !WHITE_BOX.isMethodCompiled(test, false)) {
 641                         System.out.println("Temporarily disabling VerifyOops");
 642                         try {
 643                             WHITE_BOX.setBooleanVMFlag("VerifyOops", false);
 644                             if (!stateCleared) {
 645                                 WHITE_BOX.clearMethodState(test);
 646                                 stateCleared = true;
 647                             }
 648                             verifier.invoke(this, false);
 649                         } finally {
 650                             WHITE_BOX.setBooleanVMFlag("VerifyOops", true);
 651                             System.out.println("Re-enabled VerifyOops");
 652                         }
 653                     } else {
 654                         verifier.invoke(this, false);
 655                     }
 656 
 657                     boolean b = WHITE_BOX.isMethodCompiled(test, false);
 658                     if (VERBOSE) {
 659                         System.out.println("Is " + test.getName() + " compiled? " + b);
 660                     }
 661                     if (b || XCOMP || !USE_COMPILER) {
 662                         // Don't control compilation if -Xcomp is enabled, or if compiler is disabled
 663                         break;
 664                     }
 665                     if (OSRTestTimeOut > 0 && elapsed > OSRTestTimeOut) {
 666                         break;
 667                     }
 668                 }
 669                 if (!XCOMP) {
 670                     Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
 671                 }
 672             } else {
 673                 int compLevel = getCompLevel(test.getAnnotation(Test.class));
 674                 // Trigger compilation
 675                 enqueueMethodForCompilation(test, compLevel);
 676                 if (maybeCodeBufferOverflow && !WHITE_BOX.isMethodCompiled(test, false)) {
 677                     // Let's disable VerifyOops temporarily and retry.
 678                     WHITE_BOX.setBooleanVMFlag("VerifyOops", false);
 679                     WHITE_BOX.clearMethodState(test);
 680                     enqueueMethodForCompilation(test, compLevel);
 681                     WHITE_BOX.setBooleanVMFlag("VerifyOops", true);
 682                 }
 683                 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
 684                 // Check result
 685                 verifier.invoke(this, false);
 686             }
 687             if (PRINT_TIMES || VERBOSE) {
 688                 long endTime = System.nanoTime();
 689                 long duration = (endTime - startTime);
 690                 durations.put(duration, test.getName());
 691                 if (VERBOSE) {
 692                     System.out.println("Done " + test.getName() + ": " + duration + " ns = " + (duration / 1000000) + " ms");
 693                 }
 694             }
 695             if (GCAfter) {
 696                 System.out.println("doing GC");
 697                 System.gc();
 698             }
 699         }
 700 
 701         // Print execution times
 702         if (PRINT_TIMES) {
 703           System.out.println("\n\nTest execution times:");
 704           for (Map.Entry<Long, String> entry : durations.entrySet()) {
 705               System.out.format("%-10s%15d ns\n", entry.getValue() + ":", entry.getKey());
 706           }
 707         }
 708     }
 709 
 710     // Get the appropriate compilation level for a method, according to the
 711     // given annotation, as well as the current test scenario and VM options.
 712     //
 713     private int getCompLevel(Object annotation) {
 714         int compLevel;
 715         if (annotation == null) {
 716             compLevel = COMP_LEVEL_ANY;
 717         } else if (annotation instanceof Test) {
 718             compLevel = ((Test)annotation).compLevel();
 719         } else {
 720             compLevel = ((ForceCompile)annotation).compLevel();
 721         }
 722 
 723         return restrictCompLevel(compLevel);
 724     }
 725 
 726     // Get the appropriate level as permitted by the test scenario and VM options.
 727     private static int restrictCompLevel(int compLevel) {
 728         if (compLevel == COMP_LEVEL_ANY) {
 729             compLevel = COMP_LEVEL_FULL_OPTIMIZATION;
 730         }
 731         if (FLIP_C1_C2) {
 732             // Effectively treat all (compLevel = C1) as (compLevel = C2), and
 733             //                       (compLevel = C2) as (compLevel = C1).
 734             if (compLevel == COMP_LEVEL_SIMPLE) {
 735                 compLevel = COMP_LEVEL_FULL_OPTIMIZATION;
 736             } else if (compLevel == COMP_LEVEL_FULL_OPTIMIZATION) {
 737                 compLevel = COMP_LEVEL_SIMPLE;
 738             }
 739         }
 740         if (!TEST_C1 && compLevel < COMP_LEVEL_FULL_OPTIMIZATION) {
 741             compLevel = COMP_LEVEL_FULL_OPTIMIZATION;
 742         }
 743         if (compLevel > (int)TieredStopAtLevel) {
 744             compLevel = (int)TieredStopAtLevel;
 745         }
 746         return compLevel;
 747     }
 748 
 749     public static void enqueueMethodForCompilation(Method m, int level) {
 750         level = restrictCompLevel(level);
 751         if (VERBOSE) {
 752             System.out.println("enqueueMethodForCompilation " + m + ", level = " + level);
 753         }
 754         WHITE_BOX.enqueueMethodForCompilation(m, level);
 755     }
 756 
 757     // Unlike C2, C1 intrinsics never deoptimize System.arraycopy. Instead, we fall back to
 758     // a normal method invocation when encountering flattened arrays.
 759     static boolean isCompiledByC2(Method m) {
 760         int CompLevel_none              = 0,         // Interpreter
 761             CompLevel_simple            = 1,         // C1
 762             CompLevel_limited_profile   = 2,         // C1, invocation & backedge counters
 763             CompLevel_full_profile      = 3,         // C1, invocation & backedge counters + mdo
 764             CompLevel_full_optimization = 4;         // C2 or JVMCI
 765 
 766         return USE_COMPILER && !XCOMP && WHITE_BOX.isMethodCompiled(m, false) &&
 767             WHITE_BOX.getMethodCompilationLevel(m, false) >= CompLevel_full_optimization;
 768     }
 769 }