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, 2, "Load"), 104 GoodCountsConstraint.create(BadCount.class, "bad1()", 2), 105 GoodCountsConstraint.create(BadCount.class, "bad2()", 1), 106 BadCountsConstraint.create(BadCount.class, "bad2()", 2, 2, "Store"), 107 BadCountsConstraint.create(BadCount.class, "bad3()", 1, 2, "Load"), 108 BadCountsConstraint.create(BadCount.class, "bad3()", 2, 2, "Store") 109 ); 110 111 runCheck(GoodRuleConstraint.create(Calls.class, "calls()", 1), 112 BadFailOnConstraint.create(Calls.class, "calls()", 2, 1, "CallStaticJava", "dontInline"), 113 BadFailOnConstraint.create(Calls.class, "calls()", 2, 2, "CallStaticJava", "dontInline"), 114 GoodRuleConstraint.create(Calls.class, "calls()", 3) 115 ); 116 117 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, "< 2", 636 IRNode.STORE, "<2", 637 IRNode.STORE, " < 2", 638 IRNode.STORE, " < 2", 639 }) 640 public void countComparison() { 641 iFld = 3; 642 } 643 } 644 645 class GoodCount { 646 boolean flag; 647 char cFld; 648 byte bFld; 649 short sFld; 650 int iFld; 651 long lFld; 652 float fFld; 653 double dFld; 654 long x; 655 656 long result; 657 MyClass myClass = new MyClass(); 658 MyClassEmpty myClassEmpty = new MyClassEmpty(); 659 MyClass myClassSubPoly = new MyClassSub(); 660 MyClassSub myClassSub = new MyClassSub(); 661 662 @Test 663 @IR(counts = {IRNode.STORE, "1", IRNode.STORE_I, "1"}, 664 failOn = {IRNode.STORE_B, IRNode.STORE_C, IRNode.STORE_D, 665 IRNode.STORE_F, IRNode.STORE_L}) 666 public void good1() { 667 iFld = 3; 668 } 669 670 @Test 671 @IR(counts = {IRNode.STORE, "8", 672 IRNode.STORE_B, "2", // bFld + flag 673 IRNode.STORE_C, "2", // cFld + sFld 674 IRNode.STORE_I, "1", 675 IRNode.STORE_L, "1", 676 IRNode.STORE_F, "1", 677 IRNode.STORE_D, "1"}) 678 public void good2() { 679 flag = true; 680 cFld = 'a'; 681 bFld = 1; 682 sFld = 2; 683 iFld = 3; 684 lFld = 4L; 685 fFld = 5.0f; 686 dFld = 6.0; 687 } 688 689 @Test 690 @IR(counts = {IRNode.STORE, "8", IRNode.STORE_OF_CLASS, "GoodCount", "8", 691 IRNode.STORE_B, "2", IRNode.STORE_B_OF_CLASS, "GoodCount", "2", 692 IRNode.STORE_C, "2", IRNode.STORE_C_OF_CLASS, "GoodCount", "2", 693 IRNode.STORE_I, "1", IRNode.STORE_I_OF_CLASS, "GoodCount", "1", 694 IRNode.STORE_L, "1", IRNode.STORE_L_OF_CLASS, "GoodCount", "1", 695 IRNode.STORE_F, "1", IRNode.STORE_F_OF_CLASS, "GoodCount", "1", 696 IRNode.STORE_D, "1", IRNode.STORE_D_OF_CLASS, "GoodCount", "1"}) 697 public void good3() { 698 flag = true; 699 cFld = 'a'; 700 bFld = 1; 701 sFld = 2; 702 iFld = 3; 703 lFld = 4L; 704 fFld = 5.0f; 705 dFld = 6.0; 706 } 707 708 @Test 709 @IR(counts = {IRNode.STORE, "8", IRNode.STORE_OF_CLASS, "GoodCount", "8", 710 IRNode.STORE_B, "2", IRNode.STORE_B_OF_CLASS, "GoodCount", "2", 711 IRNode.STORE_C, "2", IRNode.STORE_C_OF_CLASS, "GoodCount", "2", 712 IRNode.STORE_I, "1", IRNode.STORE_I_OF_CLASS, "GoodCount", "1", 713 IRNode.STORE_L, "1", IRNode.STORE_L_OF_CLASS, "GoodCount", "1", 714 IRNode.STORE_F, "1", IRNode.STORE_F_OF_CLASS, "GoodCount", "1", 715 IRNode.STORE_D, "1", IRNode.STORE_D_OF_CLASS, "GoodCount", "1", 716 IRNode.STORE_OF_FIELD, "lFld", "1"}) 717 public void good4() { 718 flag = true; 719 cFld = 'a'; 720 bFld = 1; 721 sFld = 2; 722 iFld = 3; 723 lFld = 4L; 724 fFld = 5.0f; 725 dFld = 6.0; 726 } 727 728 @Test 729 @IR(counts = {IRNode.STORE, "2", IRNode.STORE_I, "1", IRNode.STORE_L, "1", 730 IRNode.STORE_OF_CLASS, "GoodCount", "1", IRNode.STORE_L_OF_CLASS, "GoodCount", "1", 731 IRNode.STORE_OF_CLASS, "ir_framework/tests/MyClass", "1", 732 IRNode.STORE_I_OF_CLASS, "ir_framework/tests/MyClass", "1", 733 IRNode.STORE_OF_CLASS, "ir_framework/tests/GoodCount", "1", 734 IRNode.STORE_L_OF_CLASS, "ir_framework/tests/GoodCount", "1", 735 IRNode.STORE_OF_FIELD, "x", "2"}) 736 public void good5() { 737 x = 3; // long 738 myClass.x = 4; // int 739 } 740 741 @Test 742 @IR(counts = {IRNode.STORE_OF_FIELD, "myClassEmpty", "1", IRNode.STORE_OF_CLASS, "GoodCount", "1", 743 IRNode.STORE_OF_CLASS, "/GoodCount", "1", IRNode.STORE_OF_CLASS, "MyClassEmpty", "0"}, 744 failOn = {IRNode.STORE_OF_CLASS, "MyClassEmpty"}) 745 public void good6() { 746 myClassEmpty = new MyClassEmpty(); 747 } 748 749 @Test 750 @IR(counts = {IRNode.STORE_OF_FIELD, "iFld", "3", IRNode.STORE_OF_CLASS, "GoodCount", "0", 751 IRNode.STORE_OF_CLASS, "MyClass", "2", IRNode.STORE_OF_CLASS, "MyClassSub", "1", 752 IRNode.STORE, "3"}, 753 failOn = {IRNode.STORE_OF_CLASS, "GoodCount"}) 754 public void good7() { 755 myClass.iFld = 1; 756 myClassSubPoly.iFld = 2; 757 myClassSub.iFld = 3; 758 } 759 760 @Test 761 @IR(counts = {IRNode.LOAD, "1", IRNode.STORE, "1"}) 762 public void good8() { 763 result = iFld; 764 } 765 766 767 @Test 768 @IR(counts = {IRNode.LOAD, "4", IRNode.STORE, "1", IRNode.LOAD_OF_FIELD, "iFld", "2", IRNode.LOAD_OF_FIELD, "iFld2", "0", 769 IRNode.LOAD_OF_FIELD, "lFldStatic", "1", IRNode.LOAD_OF_CLASS, "GoodCount", "2", IRNode.LOAD_OF_CLASS, "MyClass", "1", 770 IRNode.STORE_OF_CLASS, "GoodCount", "1", IRNode.STORE_OF_FIELD, "result", "1", 771 IRNode.LOAD_OF_FIELD, "myClass", "1"}) 772 public void good9() { 773 result = iFld + MyClass.lFldStatic + myClass.iFld; // 1 + 1 + 2 loads (myClass is LoadN of GoodCount and myClass.iFld a LoadI of MyClass) 774 } 775 776 @Test 777 @IR(counts = {IRNode.LOAD, "8", 778 IRNode.LOAD_B, "1", 779 IRNode.LOAD_UB, "1", 780 IRNode.LOAD_S, "1", 781 IRNode.LOAD_US, "1", 782 IRNode.LOAD_I, "1", 783 IRNode.LOAD_L, "1", 784 IRNode.LOAD_F, "1", 785 IRNode.LOAD_D, "1"}) 786 public void good10() { 787 bFld++; 788 cFld++; 789 sFld++; 790 iFld++; 791 lFld++; 792 fFld++; 793 dFld++; 794 flag = !flag; 795 } 796 797 @Test 798 @IR(counts = {IRNode.LOAD, "8", IRNode.LOAD_OF_CLASS, "GoodCount", "8", 799 IRNode.LOAD_B, "1", IRNode.LOAD_B_OF_CLASS, "GoodCount", "1", 800 IRNode.LOAD_UB, "1", IRNode.LOAD_UB_OF_CLASS, "GoodCount", "1", 801 IRNode.LOAD_S, "1", IRNode.LOAD_S_OF_CLASS, "GoodCount", "1", 802 IRNode.LOAD_US, "1", IRNode.LOAD_US_OF_CLASS, "GoodCount", "1", 803 IRNode.LOAD_I, "1", IRNode.LOAD_I_OF_CLASS, "GoodCount", "1", 804 IRNode.LOAD_L, "1", IRNode.LOAD_L_OF_CLASS, "GoodCount", "1", 805 IRNode.LOAD_F, "1", IRNode.LOAD_F_OF_CLASS, "GoodCount", "1", 806 IRNode.LOAD_D, "1", IRNode.LOAD_D_OF_CLASS, "GoodCount", "1"}) 807 public void good11() { 808 bFld++; 809 cFld++; 810 sFld++; 811 iFld++; 812 lFld++; 813 fFld++; 814 dFld++; 815 flag = !flag; 816 } 817 } 818 819 class BadCount { 820 int iFld; 821 int iFld2; 822 int result; 823 int result2; 824 @Test 825 @IR(counts = {IRNode.LOAD, "> 1000"}) // fail 826 @IR(counts = {IRNode.STORE, "> 0"}) 827 public void bad1() { 828 result = iFld; 829 result2 = iFld2; 830 } 831 832 @Test 833 @IR(counts = {IRNode.LOAD, "2"}) // fail 834 @IR(counts = {IRNode.STORE, "< 2"}) 835 public void bad2() { 836 result = iFld; 837 result2 = iFld2; 838 } 839 840 841 @Test 842 @IR(counts = {IRNode.LOAD, "0"}) // fail 843 @IR(counts = {IRNode.STORE, " <= 1"}) // fail 844 public void bad3() { 845 result = iFld; 846 result2 = iFld2; 847 } 848 } 849 850 851 class RunTests { 852 public int iFld; 853 854 @Test 855 @IR(counts = {IRNode.STORE, "1"}) 856 @IR(failOn = IRNode.LOAD) 857 public void good1() { 858 iFld = 42; 859 } 860 861 @Test 862 @IR(counts = {IRNode.LOAD, "1"}) 863 @IR(failOn = IRNode.STORE) 864 public int good2() { 865 return iFld; 866 } 867 868 @Run(test = {"good1", "good2"}) 869 public void runGood1() { 870 good1(); 871 good2(); 872 } 873 874 875 @Test 876 @IR(counts = {IRNode.STORE, "1"}) 877 @IR(failOn = IRNode.LOAD) 878 public void good3(int x) { 879 iFld = x; 880 } 881 882 @Test 883 @IR(counts = {IRNode.STORE, "1"}) 884 @IR(failOn = IRNode.LOAD) 885 public int bad1(int x) { 886 return iFld + x; 887 } 888 889 @Run(test = {"bad1", "good3"}) 890 public void run() { 891 bad1(2); 892 good3(4); 893 } 894 } 895 896 class Calls { 897 898 @Test 899 @IR(counts = {IRNode.CALL, "1"}) 900 @IR(failOn = {IRNode.CALL_OF_METHOD, "dontInline", // Fails 901 IRNode.STATIC_CALL_OF_METHOD, "dontInline"}) // Fails 902 @IR(failOn = {IRNode.CALL_OF_METHOD, "forceInline", 903 IRNode.STATIC_CALL_OF_METHOD, "forceInline", 904 IRNode.CALL_OF_METHOD, "dontInlines", 905 IRNode.STATIC_CALL_OF_METHOD, "dontInlines", 906 IRNode.CALL_OF_METHOD, "dont", 907 IRNode.STATIC_CALL_OF_METHOD, "dont"}) 908 public void calls() { 909 dontInline(); 910 forceInline(); 911 } 912 913 @DontInline 914 public void dontInline() {} 915 916 @ForceInline 917 public void forceInline() {} 918 } 919 920 class AllocArray { 921 MyClass[] myClassArray; 922 923 @Test 924 @IR(failOn = {IRNode.ALLOC_ARRAY}) 925 @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "MyClass"}) 926 @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "MyClasss"}) // Does not fail 927 @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "ir_framework/tests/MySubClass"}) // Does not fail 928 @IR(failOn = {IRNode.ALLOC_ARRAY_OF, "ir_framework/tests/MyClass"}) 929 public void allocArray() { 930 myClassArray = new MyClass[2]; 931 } 932 } 933 934 class Loads { 935 int iFld = 34; 936 int result = 0; 937 Object myClass = new MyClass(); 938 939 @Test 940 @IR(failOn = {IRNode.LOAD, IRNode.LOOP, IRNode.LOAD_I}, counts = {IRNode.LOOP, "2", IRNode.LOAD, "2", IRNode.STORE, "2"}) 941 @IR(failOn = {IRNode.LOOP, IRNode.LOOP}, counts = {IRNode.LOOP, "0", IRNode.LOAD, "1"}) // Does not fail 942 @IR(failOn = {IRNode.LOOP, IRNode.LOOP}, counts = {IRNode.LOOP, "0", IRNode.STORE, "1"}) 943 @IR(failOn = {IRNode.LOOP, IRNode.STORE}, counts = {IRNode.LOOP, "0", IRNode.LOAD, "1"}) 944 @IR(failOn = {IRNode.LOAD_OF_CLASS, "ir_framework/tests/Loads"}) 945 @IR(failOn = {IRNode.LOAD_OF_CLASS, "Loads"}) 946 @IR(failOn = {IRNode.LOAD_OF_FIELD, "iFld"}) 947 @IR(failOn = {IRNode.LOAD_OF_FIELD, "iFld2", IRNode.LOAD_OF_CLASS, "Load"}) // Does not fail 948 @IR(failOn = {IRNode.LOAD_KLASS}) // Does not fail 949 @IR(counts = {IRNode.FIELD_ACCESS, "3"}) // Does not fail 950 public void load() { 951 result = iFld; 952 iFld = 3; 953 } 954 955 @Test 956 @IR(failOn = {IRNode.LOAD_KLASS}) 957 @IR(counts = {IRNode.FIELD_ACCESS, "3"}) 958 public void loadKlass() { 959 if (myClass instanceof MyClass) { 960 result = 3; 961 } 962 } 963 } 964 965 class Loops { 966 int limit = 1024; 967 int[] iArr = new int[100]; 968 969 @DontInline 970 public void dontInline() {} 971 972 @Test 973 @IR(failOn = IRNode.LOOP) // fails 974 @IR(failOn = IRNode.COUNTED_LOOP) 975 @IR(failOn = IRNode.COUNTED_LOOP_MAIN) 976 public void loop() { 977 for (int i = 0; i < limit; i++) { 978 dontInline(); 979 } 980 } 981 982 @Test 983 @IR(failOn = IRNode.LOOP) 984 @IR(failOn = IRNode.COUNTED_LOOP) // fails 985 @IR(failOn = IRNode.COUNTED_LOOP_MAIN) 986 public void countedLoop() { 987 for (int i = 0; i < 2000; i++) { 988 dontInline(); 989 } 990 } 991 992 @Test 993 @IR(failOn = IRNode.LOOP) // fails 994 @IR(failOn = IRNode.COUNTED_LOOP) // fails 995 @IR(failOn = IRNode.COUNTED_LOOP_MAIN) 996 public void loopAndCountedLoop() { 997 for (int i = 0; i < 2000; i++) { 998 for (int j = 0; j < limit; j++) { 999 dontInline(); 1000 } 1001 } 1002 } 1003 1004 @Test 1005 @IR(failOn = IRNode.LOOP) 1006 @IR(failOn = IRNode.COUNTED_LOOP) // fails 1007 @IR(failOn = IRNode.COUNTED_LOOP_MAIN) // fails 1008 public void countedLoopMain() { 1009 // Cannot unroll completely -> create pre/main/post 1010 for (int i = 0; i < 100; i++) { 1011 iArr[i] = i; 1012 } 1013 } 1014 1015 @Test 1016 @IR(failOn = IRNode.LOOP) 1017 @IR(failOn = IRNode.COUNTED_LOOP) 1018 @IR(failOn = IRNode.COUNTED_LOOP_MAIN) 1019 public void countedLoopUnrolled() { 1020 // Completely unrolled -> no pre/main/post 1021 for (int i = 0; i < 8; i++) { 1022 iArr[i] = i; 1023 } 1024 } 1025 } 1026 1027 class Traps { 1028 int number42 = 42; 1029 int iFld = 10; 1030 int[] iArr = new int[2]; 1031 MyClass myClass = new MyClass(); 1032 MyClassSub myClassSub = new MyClassSub(); 1033 NotLoaded notLoaded = new NotLoaded(); 1034 Object[] oArr = new Object[10]; 1035 MyClass[] mArr = new MyClass[10]; 1036 1037 @Test 1038 @IR(failOn = IRNode.TRAP) 1039 @IR(failOn = {IRNode.STORE_OF_FIELD, "iFld"}) // fails 1040 @IR(failOn = {IRNode.PREDICATE_TRAP, 1041 IRNode.UNSTABLE_IF_TRAP, 1042 IRNode.NULL_CHECK_TRAP, 1043 IRNode.NULL_ASSERT_TRAP, 1044 IRNode.RANGE_CHECK_TRAP, 1045 IRNode.CLASS_CHECK_TRAP, 1046 IRNode.INTRINSIC_TRAP, 1047 IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, 1048 IRNode.UNHANDLED_TRAP}) 1049 public void noTraps() { 1050 for (int i = 0; i < 100; i++) { 1051 if (i < 42) { 1052 // Reached, no uncommon trap 1053 iFld = i; 1054 } 1055 } 1056 } 1057 1058 @Test 1059 @IR(failOn = IRNode.TRAP) // fails 1060 @IR(failOn = IRNode.PREDICATE_TRAP) // fails 1061 @IR(failOn = {IRNode.STORE_OF_FIELD, "iFld"}) 1062 @IR(failOn = {IRNode.UNSTABLE_IF_TRAP, 1063 IRNode.NULL_CHECK_TRAP, 1064 IRNode.NULL_ASSERT_TRAP, 1065 IRNode.RANGE_CHECK_TRAP, 1066 IRNode.CLASS_CHECK_TRAP, 1067 IRNode.INTRINSIC_TRAP, 1068 IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, 1069 IRNode.UNHANDLED_TRAP}) 1070 public void predicateTrap() { 1071 for (int i = 0; i < 100; i++) { 1072 if (number42 != 42) { 1073 // Never reached 1074 iFld = i; 1075 } 1076 } 1077 } 1078 1079 @Test 1080 @IR(failOn = IRNode.TRAP) // fails 1081 @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails 1082 @IR(failOn = IRNode.UNSTABLE_IF_TRAP) // fails 1083 @IR(failOn = {IRNode.PREDICATE_TRAP, 1084 IRNode.NULL_ASSERT_TRAP, 1085 IRNode.RANGE_CHECK_TRAP, 1086 IRNode.CLASS_CHECK_TRAP, 1087 IRNode.INTRINSIC_TRAP, 1088 IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, 1089 IRNode.UNHANDLED_TRAP}) 1090 public void nullCheck() { 1091 if (myClass instanceof MyClassSub) { 1092 iFld = 4; 1093 } 1094 } 1095 1096 @Test 1097 @IR(failOn = IRNode.TRAP) // fails 1098 @IR(failOn = IRNode.NULL_ASSERT_TRAP) // fails 1099 @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails 1100 @IR(failOn = {IRNode.PREDICATE_TRAP, 1101 IRNode.UNSTABLE_IF_TRAP, 1102 IRNode.RANGE_CHECK_TRAP, 1103 IRNode.CLASS_CHECK_TRAP, 1104 IRNode.INTRINSIC_TRAP, 1105 IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, 1106 IRNode.UNHANDLED_TRAP}) 1107 public Object nullAssert() { 1108 return notLoaded.notLoadedFld; 1109 } 1110 1111 @Test 1112 @Arguments(Argument.TRUE) 1113 @IR(failOn = IRNode.TRAP) // fails 1114 @IR(failOn = IRNode.UNSTABLE_IF_TRAP) // fails 1115 @IR(failOn = {IRNode.PREDICATE_TRAP, 1116 IRNode.NULL_CHECK_TRAP, 1117 IRNode.NULL_ASSERT_TRAP, 1118 IRNode.RANGE_CHECK_TRAP, 1119 IRNode.CLASS_CHECK_TRAP, 1120 IRNode.INTRINSIC_TRAP, 1121 IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, 1122 IRNode.UNHANDLED_TRAP}) 1123 public void unstableIf(boolean flag) { 1124 if (flag) { 1125 iFld++; 1126 } else { 1127 iFld--; 1128 } 1129 } 1130 1131 @Test 1132 @IR(failOn = IRNode.TRAP) // fails 1133 @IR(failOn = IRNode.CLASS_CHECK_TRAP) // fails 1134 @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails 1135 @IR(failOn = {IRNode.PREDICATE_TRAP, 1136 IRNode.UNSTABLE_IF_TRAP, 1137 IRNode.NULL_ASSERT_TRAP, 1138 IRNode.RANGE_CHECK_TRAP, 1139 IRNode.INTRINSIC_TRAP, 1140 IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, 1141 IRNode.UNHANDLED_TRAP}) 1142 public void classCheck() { 1143 try { 1144 myClassSub = (MyClassSub) myClass; 1145 } catch (ClassCastException e) { 1146 // Expected 1147 } 1148 } 1149 1150 @Test 1151 @IR(failOn = IRNode.TRAP) // fails 1152 @IR(failOn = IRNode.RANGE_CHECK_TRAP) // fails 1153 @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails 1154 @IR(failOn = {IRNode.PREDICATE_TRAP, 1155 IRNode.UNSTABLE_IF_TRAP, 1156 IRNode.NULL_ASSERT_TRAP, 1157 IRNode.CLASS_CHECK_TRAP, 1158 IRNode.INTRINSIC_TRAP, 1159 IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, 1160 IRNode.UNHANDLED_TRAP}) 1161 public void rangeCheck() { 1162 iArr[1] = 3; 1163 } 1164 1165 1166 @Test 1167 @IR(failOn = IRNode.TRAP) // fails 1168 @IR(failOn = IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP) // fails 1169 @IR(failOn = IRNode.INTRINSIC_TRAP) // fails 1170 @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails 1171 @IR(failOn = {IRNode.PREDICATE_TRAP, 1172 IRNode.UNSTABLE_IF_TRAP, 1173 IRNode.NULL_ASSERT_TRAP, 1174 IRNode.CLASS_CHECK_TRAP, 1175 IRNode.RANGE_CHECK_TRAP, 1176 IRNode.UNHANDLED_TRAP}) 1177 public void instrinsicOrTypeCheckedInlining() { 1178 System.arraycopy(oArr, 0, mArr, 0, 8); 1179 } 1180 } 1181 1182 class UnhandledTrap { 1183 int iFld = 34; 1184 1185 @Test 1186 @IR(failOn = IRNode.TRAP) // fails 1187 @IR(failOn = IRNode.UNHANDLED_TRAP) // fails 1188 @IR(failOn = {IRNode.PREDICATE_TRAP, 1189 IRNode.UNSTABLE_IF_TRAP, 1190 IRNode.NULL_CHECK_TRAP, 1191 IRNode.NULL_ASSERT_TRAP, 1192 IRNode.RANGE_CHECK_TRAP, 1193 IRNode.CLASS_CHECK_TRAP}) 1194 public void unhandled() { 1195 try { 1196 throw new RuntimeException(); 1197 } catch (RuntimeException e) { 1198 // Expected 1199 } 1200 } 1201 } 1202 1203 class ScopeObj { 1204 1205 @DontInline 1206 public void dontInline(int i) {} 1207 1208 @Test 1209 @IR(failOn = IRNode.SCOPE_OBJECT) // fails 1210 public int scopeObject() { 1211 MyClass myClass = new MyClass(); 1212 for (int i = 0; i < 100; i++) { 1213 dontInline(myClass.iFld); 1214 } 1215 return 3; 1216 } 1217 } 1218 1219 class Membar { 1220 volatile MyClass myClass; 1221 1222 @Test 1223 @IR(failOn = IRNode.MEMBAR) // fails 1224 public int membar() { 1225 myClass = new MyClass(); 1226 return myClass.x; 1227 } 1228 } 1229 1230 class CheckCastArray { 1231 Object[] oArr = new Object[10]; 1232 MyClass[] mArr = new MyClass[10]; 1233 1234 @Test 1235 @IR(failOn = IRNode.CHECKCAST_ARRAY) // fails 1236 @IR(failOn = {IRNode.CHECKCAST_ARRAY_OF, "MyClass", // fails 1237 IRNode.CHECKCAST_ARRAY_OF, "ir_framework/tests/MyClass"}) // fails 1238 @IR(failOn = {IRNode.CHECKCAST_ARRAY_OF, "MyClasss", IRNode.CHECKCAST_ARRAY_OF, "Object"}) 1239 public boolean array() { 1240 return oArr instanceof MyClass[]; 1241 } 1242 1243 @Test 1244 @IR(failOn = IRNode.CHECKCAST_ARRAYCOPY) // fails 1245 public Object[] arrayCopy(Object[] src, Class klass) { 1246 return Arrays.copyOf(src, 8, klass); 1247 } 1248 1249 @Run(test = "arrayCopy") 1250 public void testArrayCopy() { 1251 arrayCopy(mArr, MyClass[].class); 1252 arrayCopy(mArr, Object[].class); 1253 arrayCopy(mArr, MyClassEmpty[].class); 1254 } 1255 } 1256 1257 class CompilationOutputOfFails { 1258 private Object obj; 1259 1260 @Test 1261 @IR(failOn = IRNode.COUNTED_LOOP) 1262 @IR(failOn = {"call"}, 1263 phase = CompilePhase.PRINT_OPTO_ASSEMBLY) 1264 public void both1() { 1265 for (int i = 0; i < 100; i++) { 1266 dontInline(); 1267 } 1268 } 1269 1270 @Test 1271 @IR(failOn = "CountedLoop|call", 1272 phase = {CompilePhase.PRINT_IDEAL, CompilePhase.PRINT_OPTO_ASSEMBLY}) 1273 public void both2() { 1274 for (int i = 0; i < 100; i++) { 1275 dontInline(); 1276 } 1277 } 1278 1279 @Test 1280 @IR(failOn = IRNode.COUNTED_LOOP) 1281 @IR(failOn = "call", phase = CompilePhase.PRINT_OPTO_ASSEMBLY) 1282 public void both3() { 1283 for (int i = 0; i < 100; i++) { 1284 dontInline(); 1285 } 1286 } 1287 1288 @Test 1289 @IR(counts = {IRNode.COUNTED_LOOP, "0"}) 1290 @IR(counts = {"call", "0"}, 1291 phase = {CompilePhase.PRINT_OPTO_ASSEMBLY}) 1292 public void both4() { 1293 for (int i = 0; i < 100; i++) { 1294 dontInline(); 1295 } 1296 } 1297 1298 @Test 1299 @IR(counts = {"CountedLoop|call", "10"}, 1300 phase = {CompilePhase.PRINT_IDEAL, CompilePhase.PRINT_OPTO_ASSEMBLY}) 1301 public void both5() { 1302 for (int i = 0; i < 100; i++) { 1303 dontInline(); 1304 } 1305 } 1306 1307 @Test 1308 @IR(counts = {IRNode.COUNTED_LOOP, "0"}) 1309 @IR(counts = {"call", "0"}, phase = CompilePhase.PRINT_OPTO_ASSEMBLY) 1310 public void both6() { 1311 for (int i = 0; i < 100; i++) { 1312 dontInline(); 1313 } 1314 } 1315 1316 @Test 1317 @IR(failOn = IRNode.COUNTED_LOOP) 1318 @IR(counts = {"call", "0"}, phase = CompilePhase.PRINT_OPTO_ASSEMBLY) 1319 public void both7() { 1320 for (int i = 0; i < 100; i++) { 1321 dontInline(); 1322 } 1323 } 1324 1325 @Test 1326 @IR(failOn = IRNode.COUNTED_LOOP) 1327 public void ideal1() { 1328 for (int i = 0; i < 100; i++) { 1329 dontInline(); 1330 } 1331 } 1332 1333 @Test 1334 @IR(failOn = IRNode.COUNTED_LOOP) 1335 @IR(failOn = IRNode.ALLOC) // not fail 1336 public void ideal2() { 1337 for (int i = 0; i < 100; i++) { 1338 dontInline(); 1339 } 1340 } 1341 1342 @Test 1343 @IR(failOn = IRNode.COUNTED_LOOP) 1344 @IR(counts = {IRNode.ALLOC, "0"}) // not fail 1345 public void ideal3() { 1346 for (int i = 0; i < 100; i++) { 1347 dontInline(); 1348 } 1349 } 1350 1351 @Test 1352 @IR(counts = {IRNode.COUNTED_LOOP, "2"}) 1353 public void ideal4() { 1354 for (int i = 0; i < 100; i++) { 1355 dontInline(); 1356 } 1357 } 1358 1359 @Test 1360 @IR(failOn = IRNode.ALLOC) // not fail 1361 @IR(counts = {IRNode.COUNTED_LOOP, "2"}) 1362 public void ideal5() { 1363 for (int i = 0; i < 100; i++) { 1364 dontInline(); 1365 } 1366 } 1367 1368 @Test 1369 @IR(counts = {IRNode.ALLOC, "0"}) // not fail 1370 @IR(counts = {IRNode.COUNTED_LOOP, "2"}) 1371 public void ideal6() { 1372 for (int i = 0; i < 100; i++) { 1373 dontInline(); 1374 } 1375 } 1376 1377 @Test 1378 @IR(counts = {IRNode.COUNTED_LOOP, "5"}) 1379 @IR(counts = {IRNode.COUNTED_LOOP, "2"}) 1380 public void ideal7() { 1381 for (int i = 0; i < 100; i++) { 1382 dontInline(); 1383 } 1384 } 1385 1386 @Test 1387 @IR(failOn = IRNode.ALLOC) 1388 public void opto1() { 1389 obj = new Object(); 1390 } 1391 1392 @Test 1393 @IR(failOn = IRNode.ALLOC) 1394 @IR(failOn = IRNode.STORE_F) // not fail 1395 public void opto2() { 1396 obj = new Object(); 1397 } 1398 1399 @Test 1400 @IR(failOn = IRNode.ALLOC) 1401 @IR(counts = {IRNode.COUNTED_LOOP, "1"}) // not fail 1402 public void opto3() { 1403 for (int i = 0; i < 100; i++) { 1404 obj = new Object(); 1405 } 1406 } 1407 1408 @Test 1409 @IR(counts = {IRNode.ALLOC, "0"}) 1410 public void opto4() { 1411 obj = new Object(); 1412 } 1413 1414 @Test 1415 @IR(failOn = IRNode.STORE_F) // not fail 1416 @IR(counts = {IRNode.ALLOC, "0"}) 1417 public void opto5() { 1418 obj = new Object(); 1419 } 1420 1421 @Test 1422 @IR(counts = {IRNode.STORE_F, "0"}) // not fail 1423 @IR(counts = {IRNode.ALLOC, "0"}) 1424 public void opto6() { 1425 obj = new Object(); 1426 } 1427 1428 @Test 1429 @IR(counts = {IRNode.ALLOC, "10"}) 1430 @IR(counts = {IRNode.ALLOC, "0"}) 1431 public void opto7() { 1432 obj = new Object(); 1433 } 1434 1435 @DontInline 1436 private void dontInline() {} 1437 } 1438 1439 1440 // Used only by class Traps 1441 class NotLoaded { 1442 NotLoadedHelper notLoadedFld; 1443 } 1444 1445 // Used only by class Traps 1446 class NotLoadedHelper {} 1447 1448 class MyClass { 1449 int iFld = 3; 1450 int x = 5; 1451 static long lFldStatic; 1452 } 1453 1454 class MyClassEmpty {} 1455 1456 class MyClassEmptySub extends MyClassEmpty {} 1457 1458 class MyClassSub extends MyClass { 1459 int iFld; 1460 static int iFldStatic; 1461 } 1462 1463 1464 // Base class for any kind of constraint that is used to verify if the framework reports the correct IR failures. 1465 abstract class Constraint { 1466 private final Class<?> klass; 1467 protected final int ruleIdx; 1468 private final Pattern methodPattern; 1469 private final String classAndMethod; 1470 protected final Pattern irPattern; 1471 private final String methodName; 1472 protected boolean matched; 1473 1474 Constraint(Class<?> klass, String methodName, int ruleIdx, Pattern irPattern) { 1475 this.klass = klass; 1476 classAndMethod = klass.getSimpleName() + "." + methodName; 1477 this.ruleIdx = ruleIdx; 1478 this.methodPattern = Pattern.compile(Pattern.quote(classAndMethod)); 1479 this.irPattern = irPattern; 1480 this.methodName = methodName; 1481 this.matched = false; 1482 } 1483 1484 // For good constraints only 1485 Constraint(Class<?> klass, String methodName, int ruleIdx) { 1486 this.klass = klass; 1487 classAndMethod = klass.getSimpleName() + "." + methodName; 1488 this.ruleIdx = ruleIdx; 1489 this.methodPattern = Pattern.compile(Pattern.quote(classAndMethod)); 1490 this.irPattern = null; 1491 this.methodName = methodName; 1492 this.matched = false; 1493 } 1494 1495 @Override 1496 public String toString() { 1497 return "Constraint " + getClass().getSimpleName() + ", " + errorPrefix(); 1498 } 1499 1500 public Class<?> getKlass() { 1501 return klass; 1502 } 1503 1504 protected String errorPrefix() { 1505 return "Class " + klass.getSimpleName() + ", Method " + methodName + ", Rule " + ruleIdx; 1506 } 1507 1508 public void checkConstraint(IRViolationException e) { 1509 String message = e.getExceptionInfo(); 1510 String[] splitMethods = message.split("Method"); 1511 for (int i = 1; i < splitMethods.length; i++) { 1512 String method = splitMethods[i]; 1513 if (methodPattern.matcher(method).find()) { 1514 String[] splitIrRules = method.split("@IR "); 1515 for (int j = 1; j < splitIrRules.length; j++) { 1516 String irRule = splitIrRules[j]; 1517 if (irRule.startsWith("rule " + ruleIdx)) { 1518 checkIRRule(irRule); 1519 } 1520 } 1521 } 1522 } 1523 Asserts.assertTrue(matched, this + " should have been matched"); 1524 } 1525 1526 abstract protected void checkIRRule(String irRule); 1527 } 1528 1529 // Constraint for rule that does not fail. 1530 class GoodRuleConstraint extends Constraint { 1531 1532 GoodRuleConstraint(Class<?> klass, String methodName, int ruleIdx) { 1533 super(klass, methodName, ruleIdx); 1534 matched = true; 1535 } 1536 1537 public static GoodRuleConstraint create(Class<?> klass, String methodName, int ruleIdx) { 1538 return new GoodRuleConstraint(klass, methodName, ruleIdx); 1539 } 1540 1541 @Override 1542 protected void checkIRRule(String irRule) { 1543 Asserts.fail(errorPrefix() + " should not fail:" + System.lineSeparator() + irRule); 1544 } 1545 } 1546 1547 // Constraint for rule that might fail but not with "failOn". 1548 class GoodFailOnConstraint extends GoodRuleConstraint { 1549 1550 private GoodFailOnConstraint(Class<?> klass, String methodName, int ruleIdx) { 1551 super(klass, methodName, ruleIdx); 1552 } 1553 1554 public static GoodFailOnConstraint create(Class<?> klass, String methodName, int ruleIdx) { 1555 return new GoodFailOnConstraint(klass, methodName, ruleIdx); 1556 } 1557 1558 @Override 1559 protected void checkIRRule(String irRule) { 1560 Asserts.assertFalse(irRule.contains("- failOn"), errorPrefix() + " should not have failed:" + System.lineSeparator() + irRule); 1561 } 1562 } 1563 1564 // Constraint for rule that might fail but not with "counts". 1565 class GoodCountsConstraint extends GoodRuleConstraint { 1566 1567 private GoodCountsConstraint(Class<?> klass, String methodName, int ruleIdx) { 1568 super(klass, methodName, ruleIdx); 1569 } 1570 1571 public static GoodCountsConstraint create(Class<?> klass, String methodName, int ruleIdx) { 1572 return new GoodCountsConstraint(klass, methodName, ruleIdx); 1573 } 1574 1575 @Override 1576 protected void checkIRRule(String irRule) { 1577 Asserts.assertFalse(irRule.contains("- counts"), errorPrefix() + " should not have failed with counts:" 1578 + System.lineSeparator() + irRule); 1579 } 1580 } 1581 1582 // Base class for all Regex based constraint. 1583 abstract class RegexConstraint extends Constraint { 1584 final String category; 1585 final String otherCategory; 1586 final int[] regexIndexes; 1587 final boolean isGood; 1588 final List<String> matches; 1589 1590 RegexConstraint(Class<?> klass, String methodName, String category, boolean isGood, List<String> matches, int ruleIdx, int... regexIndexes) { 1591 super(klass, methodName, ruleIdx, initIRPattern(category, ruleIdx)); 1592 this.category = category; 1593 this.regexIndexes = regexIndexes; 1594 if (category.equals("failOn")) { 1595 this.otherCategory = "counts"; 1596 } else { 1597 Asserts.assertTrue(category.equals("counts")); 1598 this.otherCategory = "failOn"; 1599 } 1600 this.isGood = isGood; 1601 this.matches = matches; 1602 } 1603 1604 @Override 1605 public String toString() { 1606 String msg = super.toString() + ", "; 1607 if (regexIndexes.length > 1) { 1608 msg += "regexes: [" + String.join(", ", Arrays.stream(regexIndexes).mapToObj(String::valueOf).toArray(String[]::new)) + "]"; 1609 } else { 1610 msg += "regex: " + regexIndexes[0]; 1611 } 1612 return msg; 1613 } 1614 1615 @Override 1616 protected String errorPrefix() { 1617 return super.errorPrefix() + " with \"" + category + "\""; 1618 } 1619 1620 private static Pattern initIRPattern(String category, int ruleIdx) { 1621 if (category.equals("failOn")) { 1622 return Pattern.compile("rule " + ruleIdx + ":.*\\R.*- failOn: Graph contains forbidden nodes.*\\R" + 1623 ".*Constraint \\d+:.*\\R.*Matched forbidden node.*"); 1624 } else { 1625 return Pattern.compile("rule " + ruleIdx + ":.*\\R.*- counts: Graph contains wrong number of nodes:\\R" + 1626 ".*Constraint \\d+:.*\\R.*Expected.*"); 1627 } 1628 } 1629 1630 @Override 1631 protected void checkIRRule(String irRule) { 1632 int categoryIndex = irRule.indexOf("- " + category); 1633 Asserts.assertTrue(categoryIndex != -1, errorPrefix() + " should have failed"); 1634 1635 int endIndex; 1636 int otherCategoryIndex = irRule.indexOf("- " + otherCategory); 1637 if (otherCategoryIndex == -1 || categoryIndex > otherCategoryIndex) { 1638 endIndex = irRule.length(); 1639 } else { 1640 endIndex = otherCategoryIndex; 1641 } 1642 String categoryString = irRule.substring(irRule.indexOf("- " + category), endIndex); 1643 Pattern pattern; 1644 Matcher matcher; 1645 for (int regexIndex : this.regexIndexes) { 1646 pattern = Pattern.compile("Constraint " + regexIndex + ":.*"); 1647 matcher = pattern.matcher(categoryString); 1648 if (isGood) { 1649 Asserts.assertFalse(matcher.find(), errorPrefix() + " failed with Constraint " + regexIndex); 1650 matched = true; 1651 } else { 1652 Asserts.assertTrue(matcher.find(), errorPrefix() + " should have failed at Constraint " + regexIndex); 1653 String[] splitRegex = categoryString.split("Constraint "); 1654 if (matches != null) { 1655 for (int i = 1; i < splitRegex.length; i++) { 1656 String regexString = splitRegex[i]; 1657 if (regexString.startsWith(String.valueOf(regexIndex))) { 1658 // Do matching on actual match and not on regex string 1659 String actualMatch = regexString.split("\\R", 2)[1]; 1660 Asserts.assertTrue(matches.stream().allMatch(actualMatch::contains), 1661 errorPrefix() + " could not find all matches at Constraint " + regexIndex); 1662 matched = true; 1663 } 1664 } 1665 } 1666 } 1667 } 1668 } 1669 } 1670 1671 // Base class for all good regex based constraints. 1672 abstract class GoodRegexConstraint extends RegexConstraint { 1673 1674 GoodRegexConstraint(Class<?> klass, String methodName, String category, int ruleIdx, int... regexIndexes) { 1675 super(klass, methodName, category, true, null, ruleIdx, regexIndexes); 1676 } 1677 } 1678 1679 // Constraint for rule that might fail with "counts" or "failOn", but the specified regex in "failOn" does not fail. 1680 class GoodFailOnRegexConstraint extends GoodRegexConstraint { 1681 1682 private GoodFailOnRegexConstraint(Class<?> klass, String methodName, int ruleIdx, int... regexIndexes) { 1683 super(klass, methodName, "failOn", ruleIdx, regexIndexes); 1684 } 1685 1686 1687 public static GoodFailOnRegexConstraint create(Class<?> klass, String methodName, int ruleIdx, int... regexIndexes) { 1688 return new GoodFailOnRegexConstraint(klass, methodName, ruleIdx, regexIndexes); 1689 } 1690 } 1691 1692 1693 // Constraint for rule that might fail with "counts" or "failOn", but the specified regex in "counts" does not fail. 1694 class GoodCountsRegexConstraint extends GoodRegexConstraint { 1695 1696 private GoodCountsRegexConstraint(Class<?> klass, String methodName, int ruleIdx, int... regexIndexes) { 1697 super(klass, methodName, "counts", ruleIdx, regexIndexes); 1698 } 1699 1700 1701 public static GoodCountsRegexConstraint create(Class<?> klass, String methodName, int ruleIdx, int... regexIndexes) { 1702 return new GoodCountsRegexConstraint(klass, methodName, ruleIdx, regexIndexes); 1703 } 1704 } 1705 1706 // Constraint for rule that fails with "failOn" and the specified regex must also fail. 1707 class BadFailOnConstraint extends RegexConstraint { 1708 1709 BadFailOnConstraint(Class<?> klass, String methodName, int ruleIdx, List<String> matches, int... regexIndexes) { 1710 super(klass, methodName, "failOn", false, matches, ruleIdx, regexIndexes); 1711 } 1712 1713 public static BadFailOnConstraint create(Class<?> klass, String methodName, int ruleIdx, int regexId, String... matches) { 1714 return new BadFailOnConstraint(klass, methodName, ruleIdx, new ArrayList<>(Arrays.asList(matches)), regexId); 1715 } 1716 1717 public static BadFailOnConstraint create(Class<?> klass, String methodName, int ruleIdx, String... matches) { 1718 return new BadFailOnConstraint(klass, methodName, ruleIdx, new ArrayList<>(Arrays.asList(matches)), 1); 1719 } 1720 } 1721 1722 // Constraint for rule that fails with "counts" and the specified regex must also fail. 1723 class BadCountsConstraint extends RegexConstraint { 1724 1725 BadCountsConstraint(Class<?> klass, String methodName, int ruleIdx, List<String> matches, int... regexIndexes) { 1726 super(klass, methodName, "counts", false, matches, ruleIdx, regexIndexes); 1727 } 1728 1729 public static BadCountsConstraint create(Class<?> klass, String methodName, int ruleIdx, int regexId, int foundCount, String... matches) { 1730 List<String> matchesList = getMatchesList(foundCount, matches, Arrays.asList(matches)); 1731 return new BadCountsConstraint(klass, methodName, ruleIdx, matchesList, regexId); 1732 } 1733 1734 public static BadCountsConstraint create(Class<?> klass, String methodName, int ruleIdx, int foundCount, String... matches) { 1735 List<String> matchesList = getMatchesList(foundCount, matches, Arrays.asList(matches)); 1736 return new BadCountsConstraint(klass, methodName, ruleIdx, matchesList, 1); 1737 } 1738 1739 private static List<String> getMatchesList(int foundCount, String[] matches, List<String> strings) { 1740 List<String> matchesList = new ArrayList<>(); 1741 matchesList.add("Failed comparison: [found] " + foundCount); 1742 if (matches != null) { 1743 matchesList.addAll(strings); 1744 } 1745 return matchesList; 1746 } 1747 }