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