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