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