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