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