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 // TODO add bugid and summary
25
26 /*
27 * @test
28 * @library /testlibrary /test/lib /compiler/whitebox /
29 * @build compiler.valhalla.valuetypes.ValueTypeTestBench
30 * @run main ClassFileInstaller sun.hotspot.WhiteBox
31 * @run main ClassFileInstaller jdk.test.lib.Platform
32 * @run main/othervm -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
33 * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
34 */
35
36 package compiler.valhalla.valuetypes;
37
38 import compiler.whitebox.CompilerWhiteBoxTest;
39 import jdk.internal.misc.Unsafe;
40 import jdk.test.lib.Asserts;
41 import jdk.test.lib.Platform;
42 import jdk.test.lib.ProcessTools;
43 import jdk.test.lib.OutputAnalyzer;
44 import jdk.test.lib.Utils;
45 import sun.hotspot.WhiteBox;
46
47 import java.lang.annotation.Retention;
48 import java.lang.annotation.RetentionPolicy;
49 import java.lang.reflect.Method;
50 import java.util.ArrayList;
51 import java.util.Hashtable;
52 import java.util.regex.Matcher;
53 import java.util.regex.Pattern;
54
55 // Test value types
56 __ByValue final class MyValue1 {
57 static int s;
58 static final long sf = ValueTypeTestBench.rL;
59 final int x;
60 final long y;
61 final MyValue2 v1;
62 final MyValue2 v2;
63 static final MyValue2 v3 = MyValue2.createInline(ValueTypeTestBench.rI, true);
64 final int c;
65
66 private MyValue1(int x, long y, MyValue2 v1, MyValue2 v2, int c) {
67 s = x;
68 this.x = x;
69 this.y = y;
70 this.v1 = v1;
71 this.v2 = v2;
72 this.c = c;
73 }
74
75 @DontInline
76 public static MyValue1 createDontInline(int x, long y) {
77 return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
78 }
79
80 @ForceInline
81 public static MyValue1 createInline(int x, long y) {
82 return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
83 }
84
85 @ForceInline
86 public long hash() {
87 return s + sf + x + y + c + v1.hash() + v2.hash() + v3.hash();
88 }
89
90 @DontCompile
91 public long hashInterpreted() {
92 return s + sf + x + y + c + v1.hash() + v2.hash() + v3.hash();
93 }
94 }
95
96 __ByValue final class MyValue2 {
97 final int x;
98 final boolean b;
99 final long c;
100
101 private MyValue2(int x, boolean b, long c) {
102 this.x = x;
103 this.b = b;
104 this.c = c;
105 }
106
107 @ForceInline
108 public static MyValue2 createInline(int x, boolean b) {
109 return __Make MyValue2(x, b, ValueTypeTestBench.rL);
110 }
111
112 @ForceInline
113 public long hash() {
114 return x + (b ? 0 : 1) + c;
115 }
116 }
117
118 public class ValueTypeTestBench {
119 // Print ideal graph after execution of each test
120 private static final boolean PRINT_GRAPH = true;
121
122 // Random test values
123 public static final int rI = Utils.getRandomInstance().nextInt() % 1000;
124 public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
125
126 public ValueTypeTestBench() {
127 val3 = MyValue1.createInline(rI, rL);
128 }
129
130 // ========== Helper methods ==========
131
132 public long hash() {
133 return hash(rI, rL);
134 }
135
149 @DontCompile
150 public void test1_verifier(boolean warmup) {
151 long result = test1();
152 Asserts.assertEQ(result, hash());
153 }
154
155 // Receive value type from interpreter via parameter
156 @Test(failOn = ALLOC + STORE + TRAP)
157 public long test2(MyValue1 v) {
158 return v.hash();
159 }
160
161 @DontCompile
162 public void test2_verifier(boolean warmup) {
163 MyValue1 v = MyValue1.createDontInline(rI, rL);
164 long result = test2(v);
165 Asserts.assertEQ(result, hash());
166 }
167
168 // Return incoming value type without accessing fields
169 @Test(failOn = ALLOC + LOAD + STORE + TRAP)
170 public MyValue1 test3(MyValue1 v) {
171 return v;
172 }
173
174 @DontCompile
175 public void test3_verifier(boolean warmup) {
176 MyValue1 v1 = MyValue1.createDontInline(rI, rL);
177 MyValue1 v2 = test3(v1);
178 Asserts.assertEQ(v1.x, v2.x);
179 Asserts.assertEQ(v1.y, v2.y);
180 }
181
182 // Create a value type in compiled code and only use fields.
183 // Allocation should go away because value type does not escape.
184 @Test(failOn = ALLOC + LOAD + STORE + TRAP)
185 public long test4() {
186 MyValue1 v = MyValue1.createInline(rI, rL);
187 return v.hash();
188 }
189
197 // an inlined compiled method via a call.
198 @Test(failOn = ALLOC + LOAD + STORE + TRAP)
199 public long test5() {
200 MyValue1 v = MyValue1.createInline(rI, rL);
201 return test5Inline(v);
202 }
203
204 @ForceInline
205 public long test5Inline(MyValue1 v) {
206 return v.hash();
207 }
208
209 @DontCompile
210 public void test5_verifier(boolean warmup) {
211 long result = test5();
212 Asserts.assertEQ(result, hash());
213 }
214
215 // Create a value type in compiled code and pass it to
216 // the interpreter via a call.
217 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
218 public long test6() {
219 MyValue1 v = MyValue1.createInline(rI, rL);
220 // Pass to interpreter
221 return v.hashInterpreted();
222 }
223
224 @DontCompile
225 public void test6_verifier(boolean warmup) {
226 long result = test6();
227 Asserts.assertEQ(result, hash());
228 }
229
230 // Create a value type in compiled code and pass it to
231 // the interpreter by returning.
232 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
233 public MyValue1 test7(int x, long y) {
234 return MyValue1.createInline(x, y);
235 }
236
237 @DontCompile
242
243 // Merge value types created from two branches
244 @Test(failOn = ALLOC + STORE + TRAP)
245 public long test8(boolean b) {
246 MyValue1 v;
247 if (b) {
248 v = MyValue1.createInline(rI, rL);
249 } else {
250 v = MyValue1.createDontInline(rI + 1, rL + 1);
251 }
252 return v.hash();
253 }
254
255 @DontCompile
256 public void test8_verifier(boolean warmup) {
257 Asserts.assertEQ(test8(true), hash());
258 Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
259 }
260
261 // Merge value types created from two branches
262 @Test(match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)
263 public MyValue1 test9(boolean b) {
264 MyValue1 v;
265 if (b) {
266 // Value type is not allocated
267 v = MyValue1.createInline(rI, rL);
268 } else {
269 // Value type is allocated by the callee
270 v = MyValue1.createDontInline(rI + 1, rL + 1);
271 }
272 // Need to allocate value type if 'b' is true
273 long sum = v.hashInterpreted();
274 if (b) {
275 v = MyValue1.createDontInline(rI, sum);
276 } else {
277 v = MyValue1.createDontInline(rI, sum + 1);
278 }
279 // Don't need to allocate value type because both branches allocate
280 return v;
281 }
282
353 for (int i = 0; i < 1000; ++i) {
354 if (b) {
355 result += v.x;
356 } else {
357 // Uncommon trap referencing v. Should not allocate
358 // but just pass the existing oop to the uncommon trap.
359 result = v.hashInterpreted();
360 }
361 }
362 return result;
363 }
364
365 @DontCompile
366 public void test13_verifier(boolean warmup) {
367 long result = test13(warmup);
368 Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash());
369 }
370
371 // Create a value type in a non-inlined method and then call a
372 // non-inlined method on that value type.
373 @Test(failOn = (ALLOC + LOAD + STORE + TRAP))
374 public long test14() {
375 MyValue1 v = MyValue1.createDontInline(rI, rL);
376 return v.hashInterpreted();
377 }
378
379 @DontCompile
380 public void test14_verifier(boolean b) {
381 long result = test14();
382 Asserts.assertEQ(result, hash());
383 }
384
385 // Create a value type in an inlined method and then call a
386 // non-inlined method on that value type.
387 @Test(failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1})
388 public long test15() {
389 MyValue1 v = MyValue1.createInline(rI, rL);
390 return v.hashInterpreted();
391 }
392
393 @DontCompile
394 public void test15_verifier(boolean b) {
395 long result = test15();
396 Asserts.assertEQ(result, hash());
397 }
398
399 // Create a value type in a non-inlined method and then call an
400 // inlined method on that value type.
401 @Test(failOn = (ALLOC + STORE + TRAP))
402 public long test16() {
403 MyValue1 v = MyValue1.createDontInline(rI, rL);
404 return v.hash();
405 }
406
407 @DontCompile
410 Asserts.assertEQ(result, hash());
411 }
412
413 // Create a value type in an inlined method and then call an
414 // inlined method on that value type.
415 @Test(failOn = (ALLOC + LOAD + STORE + TRAP))
416 public long test17() {
417 MyValue1 v = MyValue1.createInline(rI, rL);
418 return v.hash();
419 }
420
421 @DontCompile
422 public void test17_verifier(boolean b) {
423 long result = test17();
424 Asserts.assertEQ(result, hash());
425 }
426
427 // Create a value type in compiled code and pass it to the
428 // interpreter via a call. The value is live at the first call so
429 // debug info should include a reference to all its fields.
430 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
431 public long test18() {
432 MyValue1 v = MyValue1.createInline(rI, rL);
433 v.hashInterpreted();
434 return v.hashInterpreted();
435 }
436
437 @DontCompile
438 public void test18_verifier(boolean warmup) {
439 long result = test18();
440 Asserts.assertEQ(result, hash());
441 }
442
443 // Create a value type in compiled code and pass it to the
444 // interpreter via a call. The value type is passed twice but
445 // should only be allocated once.
446 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
447 public long test19() {
448 MyValue1 v = MyValue1.createInline(rI, rL);
449 return sumValue(v, v);
450 }
451
452 @DontCompile
453 public long sumValue(MyValue1 v, MyValue1 dummy) {
454 return v.hash();
455 }
456
457 @DontCompile
458 public void test19_verifier(boolean warmup) {
459 long result = test19();
460 Asserts.assertEQ(result, hash());
461 }
462
463 // Create a value type in compiled code and pass it to the
464 // interpreter via a call. The value type is live at the uncommon
465 // trap: verify that deoptimization causes the value type to be
466 // correctly allocated.
467 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD)
468 public long test20(boolean flag) {
469 MyValue1 v = MyValue1.createInline(rI, rL);
470 if (flag) {
471 // uncommon trap
472 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test16"));
473 }
474 return v.hashInterpreted();
475 }
476
477 @DontCompile
478 public void test20_verifier(boolean warmup) {
479 long result = test20(false);
480 Asserts.assertEQ(result, hash());
481 if (!warmup) {
482 result = test20(true);
483 Asserts.assertEQ(result, hash());
484 }
485 }
486
487 // Value type fields in regular object
488 MyValue1 val1;
489 MyValue2 val2;
490 final MyValue1 val3;
491 static MyValue1 val4;
492 static final MyValue1 val5 = MyValue1.createInline(rI, rL);
535
536 // Test OSR compilation
537 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
538 public long test23() {
539 MyValue1 v = MyValue1.createInline(rI, rL);
540 long result = 0;
541 // Long loop to trigger OSR compilation
542 for (int i = 0 ; i < 100_000 ; ++i) {
543 // Reference local value type in interpreter state
544 result = v.hash();
545 }
546 return result;
547 }
548
549 @DontCompile
550 public void test23_verifier(boolean warmup) {
551 long result = test23();
552 Asserts.assertEQ(result, hash());
553 }
554
555
556 // ========== Test infrastructure ==========
557
558 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
559 private static final int COMP_LEVEL_ANY = -1;
560 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
561 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
562 private static final int WARMUP = 10;
563 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
564 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
565 // TODO use Platform.isComp() after merge with JDK 9
566 private static boolean XCOMP = System.getProperty("java.vm.info").startsWith("compiled ");
567
568 // Regular expressions used to match nodes in the PrintIdeal output
569 private static final String START = "(\\d+\\t(.*";
570 private static final String MID = ".*)+\\t===.*";
571 private static final String END = ")|";
572 private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
573 private static final String LOAD = START + "Load" + MID + "valuetype\\*" + END;
574 private static final String STORE = START + "Store" + MID + "valuetype\\*" + END;
575 private static final String LOOP = START + "Loop" + MID + "" + END;
576 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap" + END;
577 // TODO: match field values of scalar replaced object
578 private static final String SCOBJ = "(.*# ScObj.*" + END;
579
580 static {
581 // Gather all test methods and put them in Hashtable
582 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
583 if (m.isAnnotationPresent(Test.class)) {
584 tests.put("ValueTypeTestBench::" + m.getName(), m);
585 }
586 }
587 }
588
589 public static void main(String[] args) throws Throwable {
590 if (args.length == 0) {
591 // Run tests in own process and verify output
592 OutputAnalyzer oa = ProcessTools.executeTestJvm("-noverify",
593 "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI",
594 "-XX:-TieredCompilation", "-XX:-BackgroundCompilation",
595 "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
596 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
597 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
598 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*",
599 ValueTypeTestBench.class.getName(), "run");
600 // If ideal graph printing is enabled/supported, verify output
601 String output = oa.getOutput();
602 oa.shouldHaveExitValue(0);
603 if (output.contains("PrintIdeal enabled")) {
604 parseOutput(output);
605 } else {
606 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
607 }
608 } else {
609 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
610 System.out.println("PrintIdeal enabled");
611 }
612 // Execute tests
613 ValueTypeTestBench bench = new ValueTypeTestBench();
614 bench.run();
615 }
616 }
617
618 public static void parseOutput(String output) throws Exception {
619 String split = "b compiler.valhalla.valuetypes.";
620 String[] compilations = output.split(split);
621 // Print header
622 System.out.println(compilations[0]);
623 // Iterate over compilation output
624 for (String graph : compilations) {
625 String[] lines = graph.split("\\n");
626 if (lines[0].contains("@")) {
627 continue; // Ignore OSR compilations
628 }
629 String testName = lines[0].split(" ")[0];
630 Method test = tests.get(testName);
631 if (test == null) {
632 // Skip helper methods
633 continue;
634 }
635 if (PRINT_GRAPH) {
636 System.out.println("\nGraph for " + graph);
637 }
638 // Parse graph using regular expressions to determine if it contains forbidden nodes
639 Test anno = test.getAnnotation(Test.class);
640 String regexFail = anno.failOn();
641 if (!regexFail.isEmpty()) {
642 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
643 Matcher matcher = pattern.matcher(graph);
644 boolean fail = false;
645 while (matcher.find()) {
646 System.out.println("Graph for '" + testName + "' contains forbidden node:");
647 System.out.println(matcher.group());
648 fail = true;
649 }
650 Asserts.assertFalse(fail, "Graph for '" + testName + "' contains forbidden nodes");
651 }
652 String[] regexMatch = anno.match();
653 int[] matchCount = anno.matchCount();
654 for (int i = 0; i < regexMatch.length; ++i) {
655 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
656 Matcher matcher = pattern.matcher(graph);
657 int count = 0;
658 String nodes = "";
659 while (matcher.find()) {
706 //WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION);
707
708 // Execute tests
709 for (Method test : tests.values()) {
710 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class);
711 // Warmup using verifier method
712 for (int i = 0; i < WARMUP; ++i) {
713 verifier.invoke(this, true);
714 }
715 // Trigger compilation
716 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION);
717 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
718 // Check result
719 verifier.invoke(this, false);
720 }
721 }
722 }
723
724 // Mark method as test
725 @Retention(RetentionPolicy.RUNTIME)
726 @interface Test {
727 // Regular expression used to match forbidden IR nodes
728 // in the C2 IR emitted for this test.
729 String failOn() default "";
730 // Regular expressions used to match and count IR nodes.
731 String[] match() default { };
732 int[] matchCount() default { };
733 }
734
735 // Force method inlining during compilation
736 @Retention(RetentionPolicy.RUNTIME)
737 @interface ForceInline { }
738
739 // Prevent method inlining during compilation
740 @Retention(RetentionPolicy.RUNTIME)
741 @interface DontInline { }
742
743 // Prevent method compilation
744 @Retention(RetentionPolicy.RUNTIME)
745 @interface DontCompile { }
|
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 // TODO add bugid and summary
25
26 /*
27 * @test
28 * @library /testlibrary /test/lib /compiler/whitebox /
29 * @build compiler.valhalla.valuetypes.ValueTypeTestBench
30 * @run main ClassFileInstaller sun.hotspot.WhiteBox
31 * @run main ClassFileInstaller jdk.test.lib.Platform
32 * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
33 * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
34 * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
35 * -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs
36 * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
37 */
38
39 package compiler.valhalla.valuetypes;
40
41 import compiler.whitebox.CompilerWhiteBoxTest;
42 import jdk.internal.misc.Unsafe;
43 import jdk.test.lib.Asserts;
44 import jdk.test.lib.Platform;
45 import jdk.test.lib.ProcessTools;
46 import jdk.test.lib.OutputAnalyzer;
47 import jdk.test.lib.Utils;
48 import sun.hotspot.WhiteBox;
49
50 import java.lang.annotation.Retention;
51 import java.lang.annotation.RetentionPolicy;
52 import java.lang.annotation.Repeatable;
53 import java.lang.reflect.Method;
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.Hashtable;
57 import java.util.List;
58 import java.util.regex.Matcher;
59 import java.util.regex.Pattern;
60
61 // Test value types
62 __ByValue final class MyValue1 {
63 static int s;
64 static final long sf = ValueTypeTestBench.rL;
65 final int x;
66 final long y;
67 final MyValue2 v1;
68 final MyValue2 v2;
69 static final MyValue2 v3 = MyValue2.createInline(ValueTypeTestBench.rI, true);
70 final int c;
71
72 private MyValue1(int x, long y, MyValue2 v1, MyValue2 v2, int c) {
73 s = x;
74 this.x = x;
75 this.y = y;
76 this.v1 = v1;
77 this.v2 = v2;
78 this.c = c;
79 }
80
81 @DontInline
82 public static MyValue1 createDontInline(int x, long y) {
83 return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
84 }
85
86 @ForceInline
87 public static MyValue1 createInline(int x, long y) {
88 return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
89 }
90
91 @ForceInline
92 public long hash() {
93 return s + sf + x + y + c + v1.hash() + v2.hash() + v3.hash();
94 }
95
96 @DontCompile
97 public long hashInterpreted() {
98 return s + sf + x + y + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted();
99 }
100 }
101
102 __ByValue final class MyValue2 {
103 final int x;
104 final boolean b;
105 final long c;
106
107 private MyValue2(int x, boolean b, long c) {
108 this.x = x;
109 this.b = b;
110 this.c = c;
111 }
112
113 @ForceInline
114 public static MyValue2 createInline(int x, boolean b) {
115 return __Make MyValue2(x, b, ValueTypeTestBench.rL);
116 }
117
118 @ForceInline
119 public long hash() {
120 return x + (b ? 0 : 1) + c;
121 }
122
123 @DontInline
124 public long hashInterpreted() {
125 return x + (b ? 0 : 1) + c;
126 }
127 }
128
129 public class ValueTypeTestBench {
130 // Print ideal graph after execution of each test
131 private static final boolean PRINT_GRAPH = true;
132
133 // Random test values
134 public static final int rI = Utils.getRandomInstance().nextInt() % 1000;
135 public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
136
137 public ValueTypeTestBench() {
138 val3 = MyValue1.createInline(rI, rL);
139 }
140
141 // ========== Helper methods ==========
142
143 public long hash() {
144 return hash(rI, rL);
145 }
146
160 @DontCompile
161 public void test1_verifier(boolean warmup) {
162 long result = test1();
163 Asserts.assertEQ(result, hash());
164 }
165
166 // Receive value type from interpreter via parameter
167 @Test(failOn = ALLOC + STORE + TRAP)
168 public long test2(MyValue1 v) {
169 return v.hash();
170 }
171
172 @DontCompile
173 public void test2_verifier(boolean warmup) {
174 MyValue1 v = MyValue1.createDontInline(rI, rL);
175 long result = test2(v);
176 Asserts.assertEQ(result, hash());
177 }
178
179 // Return incoming value type without accessing fields
180 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)
181 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + LOAD + STORE + TRAP)
182 public MyValue1 test3(MyValue1 v) {
183 return v;
184 }
185
186 @DontCompile
187 public void test3_verifier(boolean warmup) {
188 MyValue1 v1 = MyValue1.createDontInline(rI, rL);
189 MyValue1 v2 = test3(v1);
190 Asserts.assertEQ(v1.x, v2.x);
191 Asserts.assertEQ(v1.y, v2.y);
192 }
193
194 // Create a value type in compiled code and only use fields.
195 // Allocation should go away because value type does not escape.
196 @Test(failOn = ALLOC + LOAD + STORE + TRAP)
197 public long test4() {
198 MyValue1 v = MyValue1.createInline(rI, rL);
199 return v.hash();
200 }
201
209 // an inlined compiled method via a call.
210 @Test(failOn = ALLOC + LOAD + STORE + TRAP)
211 public long test5() {
212 MyValue1 v = MyValue1.createInline(rI, rL);
213 return test5Inline(v);
214 }
215
216 @ForceInline
217 public long test5Inline(MyValue1 v) {
218 return v.hash();
219 }
220
221 @DontCompile
222 public void test5_verifier(boolean warmup) {
223 long result = test5();
224 Asserts.assertEQ(result, hash());
225 }
226
227 // Create a value type in compiled code and pass it to
228 // the interpreter via a call.
229 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC)
230 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
231 public long test6() {
232 MyValue1 v = MyValue1.createInline(rI, rL);
233 // Pass to interpreter
234 return v.hashInterpreted();
235 }
236
237 @DontCompile
238 public void test6_verifier(boolean warmup) {
239 long result = test6();
240 Asserts.assertEQ(result, hash());
241 }
242
243 // Create a value type in compiled code and pass it to
244 // the interpreter by returning.
245 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
246 public MyValue1 test7(int x, long y) {
247 return MyValue1.createInline(x, y);
248 }
249
250 @DontCompile
255
256 // Merge value types created from two branches
257 @Test(failOn = ALLOC + STORE + TRAP)
258 public long test8(boolean b) {
259 MyValue1 v;
260 if (b) {
261 v = MyValue1.createInline(rI, rL);
262 } else {
263 v = MyValue1.createDontInline(rI + 1, rL + 1);
264 }
265 return v.hash();
266 }
267
268 @DontCompile
269 public void test8_verifier(boolean warmup) {
270 Asserts.assertEQ(test8(true), hash());
271 Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
272 }
273
274 // Merge value types created from two branches
275 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {9}, failOn = TRAP + ALLOC + STORE)
276 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)
277 public MyValue1 test9(boolean b) {
278 MyValue1 v;
279 if (b) {
280 // Value type is not allocated
281 v = MyValue1.createInline(rI, rL);
282 } else {
283 // Value type is allocated by the callee
284 v = MyValue1.createDontInline(rI + 1, rL + 1);
285 }
286 // Need to allocate value type if 'b' is true
287 long sum = v.hashInterpreted();
288 if (b) {
289 v = MyValue1.createDontInline(rI, sum);
290 } else {
291 v = MyValue1.createDontInline(rI, sum + 1);
292 }
293 // Don't need to allocate value type because both branches allocate
294 return v;
295 }
296
367 for (int i = 0; i < 1000; ++i) {
368 if (b) {
369 result += v.x;
370 } else {
371 // Uncommon trap referencing v. Should not allocate
372 // but just pass the existing oop to the uncommon trap.
373 result = v.hashInterpreted();
374 }
375 }
376 return result;
377 }
378
379 @DontCompile
380 public void test13_verifier(boolean warmup) {
381 long result = test13(warmup);
382 Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash());
383 }
384
385 // Create a value type in a non-inlined method and then call a
386 // non-inlined method on that value type.
387 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {9})
388 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP))
389 public long test14() {
390 MyValue1 v = MyValue1.createDontInline(rI, rL);
391 return v.hashInterpreted();
392 }
393
394 @DontCompile
395 public void test14_verifier(boolean b) {
396 long result = test14();
397 Asserts.assertEQ(result, hash());
398 }
399
400 // Create a value type in an inlined method and then call a
401 // non-inlined method on that value type.
402 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC))
403 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1})
404 public long test15() {
405 MyValue1 v = MyValue1.createInline(rI, rL);
406 return v.hashInterpreted();
407 }
408
409 @DontCompile
410 public void test15_verifier(boolean b) {
411 long result = test15();
412 Asserts.assertEQ(result, hash());
413 }
414
415 // Create a value type in a non-inlined method and then call an
416 // inlined method on that value type.
417 @Test(failOn = (ALLOC + STORE + TRAP))
418 public long test16() {
419 MyValue1 v = MyValue1.createDontInline(rI, rL);
420 return v.hash();
421 }
422
423 @DontCompile
426 Asserts.assertEQ(result, hash());
427 }
428
429 // Create a value type in an inlined method and then call an
430 // inlined method on that value type.
431 @Test(failOn = (ALLOC + LOAD + STORE + TRAP))
432 public long test17() {
433 MyValue1 v = MyValue1.createInline(rI, rL);
434 return v.hash();
435 }
436
437 @DontCompile
438 public void test17_verifier(boolean b) {
439 long result = test17();
440 Asserts.assertEQ(result, hash());
441 }
442
443 // Create a value type in compiled code and pass it to the
444 // interpreter via a call. The value is live at the first call so
445 // debug info should include a reference to all its fields.
446 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
447 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
448 public long test18() {
449 MyValue1 v = MyValue1.createInline(rI, rL);
450 v.hashInterpreted();
451 return v.hashInterpreted();
452 }
453
454 @DontCompile
455 public void test18_verifier(boolean warmup) {
456 long result = test18();
457 Asserts.assertEQ(result, hash());
458 }
459
460 // Create a value type in compiled code and pass it to the
461 // interpreter via a call. The value type is passed twice but
462 // should only be allocated once.
463 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
464 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
465 public long test19() {
466 MyValue1 v = MyValue1.createInline(rI, rL);
467 return sumValue(v, v);
468 }
469
470 @DontCompile
471 public long sumValue(MyValue1 v, MyValue1 dummy) {
472 return v.hash();
473 }
474
475 @DontCompile
476 public void test19_verifier(boolean warmup) {
477 long result = test19();
478 Asserts.assertEQ(result, hash());
479 }
480
481 // Create a value type in compiled code and pass it to the
482 // interpreter via a call. The value type is live at the uncommon
483 // trap: verify that deoptimization causes the value type to be
484 // correctly allocated.
485 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE)
486 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD)
487 public long test20(boolean flag) {
488 MyValue1 v = MyValue1.createInline(rI, rL);
489 if (flag) {
490 // uncommon trap
491 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20"));
492 }
493 return v.hashInterpreted();
494 }
495
496 @DontCompile
497 public void test20_verifier(boolean warmup) {
498 long result = test20(false);
499 Asserts.assertEQ(result, hash());
500 if (!warmup) {
501 result = test20(true);
502 Asserts.assertEQ(result, hash());
503 }
504 }
505
506 // Value type fields in regular object
507 MyValue1 val1;
508 MyValue2 val2;
509 final MyValue1 val3;
510 static MyValue1 val4;
511 static final MyValue1 val5 = MyValue1.createInline(rI, rL);
554
555 // Test OSR compilation
556 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
557 public long test23() {
558 MyValue1 v = MyValue1.createInline(rI, rL);
559 long result = 0;
560 // Long loop to trigger OSR compilation
561 for (int i = 0 ; i < 100_000 ; ++i) {
562 // Reference local value type in interpreter state
563 result = v.hash();
564 }
565 return result;
566 }
567
568 @DontCompile
569 public void test23_verifier(boolean warmup) {
570 long result = test23();
571 Asserts.assertEQ(result, hash());
572 }
573
574 // Test interpreter to compiled code with various signatures
575 @Test(failOn = ALLOC + STORE + TRAP)
576 public long test24(MyValue2 v) {
577 return v.hash();
578 }
579
580 @DontCompile
581 public void test24_verifier(boolean warmup) {
582 MyValue2 v = MyValue2.createInline(rI, true);
583 long result = test24(v);
584 Asserts.assertEQ(result, v.hashInterpreted());
585 }
586
587 @Test(failOn = ALLOC + STORE + TRAP)
588 public long test25(int i1, MyValue2 v, int i2) {
589 return v.hash() + i1 - i2;
590 }
591
592 @DontCompile
593 public void test25_verifier(boolean warmup) {
594 MyValue2 v = MyValue2.createInline(rI, true);
595 long result = test25(rI, v, 2*rI);
596 Asserts.assertEQ(result, v.hashInterpreted() - rI);
597 }
598
599 @Test(failOn = ALLOC + STORE + TRAP)
600 public long test26(long l1, MyValue2 v, long l2) {
601 return v.hash() + l1 - l2;
602 }
603
604 @DontCompile
605 public void test26_verifier(boolean warmup) {
606 MyValue2 v = MyValue2.createInline(rI, true);
607 long result = test26(rL, v, 2*rL);
608 Asserts.assertEQ(result, v.hashInterpreted() - rL);
609 }
610
611 @Test(failOn = ALLOC + STORE + TRAP)
612 public long test27(int i, MyValue2 v, long l) {
613 return v.hash() + i + l;
614 }
615
616 @DontCompile
617 public void test27_verifier(boolean warmup) {
618 MyValue2 v = MyValue2.createInline(rI, true);
619 long result = test27(rI, v, rL);
620 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
621 }
622
623 @Test(failOn = ALLOC + STORE + TRAP)
624 public long test28(long l, MyValue2 v, int i) {
625 return v.hash() + i + l;
626 }
627
628 @DontCompile
629 public void test28_verifier(boolean warmup) {
630 MyValue2 v = MyValue2.createInline(rI, true);
631 long result = test28(rL, v, rI);
632 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
633 }
634
635 @Test(failOn = ALLOC + STORE + TRAP)
636 public long test29(long l, MyValue1 v1, int i, MyValue2 v2) {
637 return v1.hash() + i + l + v2.hash();
638 }
639
640 @DontCompile
641 public void test29_verifier(boolean warmup) {
642 MyValue1 v1 = MyValue1.createDontInline(rI, rL);
643 MyValue2 v2 = MyValue2.createInline(rI, true);
644 long result = test29(rL, v1, rI, v2);
645 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted());
646 }
647
648 // Test compiled code to interpreter with various signatures
649 @DontCompile
650 public long test30_interp(MyValue2 v) {
651 return v.hash();
652 }
653
654 @Test(failOn = ALLOC + STORE + TRAP)
655 public long test30(MyValue2 v) {
656 return test30_interp(v);
657 }
658
659 @DontCompile
660 public void test30_verifier(boolean warmup) {
661 MyValue2 v = MyValue2.createInline(rI, true);
662 long result = test30(v);
663 Asserts.assertEQ(result, v.hashInterpreted());
664 }
665
666 @DontCompile
667 public long test31_interp(int i1, MyValue2 v, int i2) {
668 return v.hash() + i1 - i2;
669 }
670
671 @Test(failOn = ALLOC + STORE + TRAP)
672 public long test31(int i1, MyValue2 v, int i2) {
673 return test31_interp(i1, v, i2);
674 }
675
676 @DontCompile
677 public void test31_verifier(boolean warmup) {
678 MyValue2 v = MyValue2.createInline(rI, true);
679 long result = test31(rI, v, 2*rI);
680 Asserts.assertEQ(result, v.hashInterpreted() - rI);
681 }
682
683 @DontCompile
684 public long test32_interp(long l1, MyValue2 v, long l2) {
685 return v.hash() + l1 - l2;
686 }
687
688 @Test(failOn = ALLOC + STORE + TRAP)
689 public long test32(long l1, MyValue2 v, long l2) {
690 return test32_interp(l1, v, l2);
691 }
692
693 @DontCompile
694 public void test32_verifier(boolean warmup) {
695 MyValue2 v = MyValue2.createInline(rI, true);
696 long result = test32(rL, v, 2*rL);
697 Asserts.assertEQ(result, v.hashInterpreted() - rL);
698 }
699
700 @DontCompile
701 public long test33_interp(int i, MyValue2 v, long l) {
702 return v.hash() + i + l;
703 }
704
705 @Test(failOn = ALLOC + STORE + TRAP)
706 public long test33(int i, MyValue2 v, long l) {
707 return test33_interp(i, v, l);
708 }
709
710 @DontCompile
711 public void test33_verifier(boolean warmup) {
712 MyValue2 v = MyValue2.createInline(rI, true);
713 long result = test33(rI, v, rL);
714 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
715 }
716
717 @DontCompile
718 public long test34_interp(long l, MyValue2 v, int i) {
719 return v.hash() + i + l;
720 }
721
722 @Test(failOn = ALLOC + STORE + TRAP)
723 public long test34(long l, MyValue2 v, int i) {
724 return test34_interp(l, v, i);
725 }
726
727 @DontCompile
728 public void test34_verifier(boolean warmup) {
729 MyValue2 v = MyValue2.createInline(rI, true);
730 long result = test34(rL, v, rI);
731 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
732 }
733
734 @DontCompile
735 public long test35_interp(long l, MyValue1 v1, int i, MyValue2 v2) {
736 return v1.hash() + i + l + v2.hash();
737 }
738
739 @Test(failOn = ALLOC + STORE + TRAP)
740 public long test35(long l, MyValue1 v1, int i, MyValue2 v2) {
741 return test35_interp(l, v1, i, v2);
742 }
743
744 @DontCompile
745 public void test35_verifier(boolean warmup) {
746 MyValue1 v1 = MyValue1.createDontInline(rI, rL);
747 MyValue2 v2 = MyValue2.createInline(rI, true);
748 long result = test35(rL, v1, rI, v2);
749 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted());
750 }
751
752 // test that debug info at a call is correct
753 @DontCompile
754 public long test36_interp(MyValue2 v, boolean flag) {
755 if (flag) {
756 // uncommon trap
757 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test36"));
758 }
759 return v.hash();
760 }
761
762 @Test(failOn = ALLOC + STORE + TRAP)
763 public long test36(MyValue2 v, boolean flag, long l) {
764 return test36_interp(v, flag) + l;
765 }
766
767 @DontCompile
768 public void test36_verifier(boolean warmup) {
769 MyValue2 v = MyValue2.createInline(rI, true);
770 long result = test36(v, false, rL);
771 Asserts.assertEQ(result, v.hashInterpreted() + rL);
772 if (!warmup) {
773 result = test36(v, true, rL);
774 Asserts.assertEQ(result, v.hashInterpreted() + rL);
775 }
776 }
777
778 // ========== Test infrastructure ==========
779
780 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
781 private static final int ValueTypePassFieldsAsArgsOn = 0x1;
782 private static final int ValueTypePassFieldsAsArgsOff = 0x2;
783 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff;
784 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
785 private static final int COMP_LEVEL_ANY = -1;
786 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
787 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
788 private static final int WARMUP = 10;
789 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
790 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
791 // TODO use Platform.isComp() after merge with JDK 9
792 private static boolean XCOMP = System.getProperty("java.vm.info").startsWith("compiled ");
793
794 // Regular expressions used to match nodes in the PrintIdeal output
795 private static final String START = "(\\d+\\t(.*";
796 private static final String MID = ".*)+\\t===.*";
797 private static final String END = ")|";
798 private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
799 private static final String LOAD = START + "Load" + MID + "valuetype\\*" + END;
800 private static final String STORE = START + "Store" + MID + "valuetype\\*" + END;
801 private static final String LOOP = START + "Loop" + MID + "" + END;
802 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap" + END;
803 // TODO: match field values of scalar replaced object
804 private static final String SCOBJ = "(.*# ScObj.*" + END;
805
806 static {
807 // Gather all test methods and put them in Hashtable
808 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
809 Test[] annos = m.getAnnotationsByType(Test.class);
810 if (annos.length != 0) {
811 tests.put("ValueTypeTestBench::" + m.getName(), m);
812 }
813 }
814 }
815
816 public static void main(String[] args) throws Throwable {
817 if (args.length == 0) {
818 ArrayList<String> all_args = new ArrayList(List.of(
819 "-noverify",
820 "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI",
821 "-XX:-TieredCompilation", "-XX:-BackgroundCompilation",
822 "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
823 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
824 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
825 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*"
826 ));
827 // Run tests in own process and verify output
828 all_args.add("-XX:+UnlockExperimentalVMOptions");
829 if ((Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs")) {
830 all_args.add("-XX:+ValueTypePassFieldsAsArgs");
831 } else {
832 all_args.add("-XX:-ValueTypePassFieldsAsArgs");
833 }
834 all_args.add(ValueTypeTestBench.class.getName());
835 all_args.add("run");
836 OutputAnalyzer oa = ProcessTools.executeTestJvm(all_args.toArray(new String[0]));
837 // If ideal graph printing is enabled/supported, verify output
838 String output = oa.getOutput();
839 oa.shouldHaveExitValue(0);
840 if (output.contains("PrintIdeal enabled")) {
841 parseOutput(output);
842 } else {
843 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
844 }
845 } else {
846 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
847 System.out.println("PrintIdeal enabled");
848 }
849 // Execute tests
850 ValueTypeTestBench bench = new ValueTypeTestBench();
851 bench.run();
852 }
853 }
854
855 public static void parseOutput(String output) throws Exception {
856 String split = "b compiler.valhalla.valuetypes.";
857 String[] compilations = output.split(split);
858 // Print header
859 System.out.println(compilations[0]);
860 // Iterate over compilation output
861 for (String graph : compilations) {
862 String[] lines = graph.split("\\n");
863 if (lines[0].contains("@")) {
864 continue; // Ignore OSR compilations
865 }
866 String testName = lines[0].split(" ")[0];
867 Method test = tests.get(testName);
868 if (test == null) {
869 // Skip helper methods
870 continue;
871 }
872 if (PRINT_GRAPH) {
873 System.out.println("\nGraph for " + graph);
874 }
875 // Parse graph using regular expressions to determine if it contains forbidden nodes
876 Test[] annos = test.getAnnotationsByType(Test.class);
877 Test anno = null;
878 for (Test a : annos) {
879 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) {
880 assert anno == null;
881 anno = a;
882 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) {
883 assert anno == null;
884 anno = a;
885 }
886 }
887 assert anno != null;
888 String regexFail = anno.failOn();
889 if (!regexFail.isEmpty()) {
890 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
891 Matcher matcher = pattern.matcher(graph);
892 boolean fail = false;
893 while (matcher.find()) {
894 System.out.println("Graph for '" + testName + "' contains forbidden node:");
895 System.out.println(matcher.group());
896 fail = true;
897 }
898 Asserts.assertFalse(fail, "Graph for '" + testName + "' contains forbidden nodes");
899 }
900 String[] regexMatch = anno.match();
901 int[] matchCount = anno.matchCount();
902 for (int i = 0; i < regexMatch.length; ++i) {
903 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
904 Matcher matcher = pattern.matcher(graph);
905 int count = 0;
906 String nodes = "";
907 while (matcher.find()) {
954 //WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION);
955
956 // Execute tests
957 for (Method test : tests.values()) {
958 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class);
959 // Warmup using verifier method
960 for (int i = 0; i < WARMUP; ++i) {
961 verifier.invoke(this, true);
962 }
963 // Trigger compilation
964 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION);
965 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
966 // Check result
967 verifier.invoke(this, false);
968 }
969 }
970 }
971
972 // Mark method as test
973 @Retention(RetentionPolicy.RUNTIME)
974 @Repeatable(Tests.class)
975 @interface Test {
976 // Regular expression used to match forbidden IR nodes
977 // in the C2 IR emitted for this test.
978 String failOn() default "";
979 // Regular expressions used to match and count IR nodes.
980 String[] match() default { };
981 int[] matchCount() default { };
982 int valid() default ValueTypeTestBench.AllFlags;
983 }
984
985 @Retention(RetentionPolicy.RUNTIME)
986 @interface Tests {
987 Test[] value();
988 }
989
990 // Force method inlining during compilation
991 @Retention(RetentionPolicy.RUNTIME)
992 @interface ForceInline { }
993
994 // Prevent method inlining during compilation
995 @Retention(RetentionPolicy.RUNTIME)
996 @interface DontInline { }
997
998 // Prevent method compilation
999 @Retention(RetentionPolicy.RUNTIME)
1000 @interface DontCompile { }
|