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 ir_framework.tests;
  25 
  26 import compiler.lib.ir_framework.*;
  27 import compiler.lib.ir_framework.driver.irmatching.IRViolationException;
  28 import jdk.test.lib.Asserts;
  29 import jdk.test.lib.Platform;
  30 import jdk.test.whitebox.WhiteBox;
  31 
  32 import java.io.ByteArrayOutputStream;
  33 import java.io.PrintStream;
  34 import java.util.*;
  35 import java.util.regex.Matcher;
  36 import java.util.regex.Pattern;
  37 import java.util.stream.Collectors;
  38 
  39 /*
  40  * @test
  41  * @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler1.enabled & vm.compiler2.enabled & vm.flagless
  42  * @summary Test IR matcher with different default IR node regexes. Use -DPrintApplicableIRRules.
  43  *          Normally, the framework should be called with driver.
  44  * @library /test/lib /testlibrary_tests /
  45  * @build jdk.test.whitebox.WhiteBox
  46  * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
  47  * @run main/othervm/timeout=240 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  48  *                               -XX:+WhiteBoxAPI -DPrintApplicableIRRules=true  ir_framework.tests.TestIRMatching
  49  */
  50 
  51 public class TestIRMatching {
  52 
  53     private static final Map<Exception, String> exceptions = new LinkedHashMap<>();
  54     private static final ByteArrayOutputStream baos = new ByteArrayOutputStream();
  55     private static final ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
  56     private static final PrintStream ps = new PrintStream(baos);
  57     private static final PrintStream psErr = new PrintStream(baosErr);
  58     private static final PrintStream oldOut = System.out;
  59     private static final PrintStream oldErr = System.err;
  60 
  61     private static void addException(Exception e) {
  62         System.out.flush();
  63         System.err.flush();
  64         exceptions.put(e, baos + System.lineSeparator() + baosErr);
  65     }
  66 
  67     public static void main(String[] args) {
  68         // Redirect System.out and System.err to reduce noise.
  69         System.setOut(ps);
  70         System.setErr(psErr);
  71         runWithArguments(AndOr1.class, "-XX:TLABRefillWasteFraction=52", "-XX:+UsePerfData", "-XX:+UseTLAB");
  72         runWithArguments(CountComparisons.class, "-XX:TLABRefillWasteFraction=50");
  73         runWithArguments(GoodCount.class, "-XX:TLABRefillWasteFraction=50");
  74         runWithArguments(MultipleFailOnGood.class, "-XX:TLABRefillWasteFraction=50");
  75 
  76         runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:+UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test1", 1, "CallStaticJava"));
  77         runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:-UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test2", 1, "CallStaticJava"));
  78 
  79         runCheck(BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1", 1, 1, "Store"),
  80                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1", 1, 3, "Store"),
  81                  GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail1", 1, 2, 4),
  82                  GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail2", 1, 1),
  83                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail2", 1, 2, "CallStaticJava"),
  84                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail3", 1, 2, "Store"),
  85                  GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail3", 1, 1, 3),
  86                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail4", 1, 1, "Store"),
  87                  GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail4", 1, 2, 3),
  88                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail5", 1, 1, "Store"),
  89                  GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail5", 1, 2, 3),
  90                  GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail6", 1, 1),
  91                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail6", 1, 2, "MyClass"),
  92                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail6", 1, 3, "CallStaticJava"),
  93                  GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail7", 1, 1),
  94                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail7", 1, 2, "MyClass"),
  95                  GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail8", 1, 1),
  96                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail8", 1, 2, "MyClass"),
  97                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail9", 1, 1, "Store"),
  98                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail9", 1, 2, "CallStaticJava"),
  99                  BadFailOnConstraint.create(MultipleFailOnBad.class, "fail10", 1, 1, "Store", "iFld"),
 100                  GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail10", 1, 2, 3)
 101         );
 102 
 103         runCheck(BadCountsConstraint.create(BadCount.class, "bad1", 1, 2, "Load"),
 104                  GoodCountsConstraint.create(BadCount.class, "bad1", 2),
 105                  GoodCountsConstraint.create(BadCount.class, "bad2", 1),
 106                  BadCountsConstraint.create(BadCount.class, "bad2", 2, 2,"Store"),
 107                  BadCountsConstraint.create(BadCount.class, "bad3", 1, 2,"Load"),
 108                  BadCountsConstraint.create(BadCount.class, "bad3", 2, 2,"Store")
 109         );
 110 
 111         runCheck(GoodRuleConstraint.create(Calls.class, "calls", 1),
 112                  BadFailOnConstraint.create(Calls.class, "calls", 2, 1, "CallStaticJava", "dontInline"),
 113                  BadFailOnConstraint.create(Calls.class, "calls", 2, 2, "CallStaticJava", "dontInline"),
 114                  GoodRuleConstraint.create(Calls.class, "calls", 3)
 115         );
 116 
 117         runCheck(BadFailOnConstraint.create(AllocInstance.class, "allocInstance", 1),
 118                 BadFailOnConstraint.create(AllocInstance.class, "allocInstance", 2),
 119                 GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 3),
 120                 GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 4),
 121                 GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 5),
 122                 BadFailOnConstraint.create(AllocInstance.class, "allocInstance", 6),
 123                 BadFailOnConstraint.create(AllocInstance.class, "allocInstance", 7),
 124                 GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 8),
 125                 GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 9),
 126                 GoodFailOnConstraint.create(AllocInstance.class, "allocInstance", 10)
 127         );
 128 
 129         runCheck(
 130                 BadFailOnConstraint.create(AllocInstance.class, "allocNested", 1),
 131                 BadFailOnConstraint.create(AllocInstance.class, "allocNested", 2),
 132                 BadFailOnConstraint.create(AllocInstance.class, "allocNested", 3)
 133         );
 134 
 135         runCheck(BadFailOnConstraint.create(AllocArray.class, "allocArray", 1),
 136                  BadFailOnConstraint.create(AllocArray.class, "allocArray", 2),
 137                  GoodFailOnConstraint.create(AllocArray.class, "allocArray", 3),
 138                  GoodFailOnConstraint.create(AllocArray.class, "allocArray", 4),
 139                  GoodFailOnConstraint.create(AllocArray.class, "allocArray", 5),
 140                  BadFailOnConstraint.create(AllocArray.class, "allocArray", 6),
 141                  BadFailOnConstraint.create(AllocArray.class, "allocArray", 7),
 142                  GoodFailOnConstraint.create(AllocArray.class, "allocArray", 8),
 143                  GoodFailOnConstraint.create(AllocArray.class, "allocArray", 9),
 144                  GoodFailOnConstraint.create(AllocArray.class, "allocArray", 10)
 145         );
 146 
 147         runCheck(BadFailOnConstraint.create(AllocArray.class, "allocMultiArray", 1),
 148                  BadFailOnConstraint.create(AllocArray.class, "allocMultiArray", 2),
 149                  GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 3),
 150                  GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 4),
 151                  GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 5),
 152                  BadFailOnConstraint.create(AllocArray.class, "allocMultiArray", 6),
 153                  BadFailOnConstraint.create(AllocArray.class, "allocMultiArray", 7),
 154                  GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 8),
 155                  GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 9),
 156                  GoodFailOnConstraint.create(AllocArray.class, "allocMultiArray", 10)
 157         );
 158 
 159         runCheck(GoodRuleConstraint.create(RunTests.class, "good1", 1),
 160                  GoodRuleConstraint.create(RunTests.class, "good1", 2),
 161                  GoodRuleConstraint.create(RunTests.class, "good2", 1),
 162                  GoodRuleConstraint.create(RunTests.class, "good2", 2),
 163                  GoodRuleConstraint.create(RunTests.class, "good3", 1),
 164                  BadCountsConstraint.create(RunTests.class, "bad1", 1, 0),
 165                  BadFailOnConstraint.create(RunTests.class, "bad1", 2, "Load")
 166         );
 167 
 168         // Loops
 169         runCheck(BadFailOnConstraint.create(Loops.class, "loop", 1, "Loop"),
 170                  GoodRuleConstraint.create(Loops.class, "loop", 2),
 171                  GoodRuleConstraint.create(Loops.class, "loop", 3),
 172                  GoodRuleConstraint.create(Loops.class, "countedLoop", 1),
 173                  BadFailOnConstraint.create(Loops.class, "countedLoop", 2, "CountedLoop"),
 174                  GoodRuleConstraint.create(Loops.class, "countedLoop", 3),
 175                  BadFailOnConstraint.create(Loops.class, "loopAndCountedLoop", 1, "Loop"),
 176                  BadFailOnConstraint.create(Loops.class, "loopAndCountedLoop", 2, "CountedLoop"),
 177                  GoodRuleConstraint.create(Loops.class, "loopAndCountedLoop", 3),
 178                  GoodRuleConstraint.create(Loops.class, "countedLoopMain", 1),
 179                  BadFailOnConstraint.create(Loops.class, "countedLoopMain", 2, "CountedLoop"),
 180                  BadFailOnConstraint.create(Loops.class, "countedLoopMain", 3, "CountedLoop", "main"),
 181                  GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled", 1),
 182                  GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled", 2),
 183                  GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled", 3)
 184         );
 185 
 186         // Traps
 187         runCheck(GoodRuleConstraint.create(Traps.class, "noTraps", 1),
 188                  BadFailOnConstraint.create(Traps.class, "noTraps", 2, "Store", "iFld"),
 189                  GoodRuleConstraint.create(Traps.class, "noTraps", 3),
 190                  BadFailOnConstraint.create(Traps.class, "predicateTrap", 1, "CallStaticJava", "uncommon_trap"),
 191                  BadFailOnConstraint.create(Traps.class, "predicateTrap", 2, "CallStaticJava", "uncommon_trap", "predicate"),
 192                  GoodRuleConstraint.create(Traps.class, "predicateTrap", 3),
 193                  GoodRuleConstraint.create(Traps.class, "predicateTrap", 4),
 194                  BadFailOnConstraint.create(Traps.class, "nullCheck", 1, "CallStaticJava", "uncommon_trap"),
 195                  BadFailOnConstraint.create(Traps.class, "nullCheck", 2, "CallStaticJava", "uncommon_trap", "null_check"),
 196                  BadFailOnConstraint.create(Traps.class, "nullCheck", 3, "uncommon_trap", "class_check"),
 197                  GoodRuleConstraint.create(Traps.class, "nullCheck", 4),
 198                  BadFailOnConstraint.create(Traps.class, "nullAssert", 1, "CallStaticJava", "uncommon_trap"),
 199                  BadFailOnConstraint.create(Traps.class, "nullAssert", 2, "CallStaticJava", "uncommon_trap", "null_assert"),
 200                  BadFailOnConstraint.create(Traps.class, "nullAssert", 3, "CallStaticJava", "uncommon_trap", "null_check"),
 201                  GoodRuleConstraint.create(Traps.class, "nullAssert", 4),
 202                  BadFailOnConstraint.create(Traps.class, "unstableIf", 1, "CallStaticJava", "uncommon_trap"),
 203                  BadFailOnConstraint.create(Traps.class, "unstableIf", 2, "CallStaticJava", "uncommon_trap", "unstable_if"),
 204                  GoodRuleConstraint.create(Traps.class, "unstableIf", 3),
 205                  BadFailOnConstraint.create(Traps.class, "classCheck", 1, "CallStaticJava", "uncommon_trap"),
 206                  BadFailOnConstraint.create(Traps.class, "classCheck", 2, "CallStaticJava", "uncommon_trap", "class_check"),
 207                  BadFailOnConstraint.create(Traps.class, "classCheck", 3, "CallStaticJava", "uncommon_trap", "null_check"),
 208                  GoodRuleConstraint.create(Traps.class, "classCheck", 4),
 209                  BadFailOnConstraint.create(Traps.class, "rangeCheck", 1, "CallStaticJava", "uncommon_trap"),
 210                  BadFailOnConstraint.create(Traps.class, "rangeCheck", 2, "CallStaticJava", "uncommon_trap", "range_check"),
 211                  BadFailOnConstraint.create(Traps.class, "rangeCheck", 3, "CallStaticJava", "uncommon_trap", "null_check"),
 212                  GoodRuleConstraint.create(Traps.class, "rangeCheck", 4),
 213                  BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 1, "CallStaticJava", "uncommon_trap"),
 214                  WhiteBox.getWhiteBox().isJVMCISupportedByGC() ?
 215                     BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 2, "CallStaticJava", "uncommon_trap", "intrinsic_or_type_checked_inlining")
 216                     : GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 2),
 217                  BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 3, "CallStaticJava", "uncommon_trap", "intrinsic"),
 218                  BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 4, "CallStaticJava", "uncommon_trap", "null_check"),
 219                  GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining", 5)
 220         );
 221 
 222 
 223         runCheck(new String[] {"-XX:+BailoutToInterpreterForThrows"},
 224                  BadFailOnConstraint.create(UnhandledTrap.class, "unhandled", 1, "CallStaticJava", "uncommon_trap"),
 225                  BadFailOnConstraint.create(UnhandledTrap.class, "unhandled", 2, "CallStaticJava", "uncommon_trap", "unhandled"),
 226                  GoodRuleConstraint.create(UnhandledTrap.class, "unhandled", 3)
 227         );
 228 
 229         runCheck(BadFailOnConstraint.create(ScopeObj.class, "scopeObject", 1, "ScObj"));
 230         runCheck(BadFailOnConstraint.create(Membar.class, "membar", 1, "MemBar"));
 231 
 232         String cmp;
 233         if (Platform.isPPC() || Platform.isX86()) {
 234             cmp = "CMP";
 235         } else if (Platform.isS390x()){
 236             cmp = "CLFI";
 237         } else {
 238             cmp = "cmp";
 239         }
 240         runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array", 1, cmp, "Constant"),
 241                  BadFailOnConstraint.create(CheckCastArray.class, "array", 2, 1,cmp, "Constant", "MyClass"),
 242                  BadFailOnConstraint.create(CheckCastArray.class, "array", 2, 2,cmp, "Constant", "ir_framework/tests/MyClass"),
 243                  GoodFailOnConstraint.create(CheckCastArray.class, "array", 3),
 244                  Platform.isS390x() ? // There is no checkcast_arraycopy stub for C2 on s390
 245                      GoodFailOnConstraint.create(CheckCastArray.class, "arrayCopy", 1)
 246                      : BadFailOnConstraint.create(CheckCastArray.class, "arrayCopy", 1, "checkcast_arraycopy")
 247         );
 248 
 249         try {
 250             runWithArgumentsFail(CompilationOutputOfFails.class);
 251             Asserts.fail("Should have thrown exception");
 252         } catch (IRViolationException e) {
 253             try {
 254                 StringBuilder failures = new StringBuilder();
 255                 System.out.flush();
 256                 String output = baos.toString();
 257                 baos.reset();
 258                 Pattern pattern = Pattern.compile(compilationPrefix() + ".*both\\d.*\\R> Phase \""
 259                                                   + CompilePhase.PRINT_IDEAL.getName()
 260                                                   + "\":(?:(?!PrintOpto|" + compilationPrefix()
 261                                                   + ")[\\S\\s])+PrintOptoAssembly");
 262                 Matcher matcher = pattern.matcher(output);
 263                 long bothCount = matcher.results().count();
 264                 if (bothCount != 7L) {
 265                     failures.append("- Could not find all both() methods, expected 7 but found ").append(bothCount)
 266                             .append(System.lineSeparator());
 267                 }
 268                 pattern = Pattern.compile(compilationPrefix() + ".*ideal\\d.*\\R> Phase \""
 269                                           + CompilePhase.PRINT_IDEAL.getName()
 270                                           + "\":(?:(?!" + compilationPrefix() + ")[\\S\\s])+");
 271                 matcher = pattern.matcher(output);
 272                 int count = 0;
 273                 while (matcher.find()) {
 274                     String match = matcher.group();
 275                     if (match.contains("PrintOptoAssembly")) {
 276                         failures.append("Cannot contain opto assembly: ").append(System.lineSeparator()).append(match);
 277                     }
 278                     count++;
 279                 }
 280                 if (count != 7) {
 281                     failures.append("- Could not find all ideal() methods, expected 7 but found ").append(count)
 282                             .append(System.lineSeparator());
 283                 }
 284                 pattern = Pattern.compile(compilationPrefix() + ".*macro\\d.*\\R> Phase \""
 285                         + CompilePhase.BEFORE_MACRO_EXPANSION.getName()
 286                         + "\":(?:(?!" + compilationPrefix() + ")[\\S\\s])+");
 287                 matcher = pattern.matcher(output);
 288                 count = 0;
 289                 while (matcher.find()) {
 290                     String match = matcher.group();
 291                     if (match.contains("PrintIdeal")) {
 292                         failures.append("Cannot contain print assembly: ").append(System.lineSeparator()).append(match);
 293                     }
 294                     count++;
 295                 }
 296                 if (count != 7) {
 297                     failures.append("- Could not find all macro() methods, expected 7 but found ").append(count).append(System.lineSeparator());
 298                 }
 299                 if (!failures.isEmpty()) {
 300                     addException(new RuntimeException(failures.toString()));
 301                 }
 302             } catch (Exception e1) {
 303                 addException(e1);
 304             }
 305         } catch (Exception e) {
 306             addException(e);
 307         }
 308 
 309         runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=50");
 310         System.out.flush();
 311         String output = baos.toString();
 312         findIrIds(output, "testMatchAllIf50", 1, 22);
 313         assertNoIds(output, "testMatchNoneIf50");
 314 
 315         runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=49");
 316         System.out.flush();
 317         output = baos.toString();
 318         findIrIds(output, "testMatchAllIf50", 5, 7, 14, 19);
 319         findIrIds(output, "testMatchNoneIf50", 1, 4, 9, 11, 18, 23);
 320 
 321         runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=51");
 322         System.out.flush();
 323         output = baos.toString();
 324         findIrIds(output, "testMatchAllIf50", 8, 13, 20, 22);
 325         findIrIds(output, "testMatchNoneIf50", 5, 8, 12, 17, 21, 23);
 326         System.setOut(oldOut);
 327         System.setErr(oldErr);
 328 
 329         if (!exceptions.isEmpty()) {
 330             System.err.println("TestIRMatching failed with " + exceptions.size() + " exception(s):");
 331             int i = 1;
 332             System.err.println("************************");
 333             for (Map.Entry<Exception, String> entry : exceptions.entrySet()) {
 334                 System.err.println("***** Exception " + String.format("%02d", i++) +" *****");
 335                 System.err.println("************************");
 336 
 337                 Exception e = entry.getKey();
 338                 e.printStackTrace(System.err);
 339                 System.err.println();
 340                 System.err.println("===== OUTPUT ======");
 341                 System.err.println(entry.getValue());
 342                 System.err.println("MESSAGE: " + e.getMessage());
 343                 System.err.println("************************");
 344             }
 345             i = 1;
 346             System.err.println("====================================");
 347             System.err.println("********************");
 348             System.err.println("***** OVERVIEW *****");
 349             System.err.println("********************");
 350             for (Map.Entry<Exception, String> entry : exceptions.entrySet()) {
 351                 System.err.print((i++) + ") ");
 352                 entry.getKey().printStackTrace(System.err);
 353                 System.err.println("********************");
 354             }
 355             throw new RuntimeException("TestIRMatching failed with " + exceptions.size() + " exception(s) - check stderr and stdout");
 356         }
 357     }
 358 
 359     private static void runFramework(TestFramework framework) {
 360         baos.reset();
 361         baosErr.reset();
 362         framework.start();
 363     }
 364 
 365     private static void runWithArguments(Class<?> clazz, String... args) {
 366         try {
 367             runFramework(new TestFramework(clazz).addFlags(args));
 368         } catch (Exception e) {
 369             addException(e);
 370         }
 371     }
 372 
 373     private static void runWithArgumentsFail(Class<?> clazz, String... args) {
 374         runFramework(new TestFramework(clazz).addFlags(args));
 375     }
 376 
 377     private static void runCheck(String[] args , Constraint... constraints) {
 378         try {
 379             TestFramework framework = new TestFramework(constraints[0].getKlass()); // All constraints have the same class.
 380             if (args != null) {
 381                 framework.addFlags(args);
 382             }
 383             runFramework(framework);
 384             Asserts.fail("Should have thrown exception");
 385         } catch (IRViolationException e) {
 386             checkConstraints(e, constraints);
 387         } catch (Exception e) {
 388             addException(e);
 389         }
 390     }
 391 
 392     private static void runCheck(Constraint... constraints) {
 393         runCheck(null, constraints);
 394     }
 395 
 396     private static void checkConstraints(IRViolationException e, Constraint[] constraints) {
 397         String message = e.getExceptionInfo();
 398         try {
 399             for (Constraint constraint : constraints) {
 400                 constraint.checkConstraint(e);
 401             }
 402         } catch (Exception e1) {
 403             System.out.println(e.getCompilations());
 404             System.out.println(message);
 405             addException(e1);
 406         }
 407     }
 408 
 409     private static String compilationPrefix() {
 410         return "\\d\\) Compilation";
 411     }
 412 
 413     private static void findIrIds(String output, String method, int... numbers) {
 414         StringBuilder builder = new StringBuilder();
 415         builder.append(method).append(": ");
 416         for (int i = 0; i < numbers.length; i+=2) {
 417             int start = numbers[i];
 418             int endIncluded = numbers[i + 1];
 419             for (int j = start; j <= endIncluded; j++) {
 420                 if (j != numbers[0]) {
 421                     builder.append(", ");
 422                 }
 423                 builder.append(j);
 424             }
 425         }
 426         if (!output.contains(builder.toString())) {
 427             addException(new RuntimeException("Could not find line in Applicable IR Rules: \"" + builder +
 428                                                       System.lineSeparator()));
 429         }
 430     }
 431 
 432     private static void assertNoIds(String output, String methodName) {
 433         String applicableIRRules = output.split("Applicable IR Rules")[1];
 434         if (applicableIRRules.contains(methodName)) {
 435             addException(new RuntimeException("Should not find ids for \"" + methodName + "\"" + System.lineSeparator()));
 436         }
 437     }
 438 }
 439 
 440 class AndOr1 {
 441     @Test
 442     @Arguments(values = Argument.DEFAULT)
 443     @IR(applyIfAnd = {"UsePerfData", "true", "TLABRefillWasteFraction", "50", "UseTLAB", "true"}, failOn = {IRNode.CALL})
 444     public void test1(int i) {
 445         dontInline();
 446     }
 447 
 448     @Test
 449     @IR(applyIfOr = {"UsePerfData", "false", "TLABRefillWasteFraction", "51", "UseTLAB", "false"}, failOn = {IRNode.CALL})
 450     public void test2() {
 451         dontInline();
 452     }
 453 
 454     @DontInline
 455     private void dontInline() {
 456     }
 457 }
 458 
 459 class MultipleFailOnGood {
 460     private int iFld;
 461     private MyClassSub myClassSub = new MyClassSub();
 462 
 463     @Test
 464     @IR(applyIf = {"TLABRefillWasteFraction", "50"}, failOn = {IRNode.STORE, IRNode.CALL})
 465     @IR(failOn = {IRNode.STORE, IRNode.CALL})
 466     @IR(applyIfOr = {"TLABRefillWasteFraction", "99", "TLABRefillWasteFraction", "100"}, failOn = {IRNode.LOOP, IRNode.CALL}) // Not applied
 467     public void good1() {
 468         forceInline();
 469     }
 470 
 471     @Test
 472     @IR(failOn = {IRNode.STORE, IRNode.CALL})
 473     @IR(applyIfNot = {"TLABRefillWasteFraction", "20"}, failOn = {IRNode.ALLOC})
 474     @IR(applyIfNot = {"TLABRefillWasteFraction", "< 100"}, failOn = {IRNode.ALLOC_OF, "Test"})
 475     public void good2() {
 476         forceInline();
 477     }
 478 
 479     @Test
 480     @IR(failOn = {IRNode.STORE_OF_CLASS, "Test", IRNode.CALL})
 481     @IR(applyIfNot = {"TLABRefillWasteFraction", "20"}, failOn = {IRNode.ALLOC})
 482     @IR(applyIfNot = {"TLABRefillWasteFraction", "< 100"}, failOn = {IRNode.ALLOC_OF, "Test"})
 483     public void good3() {
 484         forceInline();
 485     }
 486 
 487     @Test
 488     @IR(failOn = {IRNode.CALL, IRNode.STORE_OF_CLASS, "UnknownClass"})
 489     public void good4() {
 490         iFld = 42;
 491     }
 492 
 493     @Test
 494     @IR(failOn = {IRNode.STORE_OF_FIELD, "xFld", IRNode.CALL})
 495     public void good5() {
 496         iFld = 42;
 497     }
 498 
 499     @Test
 500     @IR(failOn = {IRNode.STORE_OF_CLASS, "MyClass"}) // Needs exact match to fail
 501     public void good6() {
 502         myClassSub.iFld = 42;
 503     }
 504 
 505     @Test
 506     @IR(failOn = {IRNode.STORE_OF_CLASS, "MyClassSub"}) // Static write is with Class and not MySubClass
 507     public void good7() {
 508         MyClassSub.iFldStatic = 42;
 509     }
 510 
 511     @ForceInline
 512     private void forceInline() {}
 513 }
 514 
 515 class MultipleFailOnBad {
 516     private int iFld;
 517     private int myInt;
 518     private MyClassEmpty myClass;
 519 
 520     @Test
 521     @IR(failOn = {IRNode.STORE, IRNode.CALL, IRNode.STORE_I, IRNode.LOOP})
 522     public void fail1() {
 523         iFld = 42;
 524     }
 525 
 526     @Test
 527     @IR(failOn = {IRNode.STORE, IRNode.CALL})
 528     public void fail2() {
 529         dontInline();
 530     }
 531 
 532     @Test
 533     @IR(failOn = {IRNode.CALL, IRNode.STORE_OF_CLASS, "MultipleFailOnBad", IRNode.ALLOC})
 534     public void fail3() {
 535         iFld = 42;
 536     }
 537 
 538     @Test
 539     @IR(failOn = {IRNode.STORE_OF_CLASS, "ir_framework/tests/MultipleFailOnBad", IRNode.CALL, IRNode.ALLOC})
 540     public void fail4() {
 541         iFld = 42;
 542     }
 543 
 544     @Test
 545     @IR(failOn = {IRNode.STORE_OF_FIELD, "iFld", IRNode.CALL, IRNode.ALLOC})
 546     public void fail5() {
 547         iFld = 42;
 548     }
 549 
 550     @Test
 551     @IR(failOn = {IRNode.STORE_OF_CLASS, "MyClassEmpty", IRNode.ALLOC, IRNode.CALL})
 552     public void fail6() {
 553         myClass = new MyClassEmpty();
 554     }
 555 
 556     @Test
 557     @IR(failOn = {IRNode.STORE_OF_CLASS, "UnknownClass", IRNode.ALLOC_OF, "MyClassEmpty"})
 558     public void fail7() {
 559         myClass = new MyClassEmpty();
 560     }
 561 
 562     @Test
 563     @IR(failOn = {IRNode.STORE_OF_CLASS, "UnknownClass", IRNode.ALLOC_OF, "ir_framework/tests/MyClassEmptySub"})
 564     public void fail8() {
 565         myClass = new MyClassEmptySub();
 566     }
 567 
 568     @Test
 569     @IR(failOn = {IRNode.STORE, IRNode.CALL})
 570     public void fail9() {
 571         iFld = 42;
 572         dontInline();
 573     }
 574 
 575     @Test
 576     @IR(failOn = {IRNode.STORE_OF_FIELD, "iFld", IRNode.CALL, IRNode.ALLOC})
 577     public void fail10() {
 578         myInt = 34;
 579         iFld = 42;
 580     }
 581 
 582     @DontInline
 583     private void dontInline() {}
 584 }
 585 
 586 // Called with -XX:TLABRefillWasteFraction=X.
 587 class FlagComparisons {
 588     // Applies all IR rules if TLABRefillWasteFraction=50
 589     @Test
 590     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "50"}) // Index 1
 591     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=50"})
 592     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 50"})
 593     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " =   50"})
 594     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=50"}) // Index 5
 595     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<= 50"})
 596     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <=  50"})
 597     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=50"}) // Index 8
 598     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">= 50"})
 599     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >=  50"})
 600     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">49"})
 601     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "> 49"})
 602     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >  49"})
 603     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<51"}) // Index 14
 604     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "< 51"})
 605     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <  51"})
 606     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=51"})
 607     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!= 51"})
 608     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " !=  51"})
 609     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=49"})
 610     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!= 49"})
 611     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " !=  49"}) // Index 22
 612     public void testMatchAllIf50() {}
 613 
 614     // Applies no IR rules if TLABRefillWasteFraction=50
 615     @Test
 616     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "49"}) // Index 1
 617     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=49"})
 618     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 49"})
 619     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " =  49"})
 620     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "51"}) // Index 5
 621     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=51"})
 622     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 51"})
 623     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " =  51"})
 624     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=49"}) // Index 9
 625     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<= 49"})
 626     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <=  49"})
 627     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=51"}) // Index 12
 628     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">= 51"})
 629     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >=  51"})
 630     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">50"})
 631     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "> 50"})
 632     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >  50"})
 633     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<50"}) // Index 18
 634     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "< 50"})
 635     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <  50"})
 636     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=50"})
 637     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!= 50"})
 638     @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " !=  50"}) // Index 23
 639     public void testMatchNoneIf50() {}
 640 }
 641 
 642 class CountComparisons {
 643     int iFld;
 644 
 645     @Test
 646     @IR(counts = {IRNode.STORE, "= 1",
 647                   IRNode.STORE, "=1",
 648                   IRNode.STORE, " = 1",
 649                   IRNode.STORE, "  =  1",
 650                   IRNode.STORE, ">= 1",
 651                   IRNode.STORE, ">=1",
 652                   IRNode.STORE, " >= 1",
 653                   IRNode.STORE, "  >=  1",
 654                   IRNode.STORE, "<= 1",
 655                   IRNode.STORE, "<=1",
 656                   IRNode.STORE, " <= 1",
 657                   IRNode.STORE, "  <=  1",
 658                   IRNode.STORE, "> 0",
 659                   IRNode.STORE, ">0",
 660                   IRNode.STORE, " > 0",
 661                   IRNode.STORE, "  >  0",
 662                   IRNode.STORE, "< 2",
 663                   IRNode.STORE, "<2",
 664                   IRNode.STORE, " < 2",
 665                   IRNode.STORE, "  <  2",
 666     })
 667     public void countComparison() {
 668         iFld = 3;
 669     }
 670 }
 671 
 672 class GoodCount {
 673     boolean flag;
 674     char cFld;
 675     byte bFld;
 676     short sFld;
 677     int iFld;
 678     long lFld;
 679     float fFld;
 680     double dFld;
 681     long x;
 682 
 683     long result;
 684     MyClass myClass = new MyClass();
 685     MyClassEmpty myClassEmpty = new MyClassEmpty();
 686     MyClass myClassSubPoly = new MyClassSub();
 687     MyClassSub myClassSub = new MyClassSub();
 688 
 689     @Test
 690     @IR(counts = {IRNode.STORE, "1", IRNode.STORE_I, "1"},
 691         failOn = {IRNode.STORE_B, IRNode.STORE_C, IRNode.STORE_D,
 692                   IRNode.STORE_F, IRNode.STORE_L})
 693     public void good1() {
 694         iFld = 3;
 695     }
 696 
 697     @Test
 698     @IR(counts = {IRNode.STORE, "8",
 699                   IRNode.STORE_B, "2", // bFld + flag
 700                   IRNode.STORE_C, "2", // cFld + sFld
 701                   IRNode.STORE_I, "1",
 702                   IRNode.STORE_L, "1",
 703                   IRNode.STORE_F, "1",
 704                   IRNode.STORE_D, "1"})
 705     public void good2() {
 706         flag = true;
 707         cFld = 'a';
 708         bFld = 1;
 709         sFld = 2;
 710         iFld = 3;
 711         lFld = 4L;
 712         fFld = 5.0f;
 713         dFld = 6.0;
 714     }
 715 
 716     @Test
 717     @IR(counts = {IRNode.STORE, "8", IRNode.STORE_OF_CLASS, "GoodCount", "8",
 718                   IRNode.STORE_B, "2", IRNode.STORE_B_OF_CLASS, "GoodCount", "2",
 719                   IRNode.STORE_C, "2", IRNode.STORE_C_OF_CLASS, "GoodCount", "2",
 720                   IRNode.STORE_I, "1", IRNode.STORE_I_OF_CLASS, "GoodCount", "1",
 721                   IRNode.STORE_L, "1", IRNode.STORE_L_OF_CLASS, "GoodCount", "1",
 722                   IRNode.STORE_F, "1", IRNode.STORE_F_OF_CLASS, "GoodCount", "1",
 723                   IRNode.STORE_D, "1", IRNode.STORE_D_OF_CLASS, "GoodCount", "1"})
 724     public void good3() {
 725         flag = true;
 726         cFld = 'a';
 727         bFld = 1;
 728         sFld = 2;
 729         iFld = 3;
 730         lFld = 4L;
 731         fFld = 5.0f;
 732         dFld = 6.0;
 733     }
 734 
 735     @Test
 736     @IR(counts = {IRNode.STORE, "8", IRNode.STORE_OF_CLASS, "GoodCount", "8",
 737                   IRNode.STORE_B, "2", IRNode.STORE_B_OF_CLASS, "GoodCount", "2",
 738                   IRNode.STORE_C, "2", IRNode.STORE_C_OF_CLASS, "GoodCount", "2",
 739                   IRNode.STORE_I, "1", IRNode.STORE_I_OF_CLASS, "GoodCount", "1",
 740                   IRNode.STORE_L, "1", IRNode.STORE_L_OF_CLASS, "GoodCount", "1",
 741                   IRNode.STORE_F, "1", IRNode.STORE_F_OF_CLASS, "GoodCount", "1",
 742                   IRNode.STORE_D, "1", IRNode.STORE_D_OF_CLASS, "GoodCount", "1",
 743                   IRNode.STORE_OF_FIELD, "lFld", "1"})
 744     public void good4() {
 745         flag = true;
 746         cFld = 'a';
 747         bFld = 1;
 748         sFld = 2;
 749         iFld = 3;
 750         lFld = 4L;
 751         fFld = 5.0f;
 752         dFld = 6.0;
 753     }
 754 
 755     @Test
 756     @IR(counts = {IRNode.STORE, "2", IRNode.STORE_I, "1", IRNode.STORE_L, "1",
 757                   IRNode.STORE_OF_CLASS, "GoodCount", "1", IRNode.STORE_L_OF_CLASS, "GoodCount", "1",
 758                   IRNode.STORE_OF_CLASS, "ir_framework/tests/MyClass", "1",
 759                   IRNode.STORE_I_OF_CLASS, "ir_framework/tests/MyClass", "1",
 760                   IRNode.STORE_OF_CLASS, "ir_framework/tests/GoodCount", "1",
 761                   IRNode.STORE_L_OF_CLASS, "ir_framework/tests/GoodCount", "1",
 762                   IRNode.STORE_OF_FIELD, "x", "2"})
 763     public void good5() {
 764         x = 3; // long
 765         myClass.x = 4; // int
 766     }
 767 
 768     @Test
 769     @IR(counts = {
 770             IRNode.STORE_OF_FIELD, "myClassEmpty", "1",
 771             IRNode.STORE_OF_CLASS, "oodCount", "0",
 772             IRNode.STORE_OF_CLASS, "GoodCount", "1",
 773             IRNode.STORE_OF_CLASS, "/GoodCount", "1",
 774             IRNode.STORE_OF_CLASS, "tests/GoodCount", "1",
 775             IRNode.STORE_OF_CLASS, "/tests/GoodCount", "1",
 776             IRNode.STORE_OF_CLASS, "ir_framework/tests/GoodCount", "1",
 777             IRNode.STORE_OF_CLASS, "/ir_framework/tests/GoodCount", "0",
 778             IRNode.STORE_OF_CLASS, "MyClassEmpty", "0"
 779         },
 780         failOn = {IRNode.STORE_OF_CLASS, "MyClassEmpty"})
 781     public void good6() {
 782         myClassEmpty = new MyClassEmpty();
 783     }
 784 
 785     @Test
 786     @IR(counts = {IRNode.STORE_OF_FIELD, "iFld", "3", IRNode.STORE_OF_CLASS, "GoodCount", "0",
 787                   IRNode.STORE_OF_CLASS, "MyClass", "2", IRNode.STORE_OF_CLASS, "MyClassSub", "1",
 788                   IRNode.STORE, "3"},
 789         failOn = {IRNode.STORE_OF_CLASS, "GoodCount"})
 790     public void good7() {
 791         myClass.iFld = 1;
 792         myClassSubPoly.iFld = 2;
 793         myClassSub.iFld = 3;
 794     }
 795 
 796     @Test
 797     @IR(counts = {IRNode.LOAD, "1", IRNode.STORE, "1"})
 798     public void good8() {
 799         result = iFld;
 800     }
 801 
 802 
 803     @Test
 804     @IR(counts = {IRNode.LOAD, "4", IRNode.STORE, "1", IRNode.LOAD_OF_FIELD, "iFld", "2", IRNode.LOAD_OF_FIELD, "iFld2", "0",
 805                   IRNode.LOAD_OF_FIELD, "lFldStatic", "1", IRNode.LOAD_OF_CLASS, "GoodCount", "2", IRNode.LOAD_OF_CLASS, "MyClass", "1",
 806                   IRNode.STORE_OF_CLASS, "GoodCount", "1", IRNode.STORE_OF_FIELD, "result", "1",
 807                   IRNode.LOAD_OF_FIELD, "myClass", "1"})
 808     public void good9() {
 809         result = iFld + MyClass.lFldStatic + myClass.iFld; // 1 + 1 + 2 loads (myClass is LoadN of GoodCount and myClass.iFld a LoadI of MyClass)
 810     }
 811 
 812     @Test
 813     @IR(counts = {IRNode.LOAD, "8",
 814                   IRNode.LOAD_B, "1",
 815                   IRNode.LOAD_UB, "1",
 816                   IRNode.LOAD_S, "1",
 817                   IRNode.LOAD_US, "1",
 818                   IRNode.LOAD_I, "1",
 819                   IRNode.LOAD_L, "1",
 820                   IRNode.LOAD_F, "1",
 821                   IRNode.LOAD_D, "1"})
 822     public void good10() {
 823         bFld++;
 824         cFld++;
 825         sFld++;
 826         iFld++;
 827         lFld++;
 828         fFld++;
 829         dFld++;
 830         flag = !flag;
 831     }
 832 
 833     @Test
 834     @IR(counts = {IRNode.LOAD, "8", IRNode.LOAD_OF_CLASS, "GoodCount", "8",
 835                   IRNode.LOAD_B, "1", IRNode.LOAD_B_OF_CLASS, "GoodCount", "1",
 836                   IRNode.LOAD_UB, "1", IRNode.LOAD_UB_OF_CLASS, "GoodCount", "1",
 837                   IRNode.LOAD_S, "1", IRNode.LOAD_S_OF_CLASS, "GoodCount", "1",
 838                   IRNode.LOAD_US, "1", IRNode.LOAD_US_OF_CLASS, "GoodCount", "1",
 839                   IRNode.LOAD_I, "1", IRNode.LOAD_I_OF_CLASS, "GoodCount", "1",
 840                   IRNode.LOAD_L, "1", IRNode.LOAD_L_OF_CLASS, "GoodCount", "1",
 841                   IRNode.LOAD_F, "1", IRNode.LOAD_F_OF_CLASS, "GoodCount", "1",
 842                   IRNode.LOAD_D, "1", IRNode.LOAD_D_OF_CLASS, "GoodCount", "1"})
 843     public void good11() {
 844         bFld++;
 845         cFld++;
 846         sFld++;
 847         iFld++;
 848         lFld++;
 849         fFld++;
 850         dFld++;
 851         flag = !flag;
 852     }
 853 }
 854 
 855 class BadCount {
 856     int iFld;
 857     int iFld2;
 858     int result;
 859     int result2;
 860     @Test
 861     @IR(counts = {IRNode.LOAD, "> 1000"}) // fail
 862     @IR(counts = {IRNode.STORE, "> 0"})
 863     public void bad1() {
 864         result = iFld;
 865         result2 = iFld2;
 866     }
 867 
 868     @Test
 869     @IR(counts = {IRNode.LOAD, "2"}) // fail
 870     @IR(counts = {IRNode.STORE, "< 2"})
 871     public void bad2() {
 872         result = iFld;
 873         result2 = iFld2;
 874     }
 875 
 876 
 877     @Test
 878     @IR(counts = {IRNode.LOAD, "0"}) // fail
 879     @IR(counts = {IRNode.STORE, " <= 1"}) // fail
 880     public void bad3() {
 881         result = iFld;
 882         result2 = iFld2;
 883     }
 884 }
 885 
 886 
 887 class RunTests {
 888     public int iFld;
 889 
 890     @Test
 891     @IR(counts = {IRNode.STORE, "1"})
 892     @IR(failOn = IRNode.LOAD)
 893     public void good1() {
 894         iFld = 42;
 895     }
 896 
 897     @Test
 898     @IR(counts = {IRNode.LOAD, "1"})
 899     @IR(failOn = IRNode.STORE)
 900     public int good2() {
 901         return iFld;
 902     }
 903 
 904     @Run(test = {"good1", "good2"})
 905     public void runGood1() {
 906         good1();
 907         good2();
 908     }
 909 
 910 
 911     @Test
 912     @IR(counts = {IRNode.STORE, "1"})
 913     @IR(failOn = IRNode.LOAD)
 914     public void good3(int x) {
 915         iFld = x;
 916     }
 917 
 918     @Test
 919     @IR(counts = {IRNode.STORE, "1"})
 920     @IR(failOn = IRNode.LOAD)
 921     public int bad1(int x) {
 922         return iFld + x;
 923     }
 924 
 925     @Run(test = {"bad1", "good3"})
 926     public void run() {
 927         bad1(2);
 928         good3(4);
 929     }
 930 }
 931 
 932 class Calls {
 933 
 934     @Test
 935     @IR(counts = {IRNode.CALL, "1"})
 936     @IR(failOn = {IRNode.CALL_OF_METHOD, "dontInline",  // Fails
 937                   IRNode.STATIC_CALL_OF_METHOD, "dontInline"}) // Fails
 938     @IR(failOn = {IRNode.CALL_OF_METHOD, "forceInline",
 939                   IRNode.STATIC_CALL_OF_METHOD, "forceInline",
 940                   IRNode.CALL_OF_METHOD, "dontInlines",
 941                   IRNode.STATIC_CALL_OF_METHOD, "dontInlines",
 942                   IRNode.CALL_OF_METHOD, "dont",
 943                   IRNode.STATIC_CALL_OF_METHOD, "dont"})
 944     public void calls() {
 945         dontInline();
 946         forceInline();
 947     }
 948 
 949     @DontInline
 950     public void dontInline() {}
 951 
 952     @ForceInline
 953     public void forceInline() {}
 954 }
 955 
 956 class AllocInstance {
 957     MyClass myClass;
 958 
 959     @Test
 960     @IR(failOn = {IRNode.ALLOC})
 961     @IR(failOn = {IRNode.ALLOC_OF, "MyClass"})
 962     @IR(failOn = {IRNode.ALLOC_OF, "Class"}) // Does not fail
 963     @IR(failOn = {IRNode.ALLOC_OF, "MyClasss"}) // Does not fail
 964     @IR(failOn = {IRNode.ALLOC_OF, "ir_framework/tests/MySubClass"}) // Does not fail
 965     @IR(failOn = {IRNode.ALLOC_OF, "ir_framework/tests/MyClass"})
 966     @IR(failOn = {IRNode.ALLOC_OF, "tests/MyClass"})
 967     @IR(failOn = {IRNode.ALLOC_OF, "ests/MyClass"}) // Does not fail
 968     @IR(failOn = {IRNode.ALLOC_OF, "Atests/MyClass"}) // Does not fail
 969     @IR(failOn = {IRNode.ALLOC_OF, "tests"}) // Does not fail
 970     public void allocInstance() {
 971         myClass = new MyClass();
 972     }
 973 
 974     static class Nested {}
 975     @Test
 976     @IR(failOn = {IRNode.ALLOC_OF, "Nested"})
 977     @IR(failOn = {IRNode.ALLOC_OF, "AllocInstance\\$Nested"})
 978     @IR(failOn = {IRNode.ALLOC_OF, "AllocInst\\w+\\$Nested"})
 979     public Nested allocNested() { return new Nested(); }
 980 }
 981 
 982 class AllocArray {
 983     MyClass[] myClassArray;
 984     MyClass[][] myClassMultiArray;
 985 
 986     @Test
 987     @IR(failOn = {IRNode.ALLOC_ARRAY})
 988     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "MyClass"})
 989     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "Class"}) // Does not fail
 990     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "MyClasss"}) // Does not fail
 991     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "ir_framework/tests/MySubClass"}) // Does not fail
 992     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "ir_framework/tests/MyClass"})
 993     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "tests/MyClass"})
 994     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "ests/MyClass"}) // Does not fail
 995     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "Atests/MyClass"}) // Does not fail
 996     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "tests"}) // Does not fail
 997     public void allocArray() {
 998         myClassArray = new MyClass[2];
 999     }
