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