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