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