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