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