1000 
1001     @Test
1002     @IR(failOn = {IRNode.ALLOC_ARRAY})
1003     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "MyClass"})
1004     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "Class"}) // Does not fail
1005     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "MyClasss"}) // Does not fail
1006     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "ir_framework/tests/MySubClass"}) // Does not fail
1007     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "ir_framework/tests/MyClass"})
1008     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "tests/MyClass"})
1009     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "ests/MyClass"}) // Does not fail
1010     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "Atests/MyClass"}) // Does not fail
1011     @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "tests"}) // Does not fail
1012     public void allocMultiArray() {
1013         myClassMultiArray = new MyClass[2][3];
1014     }
1015 }
1016 
1017 class Loads {
1018     int iFld = 34;
1019     int result = 0;
1020     Object myClass = new MyClass();
1021 
1022     @Test
1023     @IR(failOn = {IRNode.LOAD, IRNode.LOOP, IRNode.LOAD_I}, counts = {IRNode.LOOP, "2", IRNode.LOAD, "2", IRNode.STORE, "2"})
1024     @IR(failOn = {IRNode.LOOP, IRNode.LOOP}, counts = {IRNode.LOOP, "0", IRNode.LOAD, "1"}) // Does not fail
1025     @IR(failOn = {IRNode.LOOP, IRNode.LOOP}, counts = {IRNode.LOOP, "0", IRNode.STORE, "1"})
1026     @IR(failOn = {IRNode.LOOP, IRNode.STORE}, counts = {IRNode.LOOP, "0", IRNode.LOAD, "1"})
1027     @IR(failOn = {IRNode.LOAD_OF_CLASS, "ir_framework/tests/Loads"})
1028     @IR(failOn = {IRNode.LOAD_OF_CLASS, "Loads"})
1029     @IR(failOn = {IRNode.LOAD_OF_FIELD, "iFld"})
1030     @IR(failOn = {IRNode.LOAD_OF_FIELD, "iFld2", IRNode.LOAD_OF_CLASS, "Load"}) // Does not fail
1031     @IR(failOn = {IRNode.LOAD_KLASS}) // Does not fail
1032     @IR(counts = {IRNode.FIELD_ACCESS, "3"}) // Does not fail
1033     public void load() {
1034         result = iFld;
1035         iFld = 3;
1036     }
1037 
1038     @Test
1039     @IR(failOn = {IRNode.LOAD_KLASS})
1040     @IR(counts = {IRNode.FIELD_ACCESS, "3"})
1041     public void loadKlass() {
1042         if (myClass instanceof MyClass) {
1043             result = 3;
1044         }
1045     }
1046 }
1047 
1048 class Loops {
1049     int limit = 1024;
1050     int[] iArr = new int[100];
1051 
1052     @DontInline
1053     public void dontInline() {}
1054 
1055     @Test
1056     @IR(failOn = IRNode.LOOP) // fails
1057     @IR(failOn = IRNode.COUNTED_LOOP)
1058     @IR(failOn = IRNode.COUNTED_LOOP_MAIN)
1059     public void loop() {
1060         for (int i = 0; i < limit; i++) {
1061             dontInline();
1062         }
1063     }
1064 
1065     @Test
1066     @IR(failOn = IRNode.LOOP)
1067     @IR(failOn = IRNode.COUNTED_LOOP) // fails
1068     @IR(failOn = IRNode.COUNTED_LOOP_MAIN)
1069     public void countedLoop() {
1070         for (int i = 0; i < 2000; i++) {
1071             dontInline();
1072         }
1073     }
1074 
1075     @Test
1076     @IR(failOn = IRNode.LOOP) // fails
1077     @IR(failOn = IRNode.COUNTED_LOOP) // fails
1078     @IR(failOn = IRNode.COUNTED_LOOP_MAIN)
1079     public void loopAndCountedLoop() {
1080         for (int i = 0; i < 2000; i++) {
1081             for (int j = 0; j < limit; j++) {
1082                 dontInline();
1083             }
1084         }
1085     }
1086 
1087     @Test
1088     @IR(failOn = IRNode.LOOP)
1089     @IR(failOn = IRNode.COUNTED_LOOP) // fails
1090     @IR(failOn = IRNode.COUNTED_LOOP_MAIN) // fails
1091     public void countedLoopMain() {
1092         // Cannot unroll completely -> create pre/main/post
1093         for (int i = 0; i < 100; i++) {
1094             iArr[i] = i;
1095         }
1096     }
1097 
1098     @Test
1099     @IR(failOn = IRNode.LOOP)
1100     @IR(failOn = IRNode.COUNTED_LOOP)
1101     @IR(failOn = IRNode.COUNTED_LOOP_MAIN)
1102     public void countedLoopUnrolled() {
1103         // Completely unrolled -> no pre/main/post
1104         for (int i = 0; i < 8; i++) {
1105             iArr[i] = i;
1106         }
1107     }
1108 }
1109 
1110 class Traps {
1111     int number42 = 42;
1112     int iFld = 10;
1113     int[] iArr = new int[2];
1114     MyClass myClass = new MyClass();
1115     MyClassSub myClassSub = new MyClassSub();
1116     NotLoaded notLoaded = new NotLoaded();
1117     Object[] oArr = new Object[10];
1118     MyClass[] mArr = new MyClass[10];
1119 
1120     @Test
1121     @IR(failOn = IRNode.TRAP)
1122     @IR(failOn = {IRNode.STORE_OF_FIELD, "iFld"}) // fails
1123     @IR(failOn = {IRNode.PREDICATE_TRAP,
1124                   IRNode.UNSTABLE_IF_TRAP,
1125                   IRNode.NULL_CHECK_TRAP,
1126                   IRNode.NULL_ASSERT_TRAP,
1127                   IRNode.RANGE_CHECK_TRAP,
1128                   IRNode.CLASS_CHECK_TRAP,
1129                   IRNode.INTRINSIC_TRAP,
1130                   IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP,
1131                   IRNode.UNHANDLED_TRAP})
1132     public void noTraps() {
1133         for (int i = 0; i < 100; i++) {
1134             if (i < 42) {
1135                 // Reached, no uncommon trap
1136                 iFld = i;
1137             }
1138         }
1139     }
1140 
1141     @Test
1142     @IR(failOn = IRNode.TRAP) // fails
1143     @IR(failOn = IRNode.PREDICATE_TRAP) // fails
1144     @IR(failOn = {IRNode.STORE_OF_FIELD, "iFld"})
1145     @IR(failOn = {IRNode.UNSTABLE_IF_TRAP,
1146                   IRNode.NULL_CHECK_TRAP,
1147                   IRNode.NULL_ASSERT_TRAP,
1148                   IRNode.RANGE_CHECK_TRAP,
1149                   IRNode.CLASS_CHECK_TRAP,
1150                   IRNode.INTRINSIC_TRAP,
1151                   IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP,
1152                   IRNode.UNHANDLED_TRAP})
1153     public void predicateTrap() {
1154         for (int i = 0; i < 100; i++) {
1155             if (number42 != 42) {
1156                 // Never reached
1157                 iFld = i;
1158             }
1159         }
1160     }
1161 
1162     @Test
1163     @IR(failOn = IRNode.TRAP) // fails
1164     @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails
1165     @IR(failOn = IRNode.CLASS_CHECK_TRAP) // fails
1166     @IR(failOn = {IRNode.PREDICATE_TRAP,
1167                   IRNode.NULL_ASSERT_TRAP,
1168                   IRNode.RANGE_CHECK_TRAP,
1169                   IRNode.UNSTABLE_IF_TRAP,
1170                   IRNode.INTRINSIC_TRAP,
1171                   IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP,
1172                   IRNode.UNHANDLED_TRAP})
1173     public void nullCheck() {
1174         if (myClass instanceof MyClassSub) {
1175             iFld = 4;
1176         }
1177     }
1178 
1179     @Test
1180     @IR(failOn = IRNode.TRAP) // fails
1181     @IR(failOn = IRNode.NULL_ASSERT_TRAP) // fails
1182     @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails
1183     @IR(failOn = {IRNode.PREDICATE_TRAP,
1184                   IRNode.UNSTABLE_IF_TRAP,
1185                   IRNode.RANGE_CHECK_TRAP,
1186                   IRNode.CLASS_CHECK_TRAP,
1187                   IRNode.INTRINSIC_TRAP,
1188                   IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP,
1189                   IRNode.UNHANDLED_TRAP})
1190     public Object nullAssert() {
1191         return notLoaded.notLoadedFld;
1192     }
1193 
1194     @Test
1195     @Arguments(values = Argument.TRUE)
1196     @IR(failOn = IRNode.TRAP) // fails
1197     @IR(failOn = IRNode.UNSTABLE_IF_TRAP) // fails
1198     @IR(failOn = {IRNode.PREDICATE_TRAP,
1199                   IRNode.NULL_CHECK_TRAP,
1200                   IRNode.NULL_ASSERT_TRAP,
1201                   IRNode.RANGE_CHECK_TRAP,
1202                   IRNode.CLASS_CHECK_TRAP,
1203                   IRNode.INTRINSIC_TRAP,
1204                   IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP,
1205                   IRNode.UNHANDLED_TRAP})
1206     public void unstableIf(boolean flag) {
1207         if (flag) {
1208             iFld++;
1209         } else {
1210             iFld--;
1211         }
1212     }
1213 
1214     @Test
1215     @IR(failOn = IRNode.TRAP) // fails
1216     @IR(failOn = IRNode.CLASS_CHECK_TRAP) // fails
1217     @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails
1218     @IR(failOn = {IRNode.PREDICATE_TRAP,
1219                   IRNode.UNSTABLE_IF_TRAP,
1220                   IRNode.NULL_ASSERT_TRAP,
1221                   IRNode.RANGE_CHECK_TRAP,
1222                   IRNode.INTRINSIC_TRAP,
1223                   IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP,
1224                   IRNode.UNHANDLED_TRAP})
1225     public void classCheck() {
1226         try {
1227             myClassSub = (MyClassSub) myClass;
1228         } catch (ClassCastException e) {
1229             // Expected
1230         }
1231     }
1232 
1233     @Test
1234     @IR(failOn = IRNode.TRAP) // fails
1235     @IR(failOn = IRNode.RANGE_CHECK_TRAP) // fails
1236     @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails
1237     @IR(failOn = {IRNode.PREDICATE_TRAP,
1238                   IRNode.UNSTABLE_IF_TRAP,
1239                   IRNode.NULL_ASSERT_TRAP,
1240                   IRNode.CLASS_CHECK_TRAP,
1241                   IRNode.INTRINSIC_TRAP,
1242                   IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP,
1243                   IRNode.UNHANDLED_TRAP})
1244     public void rangeCheck() {
1245         iArr[1] = 3;
1246     }
1247 
1248 
1249     @Test
1250     @IR(failOn = IRNode.TRAP) // fails
1251     @IR(failOn = IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP) // fails
1252     @IR(failOn = IRNode.INTRINSIC_TRAP) // fails
1253     @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails
1254     @IR(failOn = {IRNode.PREDICATE_TRAP,
1255                   IRNode.UNSTABLE_IF_TRAP,
1256                   IRNode.NULL_ASSERT_TRAP,
1257                   IRNode.CLASS_CHECK_TRAP,
1258                   IRNode.RANGE_CHECK_TRAP,
1259                   IRNode.UNHANDLED_TRAP})
1260     public void instrinsicOrTypeCheckedInlining() {
1261         System.arraycopy(oArr, 0, mArr, 0, 8);
1262     }
1263 }
1264 
1265 class UnhandledTrap {
1266     int iFld = 34;
1267 
1268     @Test
1269     @IR(failOn = IRNode.TRAP) // fails
1270     @IR(failOn = IRNode.UNHANDLED_TRAP) // fails
1271     @IR(failOn = {IRNode.PREDICATE_TRAP,
1272                   IRNode.UNSTABLE_IF_TRAP,
1273                   IRNode.NULL_CHECK_TRAP,
1274                   IRNode.NULL_ASSERT_TRAP,
1275                   IRNode.RANGE_CHECK_TRAP,
1276                   IRNode.CLASS_CHECK_TRAP})
1277     public void unhandled() {
1278         try {
1279             throw new RuntimeException();
1280         } catch (RuntimeException e) {
1281             // Expected
1282         }
1283     }
1284 }
1285 
1286 class ScopeObj {
1287 
1288     @DontInline
1289     public void dontInline(int i) {}
1290 
1291     @Test
1292     @IR(failOn = IRNode.SCOPE_OBJECT) // fails
1293     public int scopeObject() {
1294         MyClass myClass = new MyClass();
1295         for (int i = 0; i < 100; i++) {
1296             dontInline(myClass.iFld);
1297         }
1298         return 3;
1299     }
1300 }
1301 
1302 class Membar {
1303     volatile MyClass myClass;
1304 
1305     @Test
1306     @IR(failOn = IRNode.MEMBAR) // fails
1307     public int membar() {
1308         myClass = new MyClass();
1309         return myClass.x;
1310     }
1311 }
1312 
1313 class CheckCastArray {
1314     Object[] oArr = new Object[10];
1315     MyClass[] mArr = new MyClass[10];
1316 
1317     @Test
1318     @IR(failOn = IRNode.CHECKCAST_ARRAY) // fails
1319     @IR(failOn = {IRNode.CHECKCAST_ARRAY_OF, "MyClass", // fails
1320                   IRNode.CHECKCAST_ARRAY_OF, "ir_framework/tests/MyClass"}) // fails
1321     @IR(failOn = {IRNode.CHECKCAST_ARRAY_OF, "MyClasss", IRNode.CHECKCAST_ARRAY_OF, "Object"})
1322     public boolean array(Object[] arr) {
1323         return arr instanceof MyClass[];
1324     }
1325 
1326     @Run(test = "array")
1327     public void testArray() {
1328         array(oArr);
1329         array(mArr);
1330     }
1331 
1332     @Test
1333     @IR(failOn = IRNode.CHECKCAST_ARRAYCOPY) // fails
1334     public Object[] arrayCopy(Object[] src, Class klass) {
1335         return Arrays.copyOf(src, 8, klass);
1336     }
1337 
1338     @Run(test = "arrayCopy")
1339     public void testArrayCopy() {
1340         arrayCopy(mArr, MyClass[].class);
1341         arrayCopy(mArr, Object[].class);
1342         arrayCopy(mArr, MyClassEmpty[].class);
1343     }
1344 }
1345 
1346 class CompilationOutputOfFails {
1347     private Object obj;
1348 
1349     @Test
1350     @IR(failOn = IRNode.COUNTED_LOOP)
1351     @IR(failOn = {"call"},
1352         phase = CompilePhase.PRINT_OPTO_ASSEMBLY)
1353     public void both1() {
1354         for (int i = 0; i < 100; i++) {
1355             dontInline();
1356         }
1357     }
1358 
1359     @Test
1360     @IR(failOn = "CountedLoop|call",
1361         phase = {CompilePhase.PRINT_IDEAL, CompilePhase.PRINT_OPTO_ASSEMBLY})
1362     public void both2() {
1363         for (int i = 0; i < 100; i++) {
1364             dontInline();
1365         }
1366     }
1367 
1368     @Test
1369     @IR(failOn = IRNode.COUNTED_LOOP)
1370     @IR(failOn = "call", phase = CompilePhase.PRINT_OPTO_ASSEMBLY)
1371     public void both3() {
1372         for (int i = 0; i < 100; i++) {
1373             dontInline();
1374         }
1375     }
1376 
1377     @Test
1378     @IR(counts = {IRNode.COUNTED_LOOP, "0"})
1379     @IR(counts = {"call", "0"},
1380         phase = {CompilePhase.PRINT_OPTO_ASSEMBLY})
1381     public void both4() {
1382         for (int i = 0; i < 100; i++) {
1383             dontInline();
1384         }
1385     }
1386 
1387     @Test
1388     @IR(counts = {"CountedLoop|call", "10"},
1389         phase = {CompilePhase.PRINT_IDEAL, CompilePhase.PRINT_OPTO_ASSEMBLY})
1390     public void both5() {
1391         for (int i = 0; i < 100; i++) {
1392             dontInline();
1393         }
1394     }
1395 
1396     @Test
1397     @IR(counts = {IRNode.COUNTED_LOOP, "0"})
1398     @IR(counts = {"call", "0"}, phase = CompilePhase.PRINT_OPTO_ASSEMBLY)
1399     public void both6() {
1400         for (int i = 0; i < 100; i++) {
1401             dontInline();
1402         }
1403     }
1404 
1405     @Test
1406     @IR(failOn = IRNode.COUNTED_LOOP)
1407     @IR(counts = {"call", "0"}, phase = CompilePhase.PRINT_OPTO_ASSEMBLY)
1408     public void both7() {
1409         for (int i = 0; i < 100; i++) {
1410             dontInline();
1411         }
1412     }
1413 
1414     @Test
1415     @IR(failOn = IRNode.COUNTED_LOOP)
1416     public void ideal1() {
1417         for (int i = 0; i < 100; i++) {
1418             dontInline();
1419         }
1420     }
1421 
1422     @Test
1423     @IR(failOn = IRNode.COUNTED_LOOP)
1424     @IR(failOn = IRNode.ALLOC) // not fail
1425     public void ideal2() {
1426         for (int i = 0; i < 100; i++) {
1427             dontInline();
1428         }
1429     }
1430 
1431     @Test
1432     @IR(failOn = IRNode.COUNTED_LOOP)
1433     @IR(counts = {IRNode.ALLOC, "0"}) // not fail
1434     public void ideal3() {
1435         for (int i = 0; i < 100; i++) {
1436             dontInline();
1437         }
1438     }
1439 
1440     @Test
1441     @IR(counts = {IRNode.COUNTED_LOOP, "2"})
1442     public void ideal4() {
1443         for (int i = 0; i < 100; i++) {
1444             dontInline();
1445         }
1446     }
1447 
1448     @Test
1449     @IR(failOn = IRNode.ALLOC) // not fail
1450     @IR(counts = {IRNode.COUNTED_LOOP, "2"})
1451     public void ideal5() {
1452         for (int i = 0; i < 100; i++) {
1453             dontInline();
1454         }
1455     }
1456 
1457     @Test
1458     @IR(counts = {IRNode.ALLOC, "0"}) // not fail
1459     @IR(counts = {IRNode.COUNTED_LOOP, "2"})
1460     public void ideal6() {
1461         for (int i = 0; i < 100; i++) {
1462             dontInline();
1463         }
1464     }
1465 
1466     @Test
1467     @IR(counts = {IRNode.COUNTED_LOOP, "5"})
1468     @IR(counts = {IRNode.COUNTED_LOOP, "2"})
1469     public void ideal7() {
1470         for (int i = 0; i < 100; i++) {
1471             dontInline();
1472         }
1473     }
1474 
1475     @Test
1476     @IR(failOn = IRNode.ALLOC)
1477     public void macro1() {
1478         obj = new Object();
1479     }
1480 
1481     @Test
1482     @IR(failOn = IRNode.ALLOC)
1483     @IR(failOn = IRNode.STORE_F) // not fail
1484     public void macro2() {
1485         obj = new Object();
1486     }
1487 
1488     @Test
1489     @IR(failOn = IRNode.ALLOC)
1490     @IR(counts = {IRNode.COUNTED_LOOP, ">1"}) // not fail
1491     public void macro3() {
1492         for (int i = 0; i < 100; i++) {
1493             obj = new Object();
1494         }
1495     }
1496 
1497     @Test
1498     @IR(counts = {IRNode.ALLOC, "0"})
1499     public void macro4() {
1500         obj = new Object();
1501     }
1502 
1503     @Test
1504     @IR(failOn = IRNode.STORE_F) // not fail
1505     @IR(counts = {IRNode.ALLOC, "0"})
1506     public void macro5() {
1507         obj = new Object();
1508     }
1509 
1510     @Test
1511     @IR(counts = {IRNode.STORE_F, "0"}) // not fail
1512     @IR(counts = {IRNode.ALLOC, "0"})
1513     public void macro6() {
1514         obj = new Object();
1515     }
1516 
1517     @Test
1518     @IR(counts = {IRNode.ALLOC, "10"})
1519     @IR(counts = {IRNode.ALLOC, "0"})
1520     public void macro7() {
1521         obj = new Object();
1522     }
1523 
1524     @DontInline
1525     private void dontInline() {}
1526 }
1527 
1528 
1529 // Used only by class Traps
1530 class NotLoaded {
1531     NotLoadedHelper notLoadedFld;
1532 }
1533 
1534 // Used only by class Traps
1535 class NotLoadedHelper {}
1536 
1537 class MyClass {
1538     int iFld = 3;
1539     int x = 5;
1540     static long lFldStatic;
1541 }
1542 
1543 class MyClassEmpty {}
1544 
1545 class MyClassEmptySub extends MyClassEmpty {}
1546 
1547 class MyClassSub extends MyClass {
1548     int iFld;
1549     static int iFldStatic;
1550 }
1551 
1552 
1553 // Base class for any kind of constraint that is used to verify if the framework reports the correct IR failures.
1554 abstract class Constraint {
1555     private final Class<?> klass;
1556     protected final int ruleIdx;
1557     private final Pattern methodPattern;
1558     private final String methodName;
1559     protected boolean matched;
1560 
1561     // For good constraints only
1562     Constraint(Class<?> klass, String methodName, int ruleIdx) {
1563         this.klass = klass;
1564         String classAndMethod = klass.getSimpleName() + "::" + methodName;
1565         this.ruleIdx = ruleIdx;
1566         this.methodPattern = Pattern.compile("\\b" + Pattern.quote(classAndMethod) + "\\b");
1567         this.methodName = methodName;
1568         this.matched = false;
1569     }
1570 
1571     @Override
1572     public String toString() {
1573         return "Constraint " + getClass().getSimpleName() + ", " + errorPrefix();
1574     }
1575 
1576     public Class<?> getKlass() {
1577         return klass;
1578     }
1579 
1580     protected String errorPrefix() {
1581         return "Class " + klass.getSimpleName() + ", Method " + methodName + ", Rule " + ruleIdx;
1582     }
1583 
1584     public void checkConstraint(IRViolationException e) {
1585         String message = e.getExceptionInfo();
1586         String[] splitMethods = message.split("Method");
1587         for (int i = 1; i < splitMethods.length; i++) {
1588             String method = splitMethods[i];
1589             if (methodPattern.matcher(method).find()) {
1590                 String[] splitIrRules = method.split("@IR ");
1591                 for (int j = 1; j < splitIrRules.length; j++) {
1592                     String irRule = splitIrRules[j];
1593                     if (irRule.startsWith("rule " + ruleIdx)) {
1594                         checkIRRule(irRule);
1595                     }
1596                 }
1597             }
1598         }
1599         Asserts.assertTrue(matched, this + " should have been matched");
1600     }
1601 
1602     abstract protected void checkIRRule(String irRule);
1603 }
1604 
1605 // Constraint for rule that does not fail.
1606 class GoodRuleConstraint extends Constraint {
1607 
1608     GoodRuleConstraint(Class<?> klass, String methodName, int ruleIdx) {
1609         super(klass, methodName, ruleIdx);
1610         matched = true;
1611     }
1612 
1613     public static GoodRuleConstraint create(Class<?> klass, String methodName, int ruleIdx) {
1614         return new GoodRuleConstraint(klass, methodName, ruleIdx);
1615     }
1616 
1617     @Override
1618     protected void checkIRRule(String irRule) {
1619         Asserts.fail(errorPrefix() + " should not fail:" + System.lineSeparator() + irRule);
1620     }
1621 }
1622 
1623 // Constraint for rule that might fail but not with "failOn".
1624 class GoodFailOnConstraint extends GoodRuleConstraint {
1625 
1626     private GoodFailOnConstraint(Class<?> klass, String methodName, int ruleIdx) {
1627         super(klass, methodName, ruleIdx);
1628     }
1629 
1630     public static GoodFailOnConstraint create(Class<?> klass, String methodName, int ruleIdx) {
1631         return new GoodFailOnConstraint(klass, methodName, ruleIdx);
1632     }
1633 
1634     @Override
1635     protected void checkIRRule(String irRule) {
1636         Asserts.assertFalse(irRule.contains("- failOn"), errorPrefix() + " should not have failed:" + System.lineSeparator() + irRule);
1637     }
1638 }
1639 
1640 // Constraint for rule that might fail but not with "counts".
1641 class GoodCountsConstraint extends GoodRuleConstraint {
1642 
1643     private GoodCountsConstraint(Class<?> klass, String methodName, int ruleIdx) {
1644         super(klass, methodName, ruleIdx);
1645     }
1646 
1647     public static GoodCountsConstraint create(Class<?> klass, String methodName, int ruleIdx) {
1648         return new GoodCountsConstraint(klass, methodName, ruleIdx);
1649     }
1650 
1651     @Override
1652     protected void checkIRRule(String irRule) {
1653         Asserts.assertFalse(irRule.contains("- counts"), errorPrefix() + " should not have failed with counts:"
1654                                                          + System.lineSeparator() + irRule);
1655     }
1656 }
1657 
1658 // Base class for all Regex based constraint.
1659 abstract class RegexConstraint extends Constraint {
1660     final String category;
1661     final String otherCategory;
1662     final int[] regexIndexes;
1663     final boolean isGood;
1664     final List<String> matches;
1665 
1666     RegexConstraint(Class<?> klass, String methodName, String category, boolean isGood, List<String> matches, int ruleIdx, int... regexIndexes) {
1667         super(klass, methodName, ruleIdx);
1668         this.category = category;
1669         this.regexIndexes = regexIndexes;
1670         if (category.equals("failOn")) {
1671             this.otherCategory = "counts";
1672         } else {
1673             Asserts.assertTrue(category.equals("counts"));
1674             this.otherCategory = "failOn";
1675         }
1676         this.isGood = isGood;
1677         this.matches = matches;
1678     }
1679 
1680     @Override
1681     public String toString() {
1682         String msg = super.toString() + ", ";
1683         if (regexIndexes.length > 1) {
1684             msg += "regexes: [" + String.join(", ", Arrays.stream(regexIndexes).mapToObj(String::valueOf).toArray(String[]::new)) + "]";
1685         } else {
1686             msg += "regex: " + regexIndexes[0];
1687         }
1688         return msg;
1689     }
1690 
1691     @Override
1692     protected String errorPrefix() {
1693         return super.errorPrefix() + " with \"" + category + "\"";
1694     }
1695 
1696     @Override
1697     protected void checkIRRule(String irRule) {
1698         int categoryIndex = irRule.indexOf("- " + category);
1699         Asserts.assertTrue(categoryIndex != -1, errorPrefix() + " should have failed");
1700 
1701         int endIndex;
1702         int otherCategoryIndex = irRule.indexOf("- " + otherCategory);
1703         if (otherCategoryIndex == -1 || categoryIndex > otherCategoryIndex) {
1704             endIndex = irRule.length();
1705         } else {
1706             endIndex = otherCategoryIndex;
1707         }
1708         String categoryString = irRule.substring(irRule.indexOf("- " + category), endIndex);
1709         Pattern pattern;
1710         Matcher matcher;
1711         for (int regexIndex : this.regexIndexes) {
1712             pattern = Pattern.compile("Constraint " + regexIndex + ":.*");
1713             matcher = pattern.matcher(categoryString);
1714             if (isGood) {
1715                 Asserts.assertFalse(matcher.find(), errorPrefix() + " failed with Constraint " + regexIndex);
1716                 matched = true;
1717             } else {
1718                 Asserts.assertTrue(matcher.find(), errorPrefix() + " should have failed at Constraint " + regexIndex);
1719                 String[] splitRegex = categoryString.split("Constraint ");
1720                 if (matches != null) {
1721                     for (int i = 1; i < splitRegex.length; i++) {
1722                         String regexString = splitRegex[i];
1723                         if (regexString.startsWith(String.valueOf(regexIndex))) {
1724                             // Do matching on actual match and not on regex string
1725                             String actualMatch = regexString.split("\\R", 2)[1];
1726                             Asserts.assertTrue(matches.stream().allMatch(actualMatch::contains),
1727                                                errorPrefix() + " could not find all matches at Constraint " + regexIndex);
1728                             matched = true;
1729                         }
1730                     }
1731                 }
1732             }
1733         }
1734     }
1735 }
1736 
1737 // Base class for all good regex based constraints.
1738 abstract class GoodRegexConstraint extends RegexConstraint {
1739 
1740     GoodRegexConstraint(Class<?> klass, String methodName, String category, int ruleIdx, int... regexIndexes) {
1741         super(klass, methodName, category, true, null, ruleIdx, regexIndexes);
1742     }
1743 }
1744 
1745 // Constraint for rule that might fail with "counts" or "failOn", but the specified regex in "failOn" does not fail.
1746 class GoodFailOnRegexConstraint extends GoodRegexConstraint {
1747 
1748     private GoodFailOnRegexConstraint(Class<?> klass, String methodName, int ruleIdx, int... regexIndexes) {
1749         super(klass, methodName, "failOn", ruleIdx, regexIndexes);
1750     }
1751 
1752 
1753     public static GoodFailOnRegexConstraint create(Class<?> klass, String methodName, int ruleIdx, int... regexIndexes) {
1754         return new GoodFailOnRegexConstraint(klass, methodName, ruleIdx, regexIndexes);
1755     }
1756 }
1757 
1758 
1759 // Constraint for rule that might fail with "counts" or "failOn", but the specified regex in "counts" does not fail.
1760 class GoodCountsRegexConstraint extends GoodRegexConstraint {
1761 
1762     private GoodCountsRegexConstraint(Class<?> klass, String methodName, int ruleIdx, int... regexIndexes) {
1763         super(klass, methodName, "counts", ruleIdx, regexIndexes);
1764     }
1765 
1766 
1767     public static GoodCountsRegexConstraint create(Class<?> klass, String methodName, int ruleIdx, int... regexIndexes) {
1768         return new GoodCountsRegexConstraint(klass, methodName, ruleIdx, regexIndexes);
1769     }
1770 }
1771 
1772 // Constraint for rule that fails with "failOn" and the specified regex must also fail.
1773 class BadFailOnConstraint extends RegexConstraint {
1774 
1775     BadFailOnConstraint(Class<?> klass, String methodName, int ruleIdx, List<String> matches, int... regexIndexes) {
1776         super(klass, methodName, "failOn", false, matches, ruleIdx, regexIndexes);
1777     }
1778 
1779     public static BadFailOnConstraint create(Class<?> klass, String methodName, int ruleIdx, int regexId, String... matches) {
1780         return new BadFailOnConstraint(klass, methodName, ruleIdx, new ArrayList<>(Arrays.asList(matches)), regexId);
1781     }
1782 
1783     public static BadFailOnConstraint create(Class<?> klass, String methodName, int ruleIdx, String... matches) {
1784         return new BadFailOnConstraint(klass, methodName, ruleIdx, new ArrayList<>(Arrays.asList(matches)), 1);
1785     }
1786 }
1787 
1788 // Constraint for rule that fails with "counts" and the specified regex must also fail.
1789 class BadCountsConstraint extends RegexConstraint {
1790 
1791     BadCountsConstraint(Class<?> klass, String methodName, int ruleIdx, List<String> matches, int... regexIndexes) {
1792         super(klass, methodName, "counts", false, matches, ruleIdx, regexIndexes);
1793     }
1794 
1795     public static BadCountsConstraint create(Class<?> klass, String methodName, int ruleIdx, int regexId, int foundCount, String... matches) {
1796         List<String> matchesList = getMatchesList(foundCount, matches, Arrays.asList(matches));
1797         return new BadCountsConstraint(klass, methodName, ruleIdx, matchesList, regexId);
1798     }
1799 
1800     public static BadCountsConstraint create(Class<?> klass, String methodName, int ruleIdx, int foundCount, String... matches) {
1801         List<String> matchesList = getMatchesList(foundCount, matches, Arrays.asList(matches));
1802         return new BadCountsConstraint(klass, methodName, ruleIdx, matchesList, 1);
1803     }
1804 
1805     private static List<String> getMatchesList(int foundCount, String[] matches, List<String> strings) {
1806         List<String> matchesList = new ArrayList<>();
1807         matchesList.add("Failed comparison: [found] " + foundCount);
1808         if (matches != null) {
1809             matchesList.addAll(strings);
1810         }
1811         return matchesList;
1812     }
1813 }