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