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