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