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