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