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