1 /* 2 * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package ir_framework.tests; 25 26 import compiler.lib.ir_framework.*; 27 import compiler.lib.ir_framework.driver.irmatching.IRViolationException; 28 import jdk.test.lib.Asserts; 29 import jdk.test.lib.Platform; 30 import jdk.test.whitebox.WhiteBox; 31 32 import java.io.ByteArrayOutputStream; 33 import java.io.PrintStream; 34 import java.util.*; 35 import java.util.regex.Matcher; 36 import java.util.regex.Pattern; 37 38 /* 39 * @test 40 * @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler1.enabled & vm.compiler2.enabled & vm.flagless 41 * @summary Test IR matcher with different default IR node regexes. Use -DPrintIREncoding. 42 * Normally, the framework should be called with driver. 43 * @library /test/lib /testlibrary_tests / 44 * @build jdk.test.whitebox.WhiteBox 45 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 46 * @run main/othervm/timeout=240 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions 47 * -XX:+WhiteBoxAPI -DPrintIREncoding=true ir_framework.tests.TestIRMatching 48 */ 49 50 public class TestIRMatching { 51 52 private static final Map<Exception, String> exceptions = new LinkedHashMap<>(); 53 private static final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 54 private static final ByteArrayOutputStream baosErr = new ByteArrayOutputStream(); 55 private static final PrintStream ps = new PrintStream(baos); 56 private static final PrintStream psErr = new PrintStream(baosErr); 57 private static final PrintStream oldOut = System.out; 58 private static final PrintStream oldErr = System.err; 59 60 private static void addException(Exception e) { 61 System.out.flush(); 62 System.err.flush(); 63 exceptions.put(e, baos + System.lineSeparator() + baosErr); 64 } 65 66 public static void main(String[] args) { 67 // Redirect System.out and System.err to reduce noise. 68 System.setOut(ps); 69 System.setErr(psErr); 70 runWithArguments(AndOr1.class, "-XX:TLABRefillWasteFraction=52", "-XX:+UsePerfData", "-XX:+UseTLAB"); 71 runWithArguments(CountComparisons.class, "-XX:TLABRefillWasteFraction=50"); 72 runWithArguments(GoodCount.class, "-XX:TLABRefillWasteFraction=50"); 73 runWithArguments(MultipleFailOnGood.class, "-XX:TLABRefillWasteFraction=50"); 74 75 runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:+UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test1(int)", 1, "CallStaticJava")); 76 runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:-UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test2()", 1, "CallStaticJava")); 77 78 String[] allocMatches = { "MyClass", "wrapper for: _new_instance_Java" }; 79 runCheck(BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1()", 1, 1, "Store"), 80 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1()", 1, 3, "Store"), 81 GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail1()", 1, 2, 4), 82 GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail2()", 1, 1), 83 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail2()", 1, 2, "CallStaticJava"), 84 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail3()", 1, 2, "Store"), 85 GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail3()", 1, 1, 3), 86 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail4()", 1, 1, "Store"), 87 GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail4()", 1, 2, 3), 88 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail5()", 1, 1, "Store"), 89 GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail5()", 1, 2, 3), 90 GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail6()", 1, 1), 91 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail6()", 1, 2, allocMatches), 92 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail6()", 1, 3, "CallStaticJava"), 93 GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail7()", 1, 1), 94 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail7()", 1, 2, allocMatches), 95 GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail8()", 1, 1), 96 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail8()", 1, 2, allocMatches), 97 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail9()", 1, 1, "Store"), 98 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail9()", 1, 2, "CallStaticJava"), 99 BadFailOnConstraint.create(MultipleFailOnBad.class, "fail10()", 1, 1, "Store", "iFld"), 100 GoodFailOnRegexConstraint.create(MultipleFailOnBad.class, "fail10()", 1, 2, 3) 101 ); 102 103 runCheck(BadCountsConstraint.create(BadCount.class, "bad1()", 1, 1, "Load"), 104 GoodCountsConstraint.create(BadCount.class, "bad1()", 2), 105 GoodCountsConstraint.create(BadCount.class, "bad2()", 1), 106 BadCountsConstraint.create(BadCount.class, "bad2()", 2, 1, "Store"), 107 BadCountsConstraint.create(BadCount.class, "bad3()", 1, 1, "Load"), 108 BadCountsConstraint.create(BadCount.class, "bad3()", 2, 1, "Store") 109 ); 110 111 runCheck(GoodRuleConstraint.create(Calls.class, "calls()", 1), 112 BadFailOnConstraint.create(Calls.class, "calls()", 2, 1, "CallStaticJava", "dontInline"), 113 BadFailOnConstraint.create(Calls.class, "calls()", 2, 2, "CallStaticJava", "dontInline"), 114 GoodRuleConstraint.create(Calls.class, "calls()", 3) 115 ); 116 117 String[] allocArrayMatches = { "MyClass", "wrapper for: _new_array_Java"}; 118 runCheck(BadFailOnConstraint.create(AllocArray.class, "allocArray()", 1, allocArrayMatches), 119 BadFailOnConstraint.create(AllocArray.class, "allocArray()", 2, allocArrayMatches), 120 GoodFailOnConstraint.create(AllocArray.class, "allocArray()", 3), 121 GoodFailOnConstraint.create(AllocArray.class, "allocArray()", 4), 122 BadFailOnConstraint.create(AllocArray.class, "allocArray()", 5, allocArrayMatches) 123 ); 124 125 runCheck(GoodRuleConstraint.create(RunTests.class, "good1()", 1), 126 GoodRuleConstraint.create(RunTests.class, "good1()", 2), 127 GoodRuleConstraint.create(RunTests.class, "good2()", 1), 128 GoodRuleConstraint.create(RunTests.class, "good2()", 2), 129 GoodRuleConstraint.create(RunTests.class, "good3(int)", 1), 130 BadCountsConstraint.create(RunTests.class, "bad1(int)", 1, 0), 131 BadFailOnConstraint.create(RunTests.class, "bad1(int)", 2, "Load") 132 ); 133 134 runCheck(new String[] {"-XX:+IgnoreUnrecognizedVMOptions", "-XX:-UseCompressedClassPointers"}, 135 BadFailOnConstraint.create(Loads.class, "load()", 1, 1, "Load"), 136 BadFailOnConstraint.create(Loads.class, "load()", 1, 3, "LoadI"), 137 BadCountsConstraint.create(Loads.class, "load()", 1, 1, 0), 138 BadCountsConstraint.create(Loads.class, "load()", 1, 2, 1,"Load"), 139 GoodRuleConstraint.create(Loads.class, "load()", 2), 140 GoodFailOnConstraint.create(Loads.class, "load()", 3), 141 BadCountsConstraint.create(Loads.class, "load()", 3, 2, 2,"Store"), 142 BadFailOnConstraint.create(Loads.class, "load()", 4, 2, "Store"), 143 BadFailOnConstraint.create(Loads.class, "load()", 5, "Load"), 144 BadFailOnConstraint.create(Loads.class, "load()", 6, "Load"), 145 BadFailOnConstraint.create(Loads.class, "load()", 7, "Load"), 146 GoodRuleConstraint.create(Loads.class, "load()", 8), 147 GoodRuleConstraint.create(Loads.class, "load()", 9), 148 GoodRuleConstraint.create(Loads.class, "load()", 10), 149 BadFailOnConstraint.create(Loads.class, "loadKlass()", 1), 150 BadCountsConstraint.create(Loads.class, "loadKlass()", 2, 2,"Field") 151 ); 152 153 // Loops 154 runCheck(BadFailOnConstraint.create(Loops.class, "loop()", 1, "Loop"), 155 GoodRuleConstraint.create(Loops.class, "loop()", 2), 156 GoodRuleConstraint.create(Loops.class, "loop()", 3), 157 GoodRuleConstraint.create(Loops.class, "countedLoop()", 1), 158 BadFailOnConstraint.create(Loops.class, "countedLoop()", 2, "CountedLoop"), 159 GoodRuleConstraint.create(Loops.class, "countedLoop()", 3), 160 BadFailOnConstraint.create(Loops.class, "loopAndCountedLoop()", 1, "Loop"), 161 BadFailOnConstraint.create(Loops.class, "loopAndCountedLoop()", 2, "CountedLoop"), 162 GoodRuleConstraint.create(Loops.class, "loopAndCountedLoop()", 3), 163 GoodRuleConstraint.create(Loops.class, "countedLoopMain()", 1), 164 BadFailOnConstraint.create(Loops.class, "countedLoopMain()", 2, "CountedLoop"), 165 BadFailOnConstraint.create(Loops.class, "countedLoopMain()", 3, "CountedLoop", "main"), 166 GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled()", 1), 167 GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled()", 2), 168 GoodRuleConstraint.create(Loops.class, "countedLoopUnrolled()", 3) 169 ); 170 171 // Traps 172 runCheck(GoodRuleConstraint.create(Traps.class, "noTraps()", 1), 173 BadFailOnConstraint.create(Traps.class, "noTraps()", 2, "Store", "iFld"), 174 GoodRuleConstraint.create(Traps.class, "noTraps()", 3), 175 BadFailOnConstraint.create(Traps.class, "predicateTrap()", 1, "CallStaticJava", "uncommon_trap"), 176 BadFailOnConstraint.create(Traps.class, "predicateTrap()", 2, "CallStaticJava", "uncommon_trap", "predicate"), 177 GoodRuleConstraint.create(Traps.class, "predicateTrap()", 3), 178 GoodRuleConstraint.create(Traps.class, "predicateTrap()", 4), 179 BadFailOnConstraint.create(Traps.class, "nullCheck()", 1, "CallStaticJava", "uncommon_trap"), 180 BadFailOnConstraint.create(Traps.class, "nullCheck()", 2, "CallStaticJava", "uncommon_trap", "null_check"), 181 BadFailOnConstraint.create(Traps.class, "nullCheck()", 3, "uncommon_trap", "unstable_if"), 182 GoodRuleConstraint.create(Traps.class, "nullCheck()", 4), 183 BadFailOnConstraint.create(Traps.class, "nullAssert()", 1, "CallStaticJava", "uncommon_trap"), 184 BadFailOnConstraint.create(Traps.class, "nullAssert()", 2, "CallStaticJava", "uncommon_trap", "null_assert"), 185 BadFailOnConstraint.create(Traps.class, "nullAssert()", 3, "CallStaticJava", "uncommon_trap", "null_check"), 186 GoodRuleConstraint.create(Traps.class, "nullAssert()", 4), 187 BadFailOnConstraint.create(Traps.class, "unstableIf(boolean)", 1, "CallStaticJava", "uncommon_trap"), 188 BadFailOnConstraint.create(Traps.class, "unstableIf(boolean)", 2, "CallStaticJava", "uncommon_trap", "unstable_if"), 189 GoodRuleConstraint.create(Traps.class, "unstableIf(boolean)", 3), 190 BadFailOnConstraint.create(Traps.class, "classCheck()", 1, "CallStaticJava", "uncommon_trap"), 191 BadFailOnConstraint.create(Traps.class, "classCheck()", 2, "CallStaticJava", "uncommon_trap", "class_check"), 192 BadFailOnConstraint.create(Traps.class, "classCheck()", 3, "CallStaticJava", "uncommon_trap", "null_check"), 193 GoodRuleConstraint.create(Traps.class, "classCheck()", 4), 194 BadFailOnConstraint.create(Traps.class, "rangeCheck()", 1, "CallStaticJava", "uncommon_trap"), 195 BadFailOnConstraint.create(Traps.class, "rangeCheck()", 2, "CallStaticJava", "uncommon_trap", "range_check"), 196 BadFailOnConstraint.create(Traps.class, "rangeCheck()", 3, "CallStaticJava", "uncommon_trap", "null_check"), 197 GoodRuleConstraint.create(Traps.class, "rangeCheck()", 4), 198 BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 1, "CallStaticJava", "uncommon_trap"), 199 WhiteBox.getWhiteBox().isJVMCISupportedByGC() ? 200 BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 2, "CallStaticJava", "uncommon_trap", "intrinsic_or_type_checked_inlining") 201 : GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 2), 202 BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 3, "CallStaticJava", "uncommon_trap", "intrinsic"), 203 BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 4, "CallStaticJava", "uncommon_trap", "null_check"), 204 GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 5) 205 ); 206 207 208 runCheck(new String[] {"-XX:+BailoutToInterpreterForThrows"}, 209 BadFailOnConstraint.create(UnhandledTrap.class, "unhandled()", 1, "CallStaticJava", "uncommon_trap"), 210 BadFailOnConstraint.create(UnhandledTrap.class, "unhandled()", 2, "CallStaticJava", "uncommon_trap", "unhandled"), 211 GoodRuleConstraint.create(UnhandledTrap.class, "unhandled()", 3) 212 ); 213 214 runCheck(BadFailOnConstraint.create(ScopeObj.class, "scopeObject()", 1, "ScObj")); 215 runCheck(BadFailOnConstraint.create(Membar.class, "membar()", 1, "MemBar")); 216 217 String cmp; 218 if (Platform.isPPC() || Platform.isX86()) { 219 cmp = "CMP"; 220 } else if (Platform.isS390x()){ 221 cmp = "CLFI"; 222 } else { 223 cmp = "cmp"; 224 } 225 runCheck(BadFailOnConstraint.create(CheckCastArray.class, "array()", 1, cmp, "precise"), 226 BadFailOnConstraint.create(CheckCastArray.class, "array()", 2, 1,cmp, "precise", "MyClass"), 227 BadFailOnConstraint.create(CheckCastArray.class, "array()", 2, 2,cmp, "precise", "ir_framework/tests/MyClass"), 228 GoodFailOnConstraint.create(CheckCastArray.class, "array()", 3), 229 Platform.isS390x() ? // There is no checkcast_arraycopy stub for C2 on s390 230 GoodFailOnConstraint.create(CheckCastArray.class, "arrayCopy(java.lang.Object[],java.lang.Class)", 1) 231 : BadFailOnConstraint.create(CheckCastArray.class, "arrayCopy(java.lang.Object[],java.lang.Class)", 1, "checkcast_arraycopy") 232 ); 233 234 try { 235 runWithArgumentsFail(CompilationOutputOfFails.class); 236 Asserts.fail("Should have thrown exception"); 237 } catch (IRViolationException e) { 238 try { 239 StringBuilder failures = new StringBuilder(); 240 System.out.flush(); 241 String output = baos.toString(); 242 baos.reset(); 243 Pattern pattern = Pattern.compile(compilationPrefix() + ".*both\\d.*\\R> Phase \"" 244 + CompilePhase.PRINT_IDEAL.getName() 245 + "\":(?:(?!PrintOpto|" + compilationPrefix() 246 + ")[\\S\\s])+PrintOptoAssembly"); 247 Matcher matcher = pattern.matcher(output); 248 long bothCount = matcher.results().count(); 249 if (bothCount != 7L) { 250 failures.append("- Could not find all both() methods, expected 7 but found ").append(bothCount) 251 .append(System.lineSeparator()); 252 } 253 pattern = Pattern.compile(compilationPrefix() + ".*ideal\\d.*\\R> Phase \"" 254 + CompilePhase.PRINT_IDEAL.getName() 255 + "\":(?:(?!" + compilationPrefix() + ")[\\S\\s])+"); 256 matcher = pattern.matcher(output); 257 int count = 0; 258 while (matcher.find()) { 259 String match = matcher.group(); 260 if (match.contains("PrintOptoAssembly")) { 261 failures.append("Cannot contain opto assembly: ").append(System.lineSeparator()).append(match); 262 } 263 count++; 264 } 265 if (count != 7) { 266 failures.append("- Could not find all ideal() methods, expected 7 but found ").append(count) 267 .append(System.lineSeparator()); 268 } 269 pattern = Pattern.compile(compilationPrefix() + ".*opto\\d.*\\R> Phase \"PrintOptoAssembly\":(?:(?!" 270 + compilationPrefix() + ")[\\S\\s])+"); 271 matcher = pattern.matcher(output); 272 count = 0; 273 while (matcher.find()) { 274 String match = matcher.group(); 275 if (match.contains("PrintIdeal")) { 276 failures.append("Cannot contain print assembly: ").append(System.lineSeparator()).append(match); 277 } 278 count++; 279 } 280 if (count != 7) { 281 failures.append("- Could not find all opto() methods, expected 7 but found ").append(count).append(System.lineSeparator()); 282 } 283 if (!failures.isEmpty()) { 284 addException(new RuntimeException(failures.toString())); 285 } 286 } catch (Exception e1) { 287 addException(e1); 288 } 289 } catch (Exception e) { 290 addException(e); 291 } 292 293 runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=50"); 294 System.out.flush(); 295 String output = baos.toString(); 296 findIrIds(output, "testMatchAllIf50", 1, 22); 297 findIrIds(output, "testMatchNoneIf50", -1, -1); 298 299 runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=49"); 300 System.out.flush(); 301 output = baos.toString(); 302 findIrIds(output, "testMatchAllIf50", 5, 7, 14, 19); 303 findIrIds(output, "testMatchNoneIf50", 1, 4, 9, 11, 18, 23); 304 305 runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=51"); 306 System.out.flush(); 307 output = baos.toString(); 308 findIrIds(output, "testMatchAllIf50", 8, 13, 20, 22); 309 findIrIds(output, "testMatchNoneIf50", 5, 8, 12, 17, 21, 23); 310 System.setOut(oldOut); 311 System.setErr(oldErr); 312 313 if (!exceptions.isEmpty()) { 314 System.err.println("TestIRMatching failed with " + exceptions.size() + " exception(s):"); 315 int i = 1; 316 System.err.println("************************"); 317 for (Map.Entry<Exception, String> entry : exceptions.entrySet()) { 318 System.err.println("***** Exception " + String.format("%02d", i++) +" *****"); 319 System.err.println("************************"); 320 321 Exception e = entry.getKey(); 322 e.printStackTrace(System.err); 323 System.err.println(); 324 System.err.println("===== OUTPUT ======"); 325 System.err.println(entry.getValue()); 326 System.err.println("MESSAGE: " + e.getMessage()); 327 System.err.println("************************"); 328 } 329 i = 1; 330 System.err.println("===================================="); 331 System.err.println("********************"); 332 System.err.println("***** OVERVIEW *****"); 333 System.err.println("********************"); 334 for (Map.Entry<Exception, String> entry : exceptions.entrySet()) { 335 System.err.print((i++) + ") "); 336 entry.getKey().printStackTrace(System.err); 337 System.err.println("********************"); 338 } 339 throw new RuntimeException("TestIRMatching failed with " + exceptions.size() + " exception(s) - check stderr and stdout"); 340 } 341 } 342 343 private static void runFramework(TestFramework framework) { 344 baos.reset(); 345 baosErr.reset(); 346 framework.start(); 347 } 348 349 private static void runWithArguments(Class<?> clazz, String... args) { 350 try { 351 runFramework(new TestFramework(clazz).addFlags(args)); 352 } catch (Exception e) { 353 addException(e); 354 } 355 } 356 357 private static void runWithArgumentsFail(Class<?> clazz, String... args) { 358 runFramework(new TestFramework(clazz).addFlags(args)); 359 } 360 361 private static void runCheck(String[] args , Constraint... constraints) { 362 try { 363 TestFramework framework = new TestFramework(constraints[0].getKlass()); // All constraints have the same class. 364 if (args != null) { 365 framework.addFlags(args); 366 } 367 runFramework(framework); 368 Asserts.fail("Should have thrown exception"); 369 } catch (IRViolationException e) { 370 checkConstraints(e, constraints); 371 } catch (Exception e) { 372 addException(e); 373 } 374 } 375 376 private static void runCheck(Constraint... constraints) { 377 runCheck(null, constraints); 378 } 379 380 private static void checkConstraints(IRViolationException e, Constraint[] constraints) { 381 String message = e.getExceptionInfo(); 382 try { 383 for (Constraint constraint : constraints) { 384 constraint.checkConstraint(e); 385 } 386 } catch (Exception e1) { 387 System.out.println(e.getCompilations()); 388 System.out.println(message); 389 addException(e1); 390 } 391 } 392 393 private static String compilationPrefix() { 394 return "\\d\\) Compilation"; 395 } 396 397 private static void findIrIds(String output, String method, int... numbers) { 398 StringBuilder builder = new StringBuilder(); 399 builder.append(method); 400 for (int i = 0; i < numbers.length; i+=2) { 401 int start = numbers[i]; 402 int endIncluded = numbers[i + 1]; 403 for (int j = start; j <= endIncluded; j++) { 404 builder.append(","); 405 builder.append(j); 406 } 407 } 408 if (!output.contains(builder.toString())) { 409 addException(new RuntimeException("Could not find encoding: \"" + builder + System.lineSeparator())); 410 } 411 } 412 } 413 414 class AndOr1 { 415 @Test 416 @Arguments(Argument.DEFAULT) 417 @IR(applyIfAnd = {"UsePerfData", "true", "TLABRefillWasteFraction", "50", "UseTLAB", "true"}, failOn = {IRNode.CALL}) 418 public void test1(int i) { 419 dontInline(); 420 } 421 422 @Test 423 @IR(applyIfOr = {"UsePerfData", "false", "TLABRefillWasteFraction", "51", "UseTLAB", "false"}, failOn = {IRNode.CALL}) 424 public void test2() { 425 dontInline(); 426 } 427 428 @DontInline 429 private void dontInline() { 430 } 431 } 432 433 class MultipleFailOnGood { 434 private int iFld; 435 private MyClassSub myClassSub = new MyClassSub(); 436 437 @Test 438 @IR(applyIf = {"TLABRefillWasteFraction", "50"}, failOn = {IRNode.STORE, IRNode.CALL}) 439 @IR(failOn = {IRNode.STORE, IRNode.CALL}) 440 @IR(applyIfOr = {"TLABRefillWasteFraction", "99", "TLABRefillWasteFraction", "100"}, failOn = {IRNode.LOOP, IRNode.CALL}) // Not applied 441 public void good1() { 442 forceInline(); 443 } 444 445 @Test 446 @IR(failOn = {IRNode.STORE, IRNode.CALL}) 447 @IR(applyIfNot = {"TLABRefillWasteFraction", "20"}, failOn = {IRNode.ALLOC}) 448 @IR(applyIfNot = {"TLABRefillWasteFraction", "< 100"}, failOn = {IRNode.ALLOC_OF, "Test"}) 449 public void good2() { 450 forceInline(); 451 } 452 453 @Test 454 @IR(failOn = {IRNode.STORE_OF_CLASS, "Test", IRNode.CALL}) 455 @IR(applyIfNot = {"TLABRefillWasteFraction", "20"}, failOn = {IRNode.ALLOC}) 456 @IR(applyIfNot = {"TLABRefillWasteFraction", "< 100"}, failOn = {IRNode.ALLOC_OF, "Test"}) 457 public void good3() { 458 forceInline(); 459 } 460 461 @Test 462 @IR(failOn = {IRNode.CALL, IRNode.STORE_OF_CLASS, "UnknownClass"}) 463 public void good4() { 464 iFld = 42; 465 } 466 467 @Test 468 @IR(failOn = {IRNode.STORE_OF_FIELD, "xFld", IRNode.CALL}) 469 public void good5() { 470 iFld = 42; 471 } 472 473 @Test 474 @IR(failOn = {IRNode.STORE_OF_CLASS, "MyClass"}) // Needs exact match to fail 475 public void good6() { 476 myClassSub.iFld = 42; 477 } 478 479 @Test 480 @IR(failOn = {IRNode.STORE_OF_CLASS, "MyClassSub"}) // Static write is with Class and not MySubClass 481 public void good7() { 482 MyClassSub.iFldStatic = 42; 483 } 484 485 @ForceInline 486 private void forceInline() {} 487 } 488 489 class MultipleFailOnBad { 490 private int iFld; 491 private int myInt; 492 private MyClassEmpty myClass; 493 494 @Test 495 @IR(failOn = {IRNode.STORE, IRNode.CALL, IRNode.STORE_I, IRNode.LOOP}) 496 public void fail1() { 497 iFld = 42; 498 } 499 500 @Test 501 @IR(failOn = {IRNode.STORE, IRNode.CALL}) 502 public void fail2() { 503 dontInline(); 504 } 505 506 @Test 507 @IR(failOn = {IRNode.CALL, IRNode.STORE_OF_CLASS, "MultipleFailOnBad", IRNode.ALLOC}) 508 public void fail3() { 509 iFld = 42; 510 } 511 512 @Test 513 @IR(failOn = {IRNode.STORE_OF_CLASS, "ir_framework/tests/MultipleFailOnBad", IRNode.CALL, IRNode.ALLOC}) 514 public void fail4() { 515 iFld = 42; 516 } 517 518 @Test 519 @IR(failOn = {IRNode.STORE_OF_FIELD, "iFld", IRNode.CALL, IRNode.ALLOC}) 520 public void fail5() { 521 iFld = 42; 522 } 523 524 @Test 525 @IR(failOn = {IRNode.STORE_OF_CLASS, "MyClassEmpty", IRNode.ALLOC, IRNode.CALL}) 526 public void fail6() { 527 myClass = new MyClassEmpty(); 528 } 529 530 @Test 531 @IR(failOn = {IRNode.STORE_OF_CLASS, "UnknownClass", IRNode.ALLOC_OF, "MyClassEmpty"}) 532 public void fail7() { 533 myClass = new MyClassEmpty(); 534 } 535 536 @Test 537 @IR(failOn = {IRNode.STORE_OF_CLASS, "UnknownClass", IRNode.ALLOC_OF, "ir_framework/tests/MyClassEmptySub"}) 538 public void fail8() { 539 myClass = new MyClassEmptySub(); 540 } 541 542 @Test 543 @IR(failOn = {IRNode.STORE, IRNode.CALL}) 544 public void fail9() { 545 iFld = 42; 546 dontInline(); 547 } 548 549 @Test 550 @IR(failOn = {IRNode.STORE_OF_FIELD, "iFld", IRNode.CALL, IRNode.ALLOC}) 551 public void fail10() { 552 myInt = 34; 553 iFld = 42; 554 } 555 556 @DontInline 557 private void dontInline() {} 558 } 559 560 // Called with -XX:TLABRefillWasteFraction=X. 561 class FlagComparisons { 562 // Applies all IR rules if TLABRefillWasteFraction=50 563 @Test 564 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "50"}) // Index 1 565 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=50"}) 566 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 50"}) 567 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " = 50"}) 568 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=50"}) // Index 5 569 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<= 50"}) 570 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <= 50"}) 571 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=50"}) // Index 8 572 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">= 50"}) 573 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >= 50"}) 574 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">49"}) 575 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "> 49"}) 576 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " > 49"}) 577 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<51"}) // Index 14 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", " != 51"}) 583 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!=49"}) 584 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "!= 49"}) 585 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 49"}) // Index 22 586 public void testMatchAllIf50() {} 587 588 // Applies no IR rules if TLABRefillWasteFraction=50 589 @Test 590 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "49"}) // Index 1 591 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=49"}) 592 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 49"}) 593 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " = 49"}) 594 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "51"}) // Index 5 595 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "=51"}) 596 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "= 51"}) 597 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " = 51"}) 598 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<=49"}) // Index 9 599 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<= 49"}) 600 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " <= 49"}) 601 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">=51"}) // Index 12 602 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">= 51"}) 603 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " >= 51"}) 604 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", ">50"}) 605 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "> 50"}) 606 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " > 50"}) 607 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", "<50"}) // Index 18 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"}) 612 @IR(failOn = IRNode.CALL, applyIf = {"TLABRefillWasteFraction", " != 50"}) // Index 23 613 public void testMatchNoneIf50() {} 614 } 615 616 class CountComparisons { 617 int iFld; 618 619 @Test 620 @IR(counts = {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, " <= 1", 632 IRNode.STORE, "!= 0", 633 IRNode.STORE, "!=0", 634 IRNode.STORE, " != 0", 635 IRNode.STORE, " != 0", 636 IRNode.STORE, "> 0", 637 IRNode.STORE, ">0", 638 IRNode.STORE, " > 0", 639 IRNode.STORE, " > 0", 640 IRNode.STORE, "< 2", 641 IRNode.STORE, "<2", 642 IRNode.STORE, " < 2", 643 IRNode.STORE, " < 2", 644 }) 645 public void countComparison() { 646 iFld = 3; 647 } 648 } 649 650 class GoodCount { 651 boolean flag; 652 char cFld; 653 byte bFld; 654 short sFld; 655 int iFld; 656 long lFld; 657 float fFld; 658 double dFld; 659 long x; 660 661 long result; 662 MyClass myClass = new MyClass(); 663 MyClassEmpty myClassEmpty = new MyClassEmpty(); 664 MyClass myClassSubPoly = new MyClassSub(); 665 MyClassSub myClassSub = new MyClassSub(); 666 667 @Test 668 @IR(counts = {IRNode.STORE, "1", IRNode.STORE_I, "1"}, 669 failOn = {IRNode.STORE_B, IRNode.STORE_C, IRNode.STORE_D, 670 IRNode.STORE_F, IRNode.STORE_L}) 671 public void good1() { 672 iFld = 3; 673 } 674 675 @Test 676 @IR(counts = {IRNode.STORE, "8", 677 IRNode.STORE_B, "2", // bFld + flag 678 IRNode.STORE_C, "2", // cFld + sFld 679 IRNode.STORE_I, "1", 680 IRNode.STORE_L, "1", 681 IRNode.STORE_F, "1", 682 IRNode.STORE_D, "1"}) 683 public void good2() { 684 flag = true; 685 cFld = 'a'; 686 bFld = 1; 687 sFld = 2; 688 iFld = 3; 689 lFld = 4L; 690 fFld = 5.0f; 691 dFld = 6.0; 692 } 693 694 @Test 695 @IR(counts = {IRNode.STORE, "8", IRNode.STORE_OF_CLASS, "GoodCount", "8", 696 IRNode.STORE_B, "2", IRNode.STORE_B_OF_CLASS, "GoodCount", "2", 697 IRNode.STORE_C, "2", IRNode.STORE_C_OF_CLASS, "GoodCount", "2", 698 IRNode.STORE_I, "1", IRNode.STORE_I_OF_CLASS, "GoodCount", "1", 699 IRNode.STORE_L, "1", IRNode.STORE_L_OF_CLASS, "GoodCount", "1", 700 IRNode.STORE_F, "1", IRNode.STORE_F_OF_CLASS, "GoodCount", "1", 701 IRNode.STORE_D, "1", IRNode.STORE_D_OF_CLASS, "GoodCount", "1"}) 702 public void good3() { 703 flag = true; 704 cFld = 'a'; 705 bFld = 1; 706 sFld = 2; 707 iFld = 3; 708 lFld = 4L; 709 fFld = 5.0f; 710 dFld = 6.0; 711 } 712 713 @Test 714 @IR(counts = {IRNode.STORE, "8", IRNode.STORE_OF_CLASS, "GoodCount", "8", 715 IRNode.STORE_B, "2", IRNode.STORE_B_OF_CLASS, "GoodCount", "2", 716 IRNode.STORE_C, "2", IRNode.STORE_C_OF_CLASS, "GoodCount", "2", 717 IRNode.STORE_I, "1", IRNode.STORE_I_OF_CLASS, "GoodCount", "1", 718 IRNode.STORE_L, "1", IRNode.STORE_L_OF_CLASS, "GoodCount", "1", 719 IRNode.STORE_F, "1", IRNode.STORE_F_OF_CLASS, "GoodCount", "1", 720 IRNode.STORE_D, "1", IRNode.STORE_D_OF_CLASS, "GoodCount", "1", 721 IRNode.STORE_OF_FIELD, "lFld", "1"}) 722 public void good4() { 723 flag = true; 724 cFld = 'a'; 725 bFld = 1; 726 sFld = 2; 727 iFld = 3; 728 lFld = 4L; 729 fFld = 5.0f; 730 dFld = 6.0; 731 } 732 733 @Test 734 @IR(counts = {IRNode.STORE, "2", IRNode.STORE_I, "1", IRNode.STORE_L, "1", 735 IRNode.STORE_OF_CLASS, "GoodCount", "1", IRNode.STORE_L_OF_CLASS, "GoodCount", "1", 736 IRNode.STORE_OF_CLASS, "ir_framework/tests/MyClass", "1", 737 IRNode.STORE_I_OF_CLASS, "ir_framework/tests/MyClass", "1", 738 IRNode.STORE_OF_CLASS, "ir_framework/tests/GoodCount", "1", 739 IRNode.STORE_L_OF_CLASS, "ir_framework/tests/GoodCount", "1", 740 IRNode.STORE_OF_FIELD, "x", "2"}) 741 public void good5() { 742 x = 3; // long 743 myClass.x = 4; // int 744 } 745 746 @Test 747 @IR(counts = {IRNode.STORE_OF_FIELD, "myClassEmpty", "1", IRNode.STORE_OF_CLASS, "GoodCount", "1", 748 IRNode.STORE_OF_CLASS, "/GoodCount", "1", IRNode.STORE_OF_CLASS, "MyClassEmpty", "0"}, 749 failOn = {IRNode.STORE_OF_CLASS, "MyClassEmpty"}) 750 public void good6() { 751 myClassEmpty = new MyClassEmpty(); 752 } 753 754 @Test 755 @IR(counts = {IRNode.STORE_OF_FIELD, "iFld", "3", IRNode.STORE_OF_CLASS, "GoodCount", "0", 756 IRNode.STORE_OF_CLASS, "MyClass", "2", IRNode.STORE_OF_CLASS, "MyClassSub", "1", 757 IRNode.STORE, "3"}, 758 failOn = {IRNode.STORE_OF_CLASS, "GoodCount"}) 759 public void good7() { 760 myClass.iFld = 1; 761 myClassSubPoly.iFld = 2; 762 myClassSub.iFld = 3; 763 } 764 765 @Test 766 @IR(counts = {IRNode.LOAD, "1", IRNode.STORE, "1"}) 767 public void good8() { 768 result = iFld; 769 } 770 771 772 @Test 773 @IR(counts = {IRNode.LOAD, "4", IRNode.STORE, "1", IRNode.LOAD_OF_FIELD, "iFld", "2", IRNode.LOAD_OF_FIELD, "iFld2", "0", 774 IRNode.LOAD_OF_FIELD, "lFldStatic", "1", IRNode.LOAD_OF_CLASS, "GoodCount", "2", IRNode.LOAD_OF_CLASS, "MyClass", "1", 775 IRNode.STORE_OF_CLASS, "GoodCount", "1", IRNode.STORE_OF_FIELD, "result", "1", 776 IRNode.LOAD_OF_FIELD, "myClass", "1"}) 777 public void good9() { 778 result = iFld + MyClass.lFldStatic + myClass.iFld; // 1 + 1 + 2 loads (myClass is LoadN of GoodCount and myClass.iFld a LoadI of MyClass) 779 } 780 781 @Test 782 @IR(counts = {IRNode.LOAD, "8", 783 IRNode.LOAD_B, "1", 784 IRNode.LOAD_UB, "1", 785 IRNode.LOAD_S, "1", 786 IRNode.LOAD_US, "1", 787 IRNode.LOAD_I, "1", 788 IRNode.LOAD_L, "1", 789 IRNode.LOAD_F, "1", 790 IRNode.LOAD_D, "1"}) 791 public void good10() { 792 bFld++; 793 cFld++; 794 sFld++; 795 iFld++; 796 lFld++; 797 fFld++; 798 dFld++; 799 flag = !flag; 800 } 801 802 @Test 803 @IR(counts = {IRNode.LOAD, "8", IRNode.LOAD_OF_CLASS, "GoodCount", "8", 804 IRNode.LOAD_B, "1", IRNode.LOAD_B_OF_CLASS, "GoodCount", "1", 805 IRNode.LOAD_UB, "1", IRNode.LOAD_UB_OF_CLASS, "GoodCount", "1", 806 IRNode.LOAD_S, "1", IRNode.LOAD_S_OF_CLASS, "GoodCount", "1", 807 IRNode.LOAD_US, "1", IRNode.LOAD_US_OF_CLASS, "GoodCount", "1", 808 IRNode.LOAD_I, "1", IRNode.LOAD_I_OF_CLASS, "GoodCount", "1", 809 IRNode.LOAD_L, "1", IRNode.LOAD_L_OF_CLASS, "GoodCount", "1", 810 IRNode.LOAD_F, "1", IRNode.LOAD_F_OF_CLASS, "GoodCount", "1", 811 IRNode.LOAD_D, "1", IRNode.LOAD_D_OF_CLASS, "GoodCount", "1"}) 812 public void good11() { 813 bFld++; 814 cFld++; 815 sFld++; 816 iFld++; 817 lFld++; 818 fFld++; 819 dFld++; 820 flag = !flag; 821 } 822 } 823 824 class BadCount { 825 int iFld; 826 int result; 827 @Test 828 @IR(counts = {IRNode.LOAD, "!= 1"}) // fail 829 @IR(counts = {IRNode.STORE, "> 0"}) 830 public void bad1() { 831 result = iFld; 832 } 833 834 @Test 835 @IR(counts = {IRNode.LOAD, "1"}) // fail 836 @IR(counts = {IRNode.STORE, "< 1"}) 837 public void bad2() { 838 result = iFld; 839 } 840 841 842 @Test 843 @IR(counts = {IRNode.LOAD, "0"}) // fail 844 @IR(counts = {IRNode.STORE, " <= 0"}) // fail 845 public void bad3() { 846 result = iFld; 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 }