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 * @requires os.simpleArch == "x64"
30 * @modules java.base/jdk.experimental.bytecode
31 * java.base/jdk.experimental.value
32 * java.base/jdk.internal.misc:+open
33 * jdk.incubator.mvt
34 * @compile -XDenableValueTypes ValueCapableClass1.java ValueCapableClass2.java ValueTypeTestBench.java
35 * @run main ClassFileInstaller sun.hotspot.WhiteBox
36 * @run main ClassFileInstaller jdk.test.lib.Platform
37 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
38 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+VerifyAdapterSharing -XX:+VerifyStack
39 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
40 * -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
41 * -Djdk.lang.reflect.DVT=true
42 * compiler.valhalla.valuetypes.ValueTypeTestBench
43 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
44 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+VerifyStack
45 * -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
46 * -Djdk.lang.reflect.DVT=true
47 * compiler.valhalla.valuetypes.ValueTypeTestBench
48 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
49 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+AlwaysIncrementalInline
50 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
51 * -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
52 * -Djdk.lang.reflect.DVT=true
53 * compiler.valhalla.valuetypes.ValueTypeTestBench
54 */
55
56 package compiler.valhalla.valuetypes;
57
58 import compiler.whitebox.CompilerWhiteBoxTest;
59 import jdk.experimental.bytecode.MacroCodeBuilder.CondKind;
60 import jdk.experimental.bytecode.TypeTag;
61 import jdk.experimental.value.MethodHandleBuilder;
62 import jdk.incubator.mvt.ValueType;
63 import jdk.test.lib.Asserts;
64 import jdk.test.lib.management.InputArguments;
65 import jdk.test.lib.Platform;
66 import jdk.test.lib.process.ProcessTools;
67 import jdk.test.lib.process.OutputAnalyzer;
68 import jdk.test.lib.Utils;
69 import sun.hotspot.WhiteBox;
70
71 import java.lang.annotation.Retention;
72 import java.lang.annotation.RetentionPolicy;
73 import java.lang.annotation.Repeatable;
74 import java.lang.invoke.*;
75 import java.lang.reflect.Method;
76 import java.util.ArrayList;
77 import java.util.Arrays;
78 import java.util.Hashtable;
79 import java.util.LinkedHashMap;
80 import java.util.List;
81 import java.util.Map;
82 import java.util.regex.Matcher;
83 import java.util.regex.Pattern;
84
85 // Test value types
86 __ByValue final class MyValue1 {
87 static int s;
88 static final long sf = ValueTypeTestBench.rL;
89 final int x;
90 final long y;
91 final short z;
92 final Integer o;
93 final int[] oa;
94 final MyValue2 v1;
95 final MyValue2 v2;
96 static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true);
97 final int c;
98
99 private MyValue1() {
100 s = 0;
101 this.x = 0;
102 this.y = 0;
103 this.z = 0;
115
116 @ForceInline
117 __ValueFactory static MyValue1 createDefaultInline() {
118 return __MakeDefault MyValue1();
119 }
120
121 @DontInline
122 static MyValue1 createWithFieldsDontInline(int x, long y) {
123 return createWithFieldsInline(x, y);
124 }
125
126 @ForceInline
127 static MyValue1 createWithFieldsInline(int x, long y) {
128 MyValue1 v = createDefaultInline();
129 v = setX(v, x);
130 v = setY(v, y);
131 v = setZ(v, (short)x);
132 v = setO(v, new Integer(x));
133 int[] oa = {x};
134 v = setOA(v, oa);
135 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y));
136 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y));
137 v = setC(v, ValueTypeTestBench.rI);
138 return v;
139 }
140
141 // Hash only primitive and value type fields to avoid NullPointerException
142 @ForceInline
143 public long hashPrimitive() {
144 return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash();
145 }
146
147 @ForceInline
148 public long hash() {
149 return hashPrimitive() + o + oa[0];
150 }
151
152 @DontCompile
153 public long hashInterpreted() {
154 return s + sf + x + y + z + o + oa[0] + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted();
155 }
156
157 @ForceInline
158 public void print() {
159 System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z + ", o=" + (o != null ? (Integer)o : "NULL") + ", v1[");
160 v1.print();
161 System.out.print("], v2[");
162 v2.print();
163 System.out.print("], v3[");
164 v3.print();
165 System.out.print("], c=" + c);
166 }
167
168 @ForceInline
169 __ValueFactory static MyValue1 setX(MyValue1 v, int x) {
170 v.x = x;
171 return v;
172 }
173
174 @ForceInline
175 __ValueFactory static MyValue1 setY(MyValue1 v, long y) {
176 v.y = y;
177 return v;
178 }
179
197
198 @ForceInline
199 __ValueFactory static MyValue1 setC(MyValue1 v, int c) {
200 v.c = c;
201 return v;
202 }
203
204 @ForceInline
205 __ValueFactory static MyValue1 setV1(MyValue1 v, MyValue2 v1) {
206 v.v1 = v1;
207 return v;
208 }
209
210 @ForceInline
211 __ValueFactory static MyValue1 setV2(MyValue1 v, MyValue2 v2) {
212 v.v2 = v2;
213 return v;
214 }
215 }
216
217 __ByValue final class MyValue2 {
218 final int x;
219 final byte y;
220 final boolean b;
221 final long c;
222
223 private MyValue2() {
224 this.x = 0;
225 this.y = 0;
226 this.b = false;
227 this.c = 0;
228 }
229
230 @ForceInline
231 __ValueFactory public static MyValue2 createDefaultInline() {
232 return __MakeDefault MyValue2();
233 }
234
235 @ForceInline
236 public static MyValue2 createWithFieldsInline(int x, boolean b) {
237 MyValue2 v = createDefaultInline();
238 v = setX(v, x);
239 v = setY(v, (byte)x);
240 v = setB(v, b);
241 v = setC(v, ValueTypeTestBench.rL);
242 return v;
243 }
244
245 @ForceInline
246 public long hash() {
247 return x + y + (b ? 0 : 1) + c;
248 }
249
250 @DontInline
251 public long hashInterpreted() {
252 return x + y + (b ? 0 : 1) + c;
253 }
254
255 @ForceInline
256 public void print() {
257 System.out.print("x=" + x + "y=" + y + ", b=" + b + ", c=" + c);
258 }
259
260 @ForceInline
261 __ValueFactory static MyValue2 setX(MyValue2 v, int x) {
262 v.x = x;
263 return v;
264 }
265
266 @ForceInline
267 __ValueFactory static MyValue2 setY(MyValue2 v, byte y) {
268 v.y = y;
269 return v;
270 }
271
272 @ForceInline
273 __ValueFactory static MyValue2 setC(MyValue2 v, long c) {
274 v.c = c;
275 return v;
276 }
277
278 @ForceInline
279 __ValueFactory static MyValue2 setB(MyValue2 v, boolean b) {
280 v.b = b;
281 return v;
282 }
283 }
284
285 // Value type definition to stress test return of a value in registers
286 // (uses all registers of calling convention on x86_64)
287 __ByValue final class MyValue3 {
288 final char c;
289 final byte bb;
290 final short s;
291 final int i;
292 final long l;
293 final Object o;
294 final float f1;
295 final double f2;
296 final float f3;
297 final double f4;
298 final float f5;
299 final double f6;
300 final float f7;
301 final double f8;
302
303 private MyValue3(char c,
304 byte bb,
305 short s,
306 int i,
307 long l,
308 Object o,
309 float f1,
310 double f2,
311 float f3,
312 double f4,
313 float f5,
314 double f6,
315 float f7,
316 double f8) {
317 this.c = c;
318 this.bb = bb;
319 this.s = s;
320 this.i = i;
321 this.l = l;
322 this.o = o;
323 this.f1 = f1;
324 this.f2 = f2;
325 this.f3 = f3;
326 this.f4 = f4;
327 this.f5 = f5;
328 this.f6 = f6;
329 this.f7 = f7;
330 this.f8 = f8;
331 }
332
333 private MyValue3() {
334 this.c = 0;
335 this.bb = 0;
336 this.s = 0;
337 this.i = 0;
338 this.l = 0;
339 this.o = null;
340 this.f1 = 0;
341 this.f2 = 0;
342 this.f3 = 0;
343 this.f4 = 0;
344 this.f5 = 0;
345 this.f6 = 0;
346 this.f7 = 0;
347 this.f8 = 0;
348 }
349
350 @ForceInline
351 __ValueFactory static MyValue3 setC(MyValue3 v, char c) {
352 v.c = c;
353 return v;
354 }
355
356 @ForceInline
357 __ValueFactory static MyValue3 setBB(MyValue3 v, byte bb) {
358 v.bb = bb;
359 return v;
360 }
361
362 @ForceInline
363 __ValueFactory static MyValue3 setS(MyValue3 v, short s) {
364 v.s = s;
365 return v;
366 }
367
403
404 @ForceInline
405 __ValueFactory static MyValue3 setF4(MyValue3 v, double f4) {
406 v.f4 = f4;
407 return v;
408 }
409
410 @ForceInline
411 __ValueFactory static MyValue3 setF5(MyValue3 v, float f5) {
412 v.f5 = f5;
413 return v;
414 }
415
416 @ForceInline
417 __ValueFactory static MyValue3 setF6(MyValue3 v, double f6) {
418 v.f6 = f6;
419 return v;
420 }
421
422 @ForceInline
423 __ValueFactory static MyValue3 setF7(MyValue3 v, float f7) {
424 v.f7 = f7;
425 return v;
426 }
427
428 @ForceInline
429 __ValueFactory static MyValue3 setF8(MyValue3 v, double f8) {
430 v.f8 = f8;
431 return v;
432 }
433
434 @ForceInline
435 __ValueFactory public static MyValue3 createDefault() {
436 return __MakeDefault MyValue3();
437 }
438
439 @ForceInline
440 public static MyValue3 create() {
441 java.util.Random r = Utils.getRandomInstance();
442 MyValue3 v = createDefault();
443 v = setC(v, (char)r.nextInt());
444 v = setBB(v, (byte)r.nextInt());
445 v = setS(v, (short)r.nextInt());
446 v = setI(v, r.nextInt());
447 v = setL(v, r.nextLong());
448 v = setO(v, new Object());
449 v = setF1(v, r.nextFloat());
450 v = setF2(v, r.nextDouble());
451 v = setF3(v, r.nextFloat());
452 v = setF4(v, r.nextDouble());
453 v = setF5(v, r.nextFloat());
454 v = setF6(v, r.nextDouble());
455 v = setF7(v, r.nextFloat());
456 v = setF8(v, r.nextDouble());
457 return v;
458 }
459
460 @DontInline
461 public static MyValue3 createDontInline() {
462 return create();
463 }
464
465 @ForceInline
466 public static MyValue3 copy(MyValue3 other) {
467 MyValue3 v = createDefault();
468 v = setC(v, other.c);
469 v = setBB(v, other.bb);
470 v = setS(v, other.s);
471 v = setI(v, other.i);
472 v = setL(v, other.l);
473 v = setO(v, other.o);
474 v = setF1(v, other.f1);
475 v = setF2(v, other.f2);
476 v = setF3(v, other.f3);
477 v = setF4(v, other.f4);
478 v = setF5(v, other.f5);
479 v = setF6(v, other.f6);
480 v = setF7(v, other.f7);
481 v = setF8(v, other.f8);
482 return v;
483 }
484
485 @DontInline
486 public void verify(MyValue3 other) {
487 Asserts.assertEQ(c, other.c);
488 Asserts.assertEQ(bb, other.bb);
489 Asserts.assertEQ(s, other.s);
490 Asserts.assertEQ(i, other.i);
491 Asserts.assertEQ(l, other.l);
492 Asserts.assertEQ(o, other.o);
493 Asserts.assertEQ(f1, other.f1);
494 Asserts.assertEQ(f2, other.f2);
495 Asserts.assertEQ(f3, other.f3);
496 Asserts.assertEQ(f4, other.f4);
497 Asserts.assertEQ(f5, other.f5);
498 Asserts.assertEQ(f6, other.f6);
499 Asserts.assertEQ(f7, other.f7);
500 Asserts.assertEQ(f8, other.f8);
501 }
502 }
503
504 // Value type definition with too many fields to return in registers
505 __ByValue final class MyValue4 {
506 final MyValue3 v1;
507 final MyValue3 v2;
508
509 private MyValue4(MyValue3 v1, MyValue3 v2) {
510 this.v1 = v1;
511 this.v2 = v2;
512 }
513
514 private MyValue4() {
515 this.v1 = MyValue3.createDefault();
516 this.v2 = MyValue3.createDefault();
517 }
518
519 @ForceInline
520 __ValueFactory static MyValue4 setV1(MyValue4 v, MyValue3 v1) {
521 v.v1 = v1;
522 return v;
523 }
524
525 @ForceInline
526 __ValueFactory static MyValue4 setV2(MyValue4 v, MyValue3 v2) {
527 v.v2 = v2;
528 return v;
529 }
530
531 @ForceInline
532 __ValueFactory public static MyValue4 createDefault() {
533 return __MakeDefault MyValue4();
989 Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1));
990 Asserts.assertEQ(val2.hash(), MyValue2.createWithFieldsInline(rI + 1, true).hash());
991 Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1));
992 }
993
994 // Test folding of constant value type fields
995 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
996 public long test22() {
997 // This should be constant folded
998 return val5.hash() + val5.v3.hash();
999 }
1000
1001 @DontCompile
1002 public void test22_verifier(boolean warmup) {
1003 long result = test22();
1004 Asserts.assertEQ(result, val5.hash() + val5.v3.hash());
1005 }
1006
1007 // Test OSR compilation
1008 @Test()
1009 public long test23() {
1010 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
1011 MyValue1[] va = new MyValue1[Math.abs(rI) % 3];
1012 for (int i = 0; i < va.length; ++i) {
1013 va[i] = MyValue1.createWithFieldsInline(rI, rL);
1014 }
1015 long result = 0;
1016 // Long loop to trigger OSR compilation
1017 for (int i = 0 ; i < 100_000; ++i) {
1018 // Reference local value type in interpreter state
1019 result = v.hash();
1020 for (int j = 0; j < va.length; ++j) {
1021 result += va[j].hash();
1022 }
1023 }
1024 return result;
1025 }
1026
1027 @DontCompile
1028 public void test23_verifier(boolean warmup) {
1662
1663 // Test allocation elimination of unused object with initialized value type field
1664 @Test(failOn = ALLOC + LOAD + STORE + LOOP)
1665 public void test56(boolean deopt) {
1666 TestClass56 unused = new TestClass56();
1667 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
1668 unused.v = v;
1669 if (deopt) {
1670 // uncommon trap
1671 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test56"));
1672 }
1673 }
1674
1675 @DontCompile
1676 public void test56_verifier(boolean warmup) {
1677 test56(!warmup);
1678 }
1679
1680 // Test loop peeling
1681 @Test(failOn = ALLOC + LOAD + STORE)
1682 public void test57() {
1683 MyValue1 v = MyValue1.createWithFieldsInline(0, 1);
1684 // Trigger OSR compilation and loop peeling
1685 for (int i = 0; i < 100_000; ++i) {
1686 if (v.x != i || v.y != i + 1) {
1687 // Uncommon trap
1688 throw new RuntimeException("test57 failed");
1689 }
1690 v = MyValue1.createWithFieldsInline(i + 1, i + 2);
1691 }
1692 }
1693
1694 @DontCompile
1695 public void test57_verifier(boolean warmup) {
1696 test57();
1697 }
1698
1699 // Test loop peeling and unrolling
1700 @Test()
1701 public void test58() {
1702 MyValue1 v1 = MyValue1.createWithFieldsInline(0, 0);
1703 MyValue1 v2 = MyValue1.createWithFieldsInline(1, 1);
1704 // Trigger OSR compilation and loop peeling
1705 for (int i = 0; i < 100_000; ++i) {
1706 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) {
1707 // Uncommon trap
1708 throw new RuntimeException("test58 failed");
1709 }
1710 v1 = MyValue1.createWithFieldsInline(2*(i+1), 0);
1711 v2 = MyValue1.createWithFieldsInline(i+2, i+2);
1712 }
1713 }
1714
1715 @DontCompile
1716 public void test58_verifier(boolean warmup) {
1717 test58();
1718 }
1719
1720 // When calling a method on __Value, passing fields as arguments is impossible
2557 vt = MyValue3.setI(vt, (int)vt.c);
2558 // vt is not equal to staticVal3, so C2 should not re-use the oop
2559 va[0] = vt;
2560 staticVal3 = vt;
2561 vt.verify(staticVal3);
2562 return vt;
2563 }
2564
2565 @DontCompile
2566 public void test92_verifier(boolean warmup) {
2567 staticVal3 = MyValue3.create();
2568 MyValue3[] va = new MyValue3[1];
2569 MyValue3 vt = test92(va);
2570 Asserts.assertEQ(staticVal3.i, (int)staticVal3.c);
2571 Asserts.assertEQ(va[0].i, (int)staticVal3.c);
2572 Asserts.assertEQ(vt.i, (int)staticVal3.c);
2573 }
2574
2575 // Test correct handling of __Value merges through PhiNodes
2576 @Test()
2577 public long test93() throws Throwable {
2578 // Create a new value type
2579 final MethodHandle dvt = MethodHandleBuilder.loadCode(MethodHandles.lookup(), "createValueType",
2580 MethodType.methodType(ValueType.forClass(ValueCapableClass1.class).valueClass()),
2581 CODE -> {
2582 CODE.
2583 iconst_1().
2584 anewarray(ValueType.forClass(ValueCapableClass1.class).valueClass()).
2585 iconst_0().
2586 vaload().
2587 vreturn();
2588 });
2589 // Box the value type
2590 final MethodHandle box = MethodHandleBuilder.loadCode(MethodHandles.lookup(), "boxValueType",
2591 MethodType.methodType(ValueCapableClass1.class, ValueType.forClass(ValueCapableClass1.class).valueClass()),
2592 CODE -> {
2593 CODE.
2594 vload(0).
2595 vbox(ValueCapableClass1.class).
2596 areturn();
3023 public void test105_verifier(boolean warmup) throws Throwable {
3024 test105_i++;
3025 long hash = test105();
3026 boolean b = (test105_i % 100) == 0;
3027 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+test105_i * (b ? 1 : -1), b).hash());
3028 }
3029
3030
3031 // OSR compilation with __Value local
3032 @DontCompile
3033 public __Value test106_init() {
3034 return MyValue1.createWithFieldsInline(rI, rL);
3035 }
3036
3037 @DontCompile
3038 public __Value test106_body() {
3039 return MyValue1.createWithFieldsInline(rI, rL);
3040 }
3041
3042 @Test()
3043 public __Value test106() throws Throwable {
3044 __Value vt = test106_init();
3045 for (int i = 0; i < 50_000; i++) {
3046 if (i % 2 == 1) {
3047 vt = test106_body();
3048 }
3049 }
3050 return vt;
3051 }
3052
3053 @DontCompile
3054 public void test106_verifier(boolean warmup) throws Throwable {
3055 test106();
3056 }
3057
3058 // ========== Test infrastructure ==========
3059
3060 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
3061 private static final int ValueTypePassFieldsAsArgsOn = 0x1;
3062 private static final int ValueTypePassFieldsAsArgsOff = 0x2;
3063 private static final int ValueTypeArrayFlattenOn = 0x4;
3064 private static final int ValueTypeArrayFlattenOff = 0x8;
3065 private static final int ValueTypeReturnedAsFieldsOn = 0x10;
3066 private static final int ValueTypeReturnedAsFieldsOff = 0x20;
3067 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | ValueTypeReturnedAsFieldsOn;
3068 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
3069 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
3070 private static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields");
3071 private static final int COMP_LEVEL_ANY = -2;
3072 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
3073 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
3074 private static final int WARMUP = 251;
3075 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
3076 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
3077 private static boolean XCOMP = Platform.isComp();
3078
3079 // Regular expressions used to match nodes in the PrintIdeal output
3080 private static final String START = "(\\d+\\t(.*";
3081 private static final String MID = ".*)+\\t===.*";
3082 private static final String END = ")|";
3083 private static final String ALLOC = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END;
3084 private static final String ALLOCA = "(.*precise klass \\[Qcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END;
3085 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
3086 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END;
3087 private static final String LOADK = START + "LoadK" + MID + END;
3088 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
3089 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END;
3090 private static final String LOOP = START + "Loop" + MID + "" + END;
3091 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END;
3092 private static final String RETURN = START + "Return" + MID + "returns" + END;
3093 private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END;
3094 private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END;
3095 private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END;
3096 private static final String CALL = START + "CallStaticJava" + MID + END;
3097 private static final String STOREVALUETYPEFIELDS = START + "CallStaticJava" + MID + "store_value_type_fields" + END;
3098 private static final String SCOBJ = "(.*# ScObj.*" + END;
3099
3100 static {
3101 // Gather all test methods and put them in Hashtable
3102 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
3103 Test[] annos = m.getAnnotationsByType(Test.class);
3104 if (annos.length != 0) {
3105 tests.put("ValueTypeTestBench::" + m.getName(), m);
3106 }
3107 }
3108 }
3109
3110 private static void execute_vm(String... args) throws Throwable {
3111 Asserts.assertFalse(tests.isEmpty(), "no tests to execute");
3112 ArrayList<String> all_args = new ArrayList(List.of(args));
3113 // Run tests in own process and verify output
3114 all_args.add(ValueTypeTestBench.class.getName());
3115 all_args.add("run");
3116 // Spawn process with default JVM options from the test's run command
3117 String[] vmInputArgs = InputArguments.getVmInputArgs();
3118 String[] cmds = Arrays.copyOf(vmInputArgs, vmInputArgs.length + all_args.size());
3119 System.arraycopy(all_args.toArray(), 0, cmds, vmInputArgs.length, all_args.size());
3120 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds);
3121 // If ideal graph printing is enabled/supported, verify output
3122 String output = oa.getOutput();
3123 oa.shouldHaveExitValue(0);
3124 boolean verifyIR = output.contains("PrintIdeal enabled") &&
3125 !output.contains("ValueTypePassFieldsAsArgs is not supported on this platform");
3126 if (verifyIR) {
3127 parseOutput(output);
3128 } else {
3129 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
3130 }
3131 }
3132
3133 public static void main(String[] args) throws Throwable {
3134 //tests.values().removeIf(p -> !p.getName().equals("test106")); // Run single test
3135 if (args.length == 0) {
3136 execute_vm("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-BackgroundCompilation",
3137 "-XX:+PrintCompilation", "-XX:+PrintInlining", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
3138 "-XX:CICompilerCount=1",
3139 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
3140 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
3141 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*",
3142 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue3::*",
3143 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue4::*",
3144 "-XX:CompileCommand=compileonly,java.lang.Object::<init>",
3145 "-XX:CompileCommand=inline,java.lang.__Value::hashCode",
3146 "-XX:CompileCommand=compileonly,java.lang.invoke.*::*",
3147 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueCapableClass2_*::*",
3148 "-XX:CompileCommand=compileonly,java.lang.Long::sum");
3149 } else {
3150 // Execute tests
3151 ValueTypeTestBench bench = new ValueTypeTestBench();
3152 bench.run();
3153 }
3154 }
3155
3156 public static void parseOutput(String output) throws Exception {
3157 Pattern comp_re = Pattern.compile("\\n\\s+\\d+\\s+\\d+\\s+(%| )(s| )(!| )b(n| )\\s+\\S+\\.(?<name>[^.]+::\\S+)\\s+(?<osr>@ \\d+\\s+)?[(]\\d+ bytes[)]\\n");
3158 Matcher m = comp_re.matcher(output);
3159 Map<String,String> compilations = new LinkedHashMap<>();
3160 int prev = 0;
3161 String methodName = null;
3162 while (m.find()) {
3163 if (prev == 0) {
3164 // Print header
3165 System.out.print(output.substring(0, m.start()+1));
3166 } else if (methodName != null) {
3167 compilations.put(methodName, output.substring(prev, m.start()+1));
3168 }
3169 if (m.group("osr") != null) {
3170 methodName = null;
3171 } else {
3172 methodName = m.group("name");
3173 }
3174 prev = m.end();
3175 }
3176 if (prev == 0) {
3265 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true);
3266 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false);
3267 WHITE_BOX.testSetDontInlineMethod(m, true);
3268 }
3269 if (m.isAnnotationPresent(ForceInline.class)) {
3270 WHITE_BOX.testSetForceInlineMethod(m, true);
3271 } else if (m.isAnnotationPresent(DontInline.class)) {
3272 WHITE_BOX.testSetDontInlineMethod(m, true);
3273 }
3274 }
3275 }
3276
3277 public void run() throws Exception {
3278 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
3279 System.out.println("PrintIdeal enabled");
3280 }
3281 System.out.format("rI = %d, rL = %d\n", rI, rL);
3282 setup(this.getClass().getDeclaredMethods());
3283 setup(MyValue1.class.getDeclaredMethods());
3284 setup(MyValue2.class.getDeclaredMethods());
3285 setup(MyValue3.class.getDeclaredMethods());
3286 setup(MyValue4.class.getDeclaredMethods());
3287
3288 // Compile class initializers
3289 WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION);
3290 WHITE_BOX.enqueueInitializerForCompilation(MyValue1.class, COMP_LEVEL_FULL_OPTIMIZATION);
3291 WHITE_BOX.enqueueInitializerForCompilation(MyValue2.class, COMP_LEVEL_FULL_OPTIMIZATION);
3292 WHITE_BOX.enqueueInitializerForCompilation(MyValue3.class, COMP_LEVEL_FULL_OPTIMIZATION);
3293 WHITE_BOX.enqueueInitializerForCompilation(MyValue4.class, COMP_LEVEL_FULL_OPTIMIZATION);
3294
3295 // Execute tests
3296 for (Method test : tests.values()) {
3297 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class);
3298 // Warmup using verifier method
3299 Warmup anno = test.getAnnotation(Warmup.class);
3300 int warmup = anno == null ? WARMUP : anno.value();
3301 for (int i = 0; i < warmup; ++i) {
3302 verifier.invoke(this, true);
3303 }
3304 // Trigger compilation
3305 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION);
3306 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
3307 // Check result
3308 verifier.invoke(this, false);
3309 }
3310 }
3311 }
3312
3313 // Mark method as test
3314 @Retention(RetentionPolicy.RUNTIME)
3315 @Repeatable(Tests.class)
3316 @interface Test {
3317 // Regular expression used to match forbidden IR nodes
3318 // in the C2 IR emitted for this test.
3319 String failOn() default "";
3320 // Regular expressions used to match and count IR nodes.
3321 String[] match() default { };
3322 int[] matchCount() default { };
3323 int valid() default ValueTypeTestBench.AllFlags;
3324 }
3325
3326 @Retention(RetentionPolicy.RUNTIME)
3327 @interface Tests {
3328 Test[] value();
3329 }
3330
3331 // Force method inlining during compilation
3332 @Retention(RetentionPolicy.RUNTIME)
3333 @interface ForceInline { }
3334
3335 // Prevent method inlining during compilation
3336 @Retention(RetentionPolicy.RUNTIME)
3337 @interface DontInline { }
3338
3339 // Prevent method compilation
3340 @Retention(RetentionPolicy.RUNTIME)
3341 @interface DontCompile { }
3342
3343 @Retention(RetentionPolicy.RUNTIME)
3344 @interface Warmup {
3345 int value();
3346 }
|
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 * @requires os.simpleArch == "x64"
30 * @modules java.base/jdk.experimental.bytecode
31 * java.base/jdk.experimental.value
32 * java.base/jdk.internal.misc:+open
33 * jdk.incubator.mvt
34 * @compile -XDenableValueTypes ValueCapableClass1.java ValueCapableClass2.java ValueTypeTestBench.java
35 * @run main ClassFileInstaller sun.hotspot.WhiteBox
36 * @run main ClassFileInstaller jdk.test.lib.Platform
37 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
38 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+AlwaysIncrementalInline
39 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
40 * -XX:ValueFieldMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
41 * -XX:ValueTypesBufferMaxMemory=0
42 * -Djdk.lang.reflect.DVT=true compiler.valhalla.valuetypes.ValueTypeTestBench
43 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
44 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:-UseCompressedOops
45 * -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
46 * -XX:ValueFieldMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
47 * -XX:ValueTypesBufferMaxMemory=0
48 * -Djdk.lang.reflect.DVT=true compiler.valhalla.valuetypes.ValueTypeTestBench
49 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
50 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:-UseCompressedOops
51 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
52 * -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=0 -XX:ValueArrayElemMaxFlatOops=0
53 * -XX:ValueTypesBufferMaxMemory=0
54 * -Djdk.lang.reflect.DVT=true -DVerifyIR=false compiler.valhalla.valuetypes.ValueTypeTestBench
55 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
56 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+AlwaysIncrementalInline
57 * -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
58 * -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=0 -XX:ValueArrayElemMaxFlatOops=0
59 * -XX:ValueTypesBufferMaxMemory=0
60 * -Djdk.lang.reflect.DVT=true -DVerifyIR=false compiler.valhalla.valuetypes.ValueTypeTestBench
61 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
62 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation
63 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
64 * -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
65 * -XX:ValueTypesBufferMaxMemory=0
66 * -Djdk.lang.reflect.DVT=true -DVerifyIR=false compiler.valhalla.valuetypes.ValueTypeTestBench
67 */
68
69 // TODO remove -XX:ValueTypesBufferMaxMemory=0 when interpreter buffering is fixed
70
71 package compiler.valhalla.valuetypes;
72
73 import compiler.whitebox.CompilerWhiteBoxTest;
74 import jdk.experimental.bytecode.MacroCodeBuilder.CondKind;
75 import jdk.experimental.bytecode.TypeTag;
76 import jdk.experimental.value.MethodHandleBuilder;
77 import jdk.incubator.mvt.ValueType;
78 import jdk.test.lib.Asserts;
79 import jdk.test.lib.management.InputArguments;
80 import jdk.test.lib.Platform;
81 import jdk.test.lib.process.ProcessTools;
82 import jdk.test.lib.process.OutputAnalyzer;
83 import jdk.test.lib.Utils;
84 import sun.hotspot.WhiteBox;
85
86 import java.lang.annotation.Retention;
87 import java.lang.annotation.RetentionPolicy;
88 import java.lang.annotation.Repeatable;
89 import java.lang.invoke.*;
90 import java.lang.reflect.Method;
91 import java.util.ArrayList;
92 import java.util.Arrays;
93 import java.util.Hashtable;
94 import java.util.LinkedHashMap;
95 import java.util.List;
96 import java.util.Map;
97 import java.util.regex.Matcher;
98 import java.util.regex.Pattern;
99 import java.util.TreeMap;
100
101 // Test value types
102 __ByValue final class MyValue1 {
103 static int s;
104 static final long sf = ValueTypeTestBench.rL;
105 final int x;
106 final long y;
107 final short z;
108 final Integer o;
109 final int[] oa;
110 final MyValue2 v1;
111 final MyValue2 v2;
112 static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true);
113 final int c;
114
115 private MyValue1() {
116 s = 0;
117 this.x = 0;
118 this.y = 0;
119 this.z = 0;
131
132 @ForceInline
133 __ValueFactory static MyValue1 createDefaultInline() {
134 return __MakeDefault MyValue1();
135 }
136
137 @DontInline
138 static MyValue1 createWithFieldsDontInline(int x, long y) {
139 return createWithFieldsInline(x, y);
140 }
141
142 @ForceInline
143 static MyValue1 createWithFieldsInline(int x, long y) {
144 MyValue1 v = createDefaultInline();
145 v = setX(v, x);
146 v = setY(v, y);
147 v = setZ(v, (short)x);
148 v = setO(v, new Integer(x));
149 int[] oa = {x};
150 v = setOA(v, oa);
151 v = setV1(v, MyValue2.createWithFieldsInline(x, true));
152 v = setV2(v, MyValue2.createWithFieldsInline(x, false));
153 v = setC(v, ValueTypeTestBench.rI);
154 return v;
155 }
156
157 // Hash only primitive and value type fields to avoid NullPointerException
158 @ForceInline
159 public long hashPrimitive() {
160 return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash();
161 }
162
163 @ForceInline
164 public long hash() {
165 return hashPrimitive() + o + oa[0];
166 }
167
168 @DontCompile
169 public long hashInterpreted() {
170 return s + sf + x + y + z + o + oa[0] + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted();
171 }
172
173 @ForceInline
174 public void print() {
175 System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z + ", o=" + (o != null ? (Integer)o : "NULL") + ", oa=" + oa[0] + ", v1[");
176 v1.print();
177 System.out.print("], v2[");
178 v2.print();
179 System.out.print("], v3[");
180 v3.print();
181 System.out.print("], c=" + c);
182 }
183
184 @ForceInline
185 __ValueFactory static MyValue1 setX(MyValue1 v, int x) {
186 v.x = x;
187 return v;
188 }
189
190 @ForceInline
191 __ValueFactory static MyValue1 setY(MyValue1 v, long y) {
192 v.y = y;
193 return v;
194 }
195
213
214 @ForceInline
215 __ValueFactory static MyValue1 setC(MyValue1 v, int c) {
216 v.c = c;
217 return v;
218 }
219
220 @ForceInline
221 __ValueFactory static MyValue1 setV1(MyValue1 v, MyValue2 v1) {
222 v.v1 = v1;
223 return v;
224 }
225
226 @ForceInline
227 __ValueFactory static MyValue1 setV2(MyValue1 v, MyValue2 v2) {
228 v.v2 = v2;
229 return v;
230 }
231 }
232
233 __ByValue final class MyValue2Inline {
234 final boolean b;
235 final long c;
236
237 private MyValue2Inline() {
238 this.b = false;
239 this.c = 0;
240 }
241
242 @ForceInline
243 __ValueFactory static MyValue2Inline setB(MyValue2Inline v, boolean b) {
244 v.b = b;
245 return v;
246 }
247
248 @ForceInline
249 __ValueFactory static MyValue2Inline setC(MyValue2Inline v, long c) {
250 v.c = c;
251 return v;
252 }
253
254 @ForceInline
255 __ValueFactory public static MyValue2Inline createDefault() {
256 return __MakeDefault MyValue2Inline();
257 }
258
259 @ForceInline
260 public static MyValue2Inline createWithFieldsInline(boolean b, long c) {
261 MyValue2Inline v = MyValue2Inline.createDefault();
262 v = MyValue2Inline.setB(v, b);
263 v = MyValue2Inline.setC(v, c);
264 return v;
265 }
266 }
267
268 __ByValue final class MyValue2 {
269 final int x;
270 final byte y;
271 final MyValue2Inline v1;
272
273 private MyValue2() {
274 this.x = 0;
275 this.y = 0;
276 this.v1 = MyValue2Inline.createDefault();
277 }
278
279 @ForceInline
280 __ValueFactory public static MyValue2 createDefaultInline() {
281 return __MakeDefault MyValue2();
282 }
283
284 @ForceInline
285 public static MyValue2 createWithFieldsInline(int x, boolean b) {
286 MyValue2 v = createDefaultInline();
287 v = setX(v, x);
288 v = setY(v, (byte)x);
289 v = setV1(v, MyValue2Inline.createWithFieldsInline(b, ValueTypeTestBench.rL));
290 return v;
291 }
292
293 @ForceInline
294 public long hash() {
295 return x + y + (v1.b ? 0 : 1) + v1.c;
296 }
297
298 @DontInline
299 public long hashInterpreted() {
300 return x + y + (v1.b ? 0 : 1) + v1.c;
301 }
302
303 @ForceInline
304 public void print() {
305 System.out.print("x=" + x + ", y=" + y + ", b=" + v1.b + ", c=" + v1.c);
306 }
307
308 @ForceInline
309 __ValueFactory static MyValue2 setX(MyValue2 v, int x) {
310 v.x = x;
311 return v;
312 }
313
314 @ForceInline
315 __ValueFactory static MyValue2 setY(MyValue2 v, byte y) {
316 v.y = y;
317 return v;
318 }
319
320 @ForceInline
321 __ValueFactory static MyValue2 setV1(MyValue2 v, MyValue2Inline v1) {
322 v.v1 = v1;
323 return v;
324 }
325 }
326
327 __ByValue final class MyValue3Inline {
328 final float f7;
329 final double f8;
330
331 private MyValue3Inline() {
332 this.f7 = 0;
333 this.f8 = 0;
334 }
335
336 @ForceInline
337 __ValueFactory static MyValue3Inline setF7(MyValue3Inline v, float f7) {
338 v.f7 = f7;
339 return v;
340 }
341
342 @ForceInline
343 __ValueFactory static MyValue3Inline setF8(MyValue3Inline v, double f8) {
344 v.f8 = f8;
345 return v;
346 }
347
348 @ForceInline
349 __ValueFactory public static MyValue3Inline createDefault() {
350 return __MakeDefault MyValue3Inline();
351 }
352
353 @ForceInline
354 public static MyValue3Inline createWithFieldsInline(float f7, double f8) {
355 MyValue3Inline v = createDefault();
356 v = setF7(v, f7);
357 v = setF8(v, f8);
358 return v;
359 }
360 }
361
362 // Value type definition to stress test return of a value in registers
363 // (uses all registers of calling convention on x86_64)
364 __ByValue final class MyValue3 {
365 final char c;
366 final byte bb;
367 final short s;
368 final int i;
369 final long l;
370 final Object o;
371 final float f1;
372 final double f2;
373 final float f3;
374 final double f4;
375 final float f5;
376 final double f6;
377 final MyValue3Inline v1;
378
379 private MyValue3() {
380 this.c = 0;
381 this.bb = 0;
382 this.s = 0;
383 this.i = 0;
384 this.l = 0;
385 this.o = null;
386 this.f1 = 0;
387 this.f2 = 0;
388 this.f3 = 0;
389 this.f4 = 0;
390 this.f5 = 0;
391 this.f6 = 0;
392 this.v1 = MyValue3Inline.createDefault();
393 }
394
395 @ForceInline
396 __ValueFactory static MyValue3 setC(MyValue3 v, char c) {
397 v.c = c;
398 return v;
399 }
400
401 @ForceInline
402 __ValueFactory static MyValue3 setBB(MyValue3 v, byte bb) {
403 v.bb = bb;
404 return v;
405 }
406
407 @ForceInline
408 __ValueFactory static MyValue3 setS(MyValue3 v, short s) {
409 v.s = s;
410 return v;
411 }
412
448
449 @ForceInline
450 __ValueFactory static MyValue3 setF4(MyValue3 v, double f4) {
451 v.f4 = f4;
452 return v;
453 }
454
455 @ForceInline
456 __ValueFactory static MyValue3 setF5(MyValue3 v, float f5) {
457 v.f5 = f5;
458 return v;
459 }
460
461 @ForceInline
462 __ValueFactory static MyValue3 setF6(MyValue3 v, double f6) {
463 v.f6 = f6;
464 return v;
465 }
466
467 @ForceInline
468 __ValueFactory static MyValue3 setV1(MyValue3 v, MyValue3Inline v1) {
469 v.v1 = v1;
470 return v;
471 }
472
473 @ForceInline
474 __ValueFactory public static MyValue3 createDefault() {
475 return __MakeDefault MyValue3();
476 }
477
478 @ForceInline
479 public static MyValue3 create() {
480 java.util.Random r = Utils.getRandomInstance();
481 MyValue3 v = createDefault();
482 v = setC(v, (char)r.nextInt());
483 v = setBB(v, (byte)r.nextInt());
484 v = setS(v, (short)r.nextInt());
485 v = setI(v, r.nextInt());
486 v = setL(v, r.nextLong());
487 v = setO(v, new Object());
488 v = setF1(v, r.nextFloat());
489 v = setF2(v, r.nextDouble());
490 v = setF3(v, r.nextFloat());
491 v = setF4(v, r.nextDouble());
492 v = setF5(v, r.nextFloat());
493 v = setF6(v, r.nextDouble());
494 v = setV1(v, MyValue3Inline.createWithFieldsInline(r.nextFloat(), r.nextDouble()));
495 return v;
496 }
497
498 @DontInline
499 public static MyValue3 createDontInline() {
500 return create();
501 }
502
503 @ForceInline
504 public static MyValue3 copy(MyValue3 other) {
505 MyValue3 v = createDefault();
506 v = setC(v, other.c);
507 v = setBB(v, other.bb);
508 v = setS(v, other.s);
509 v = setI(v, other.i);
510 v = setL(v, other.l);
511 v = setO(v, other.o);
512 v = setF1(v, other.f1);
513 v = setF2(v, other.f2);
514 v = setF3(v, other.f3);
515 v = setF4(v, other.f4);
516 v = setF5(v, other.f5);
517 v = setF6(v, other.f6);
518 v = setV1(v, other.v1);
519 return v;
520 }
521
522 @DontInline
523 public void verify(MyValue3 other) {
524 Asserts.assertEQ(c, other.c);
525 Asserts.assertEQ(bb, other.bb);
526 Asserts.assertEQ(s, other.s);
527 Asserts.assertEQ(i, other.i);
528 Asserts.assertEQ(l, other.l);
529 Asserts.assertEQ(o, other.o);
530 Asserts.assertEQ(f1, other.f1);
531 Asserts.assertEQ(f2, other.f2);
532 Asserts.assertEQ(f3, other.f3);
533 Asserts.assertEQ(f4, other.f4);
534 Asserts.assertEQ(f5, other.f5);
535 Asserts.assertEQ(f6, other.f6);
536 Asserts.assertEQ(v1.f7, other.v1.f7);
537 Asserts.assertEQ(v1.f8, other.v1.f8);
538 }
539 }
540
541 // Value type definition with too many fields to return in registers
542 __ByValue final class MyValue4 {
543 final MyValue3 v1;
544 final MyValue3 v2;
545
546 private MyValue4() {
547 this.v1 = MyValue3.createDefault();
548 this.v2 = MyValue3.createDefault();
549 }
550
551 @ForceInline
552 __ValueFactory static MyValue4 setV1(MyValue4 v, MyValue3 v1) {
553 v.v1 = v1;
554 return v;
555 }
556
557 @ForceInline
558 __ValueFactory static MyValue4 setV2(MyValue4 v, MyValue3 v2) {
559 v.v2 = v2;
560 return v;
561 }
562
563 @ForceInline
564 __ValueFactory public static MyValue4 createDefault() {
565 return __MakeDefault MyValue4();
1021 Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1));
1022 Asserts.assertEQ(val2.hash(), MyValue2.createWithFieldsInline(rI + 1, true).hash());
1023 Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1));
1024 }
1025
1026 // Test folding of constant value type fields
1027 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
1028 public long test22() {
1029 // This should be constant folded
1030 return val5.hash() + val5.v3.hash();
1031 }
1032
1033 @DontCompile
1034 public void test22_verifier(boolean warmup) {
1035 long result = test22();
1036 Asserts.assertEQ(result, val5.hash() + val5.v3.hash());
1037 }
1038
1039 // Test OSR compilation
1040 @Test()
1041 @Slow
1042 public long test23() {
1043 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
1044 MyValue1[] va = new MyValue1[Math.abs(rI) % 3];
1045 for (int i = 0; i < va.length; ++i) {
1046 va[i] = MyValue1.createWithFieldsInline(rI, rL);
1047 }
1048 long result = 0;
1049 // Long loop to trigger OSR compilation
1050 for (int i = 0 ; i < 100_000; ++i) {
1051 // Reference local value type in interpreter state
1052 result = v.hash();
1053 for (int j = 0; j < va.length; ++j) {
1054 result += va[j].hash();
1055 }
1056 }
1057 return result;
1058 }
1059
1060 @DontCompile
1061 public void test23_verifier(boolean warmup) {
1695
1696 // Test allocation elimination of unused object with initialized value type field
1697 @Test(failOn = ALLOC + LOAD + STORE + LOOP)
1698 public void test56(boolean deopt) {
1699 TestClass56 unused = new TestClass56();
1700 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
1701 unused.v = v;
1702 if (deopt) {
1703 // uncommon trap
1704 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test56"));
1705 }
1706 }
1707
1708 @DontCompile
1709 public void test56_verifier(boolean warmup) {
1710 test56(!warmup);
1711 }
1712
1713 // Test loop peeling
1714 @Test(failOn = ALLOC + LOAD + STORE)
1715 @Slow
1716 public void test57() {
1717 MyValue1 v = MyValue1.createWithFieldsInline(0, 1);
1718 // Trigger OSR compilation and loop peeling
1719 for (int i = 0; i < 100_000; ++i) {
1720 if (v.x != i || v.y != i + 1) {
1721 // Uncommon trap
1722 throw new RuntimeException("test57 failed");
1723 }
1724 v = MyValue1.createWithFieldsInline(i + 1, i + 2);
1725 }
1726 }
1727
1728 @DontCompile
1729 public void test57_verifier(boolean warmup) {
1730 test57();
1731 }
1732
1733 // Test loop peeling and unrolling
1734 @Test()
1735 @Slow
1736 public void test58() {
1737 MyValue1 v1 = MyValue1.createWithFieldsInline(0, 0);
1738 MyValue1 v2 = MyValue1.createWithFieldsInline(1, 1);
1739 // Trigger OSR compilation and loop peeling
1740 for (int i = 0; i < 100_000; ++i) {
1741 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) {
1742 // Uncommon trap
1743 throw new RuntimeException("test58 failed");
1744 }
1745 v1 = MyValue1.createWithFieldsInline(2*(i+1), 0);
1746 v2 = MyValue1.createWithFieldsInline(i+2, i+2);
1747 }
1748 }
1749
1750 @DontCompile
1751 public void test58_verifier(boolean warmup) {
1752 test58();
1753 }
1754
1755 // When calling a method on __Value, passing fields as arguments is impossible
2592 vt = MyValue3.setI(vt, (int)vt.c);
2593 // vt is not equal to staticVal3, so C2 should not re-use the oop
2594 va[0] = vt;
2595 staticVal3 = vt;
2596 vt.verify(staticVal3);
2597 return vt;
2598 }
2599
2600 @DontCompile
2601 public void test92_verifier(boolean warmup) {
2602 staticVal3 = MyValue3.create();
2603 MyValue3[] va = new MyValue3[1];
2604 MyValue3 vt = test92(va);
2605 Asserts.assertEQ(staticVal3.i, (int)staticVal3.c);
2606 Asserts.assertEQ(va[0].i, (int)staticVal3.c);
2607 Asserts.assertEQ(vt.i, (int)staticVal3.c);
2608 }
2609
2610 // Test correct handling of __Value merges through PhiNodes
2611 @Test()
2612 @Slow
2613 public long test93() throws Throwable {
2614 // Create a new value type
2615 final MethodHandle dvt = MethodHandleBuilder.loadCode(MethodHandles.lookup(), "createValueType",
2616 MethodType.methodType(ValueType.forClass(ValueCapableClass1.class).valueClass()),
2617 CODE -> {
2618 CODE.
2619 iconst_1().
2620 anewarray(ValueType.forClass(ValueCapableClass1.class).valueClass()).
2621 iconst_0().
2622 vaload().
2623 vreturn();
2624 });
2625 // Box the value type
2626 final MethodHandle box = MethodHandleBuilder.loadCode(MethodHandles.lookup(), "boxValueType",
2627 MethodType.methodType(ValueCapableClass1.class, ValueType.forClass(ValueCapableClass1.class).valueClass()),
2628 CODE -> {
2629 CODE.
2630 vload(0).
2631 vbox(ValueCapableClass1.class).
2632 areturn();
3059 public void test105_verifier(boolean warmup) throws Throwable {
3060 test105_i++;
3061 long hash = test105();
3062 boolean b = (test105_i % 100) == 0;
3063 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+test105_i * (b ? 1 : -1), b).hash());
3064 }
3065
3066
3067 // OSR compilation with __Value local
3068 @DontCompile
3069 public __Value test106_init() {
3070 return MyValue1.createWithFieldsInline(rI, rL);
3071 }
3072
3073 @DontCompile
3074 public __Value test106_body() {
3075 return MyValue1.createWithFieldsInline(rI, rL);
3076 }
3077
3078 @Test()
3079 @Slow
3080 public __Value test106() throws Throwable {
3081 __Value vt = test106_init();
3082 for (int i = 0; i < 50_000; i++) {
3083 if (i % 2 == 1) {
3084 vt = test106_body();
3085 }
3086 }
3087 return vt;
3088 }
3089
3090 @DontCompile
3091 public void test106_verifier(boolean warmup) throws Throwable {
3092 test106();
3093 }
3094
3095 // ========== Test infrastructure ==========
3096
3097 // User defined settings
3098 private static final boolean SKIP_SLOW = Boolean.parseBoolean(System.getProperty("SkipSlow", "false"));
3099 private static final boolean PRINT_TIMES = Boolean.parseBoolean(System.getProperty("PrintTimes", "false"));
3100 private static final boolean VERIFY_IR = Boolean.parseBoolean(System.getProperty("VerifyIR", "true"));
3101 private static final boolean VERIFY_VM = Boolean.parseBoolean(System.getProperty("VerifyVM", "false"));
3102 private static final String TESTLIST = System.getProperty("Testlist", "");
3103 private static final int WARMUP = Integer.parseInt(System.getProperty("Warmup", "251"));
3104
3105 // Pre defined settings
3106 private static final List<String> defaultFlags = Arrays.asList(
3107 "-XX:-BackgroundCompilation", "-XX:CICompilerCount=1",
3108 "-XX:+PrintCompilation", "-XX:+PrintInlining", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
3109 "-XX:CompileCommand=quiet",
3110 "-XX:CompileCommand=compileonly,java.lang.invoke.*::*",
3111 "-XX:CompileCommand=compileonly,java.lang.Long::sum",
3112 "-XX:CompileCommand=compileonly,java.lang.Object::<init>",
3113 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
3114 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*",
3115 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2Inline::*",
3116 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue3::*",
3117 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue3Inline::*",
3118 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue4::*",
3119 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueCapableClass2_*::*",
3120 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
3121 "-XX:CompileCommand=inline,java.lang.__Value::hashCode");
3122 private static final List<String> verifyFlags = Arrays.asList(
3123 "-XX:+VerifyOops", "-XX:+VerifyStack", "-XX:+VerifyLastFrame", "-XX:+VerifyBeforeGC", "-XX:+VerifyAfterGC",
3124 "-XX:+VerifyDuringGC", "-XX:+VerifyAdapterSharing", "-XX:+StressValueTypeReturnedAsFields");
3125
3126 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
3127 private static final int ValueTypePassFieldsAsArgsOn = 0x1;
3128 private static final int ValueTypePassFieldsAsArgsOff = 0x2;
3129 private static final int ValueTypeArrayFlattenOn = 0x4;
3130 private static final int ValueTypeArrayFlattenOff = 0x8;
3131 private static final int ValueTypeReturnedAsFieldsOn = 0x10;
3132 private static final int ValueTypeReturnedAsFieldsOff = 0x20;
3133 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | ValueTypeReturnedAsFieldsOn;
3134 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
3135 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
3136 private static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields");
3137 private static final int COMP_LEVEL_ANY = -2;
3138 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
3139 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
3140 private static final boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
3141 private static final boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
3142 private static final boolean XCOMP = Platform.isComp();
3143
3144 // Regular expressions used to match nodes in the PrintIdeal output
3145 private static final String START = "(\\d+\\t(.*";
3146 private static final String MID = ".*)+\\t===.*";
3147 private static final String END = ")|";
3148 private static final String ALLOC = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END;
3149 private static final String ALLOCA = "(.*precise klass \\[Qcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END;
3150 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
3151 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END;
3152 private static final String LOADK = START + "LoadK" + MID + END;
3153 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
3154 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END;
3155 private static final String LOOP = START + "Loop" + MID + "" + END;
3156 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END;
3157 private static final String RETURN = START + "Return" + MID + "returns" + END;
3158 private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END;
3159 private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END;
3160 private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END;
3161 private static final String CALL = START + "CallStaticJava" + MID + END;
3162 private static final String STOREVALUETYPEFIELDS = START + "CallStaticJava" + MID + "store_value_type_fields" + END;
3163 private static final String SCOBJ = "(.*# ScObj.*" + END;
3164
3165 static {
3166 List<String> list = null;
3167 if (!TESTLIST.isEmpty()) {
3168 list = Arrays.asList(TESTLIST.split(","));
3169 }
3170 // Gather all test methods and put them in Hashtable
3171 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
3172 Test[] annos = m.getAnnotationsByType(Test.class);
3173 if (annos.length != 0 &&
3174 (list == null || list.contains(m.getName())) &&
3175 !(SKIP_SLOW && m.isAnnotationPresent(Slow.class))) {
3176 tests.put("ValueTypeTestBench::" + m.getName(), m);
3177 }
3178 }
3179 }
3180
3181 private static void execute_vm() throws Throwable {
3182 Asserts.assertFalse(tests.isEmpty(), "no tests to execute");
3183 ArrayList<String> args = new ArrayList<String>(defaultFlags);
3184 if (VERIFY_VM) {
3185 args.addAll(verifyFlags);
3186 }
3187 // Run tests in own process and verify output
3188 args.add(ValueTypeTestBench.class.getName());
3189 args.add("run");
3190 // Spawn process with default JVM options from the test's run command
3191 String[] vmInputArgs = InputArguments.getVmInputArgs();
3192 String[] cmds = Arrays.copyOf(vmInputArgs, vmInputArgs.length + args.size());
3193 System.arraycopy(args.toArray(), 0, cmds, vmInputArgs.length, args.size());
3194 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds);
3195 // If ideal graph printing is enabled/supported, verify output
3196 String output = oa.getOutput();
3197 oa.shouldHaveExitValue(0);
3198 boolean verifyIR = VERIFY_IR && output.contains("PrintIdeal enabled") &&
3199 !output.contains("ValueTypePassFieldsAsArgs is not supported on this platform");
3200 if (verifyIR) {
3201 parseOutput(output);
3202 } else {
3203 System.out.println(output);
3204 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
3205 }
3206 }
3207
3208 public static void main(String[] args) throws Throwable {
3209 if (args.length == 0) {
3210 // Spawn a new VM instance
3211 execute_vm();
3212 } else {
3213 // Execute tests
3214 ValueTypeTestBench bench = new ValueTypeTestBench();
3215 bench.run();
3216 }
3217 }
3218
3219 private static void parseOutput(String output) throws Exception {
3220 Pattern comp_re = Pattern.compile("\\n\\s+\\d+\\s+\\d+\\s+(%| )(s| )(!| )b(n| )\\s+\\S+\\.(?<name>[^.]+::\\S+)\\s+(?<osr>@ \\d+\\s+)?[(]\\d+ bytes[)]\\n");
3221 Matcher m = comp_re.matcher(output);
3222 Map<String,String> compilations = new LinkedHashMap<>();
3223 int prev = 0;
3224 String methodName = null;
3225 while (m.find()) {
3226 if (prev == 0) {
3227 // Print header
3228 System.out.print(output.substring(0, m.start()+1));
3229 } else if (methodName != null) {
3230 compilations.put(methodName, output.substring(prev, m.start()+1));
3231 }
3232 if (m.group("osr") != null) {
3233 methodName = null;
3234 } else {
3235 methodName = m.group("name");
3236 }
3237 prev = m.end();
3238 }
3239 if (prev == 0) {
3328 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true);
3329 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false);
3330 WHITE_BOX.testSetDontInlineMethod(m, true);
3331 }
3332 if (m.isAnnotationPresent(ForceInline.class)) {
3333 WHITE_BOX.testSetForceInlineMethod(m, true);
3334 } else if (m.isAnnotationPresent(DontInline.class)) {
3335 WHITE_BOX.testSetDontInlineMethod(m, true);
3336 }
3337 }
3338 }
3339
3340 public void run() throws Exception {
3341 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
3342 System.out.println("PrintIdeal enabled");
3343 }
3344 System.out.format("rI = %d, rL = %d\n", rI, rL);
3345 setup(this.getClass().getDeclaredMethods());
3346 setup(MyValue1.class.getDeclaredMethods());
3347 setup(MyValue2.class.getDeclaredMethods());
3348 setup(MyValue2Inline.class.getDeclaredMethods());
3349 setup(MyValue3.class.getDeclaredMethods());
3350 setup(MyValue3Inline.class.getDeclaredMethods());
3351 setup(MyValue4.class.getDeclaredMethods());
3352
3353 // Compile class initializers
3354 WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION);
3355 WHITE_BOX.enqueueInitializerForCompilation(MyValue1.class, COMP_LEVEL_FULL_OPTIMIZATION);
3356 WHITE_BOX.enqueueInitializerForCompilation(MyValue2.class, COMP_LEVEL_FULL_OPTIMIZATION);
3357 WHITE_BOX.enqueueInitializerForCompilation(MyValue2Inline.class, COMP_LEVEL_FULL_OPTIMIZATION);
3358 WHITE_BOX.enqueueInitializerForCompilation(MyValue3.class, COMP_LEVEL_FULL_OPTIMIZATION);
3359 WHITE_BOX.enqueueInitializerForCompilation(MyValue3Inline.class, COMP_LEVEL_FULL_OPTIMIZATION);
3360 WHITE_BOX.enqueueInitializerForCompilation(MyValue4.class, COMP_LEVEL_FULL_OPTIMIZATION);
3361
3362 // Execute tests
3363 TreeMap<Long, String> durations = PRINT_TIMES ? new TreeMap<Long, String>() : null;
3364 for (Method test : tests.values()) {
3365 long startTime = System.nanoTime();
3366 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class);
3367 // Warmup using verifier method
3368 Warmup anno = test.getAnnotation(Warmup.class);
3369 int warmup = anno == null ? WARMUP : anno.value();
3370 for (int i = 0; i < warmup; ++i) {
3371 verifier.invoke(this, true);
3372 }
3373 // Trigger compilation
3374 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION);
3375 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
3376 // Check result
3377 verifier.invoke(this, false);
3378 if (PRINT_TIMES) {
3379 long endTime = System.nanoTime();
3380 long duration = (endTime - startTime);
3381 durations.put(duration, test.getName());
3382 }
3383 }
3384
3385 // Print execution times
3386 if (PRINT_TIMES) {
3387 System.out.println("\n\nTest execution times:");
3388 for (Map.Entry<Long, String> entry : durations.entrySet()) {
3389 System.out.format("%-10s%15d ns\n", entry.getValue() + ":", entry.getKey());
3390 }
3391 }
3392 }
3393 }
3394
3395 // Mark method as test
3396 @Retention(RetentionPolicy.RUNTIME)
3397 @Repeatable(Tests.class)
3398 @interface Test {
3399 // Regular expression used to match forbidden IR nodes
3400 // in the C2 IR emitted for this test.
3401 String failOn() default "";
3402 // Regular expressions used to match and count IR nodes.
3403 String[] match() default { };
3404 int[] matchCount() default { };
3405 int valid() default ValueTypeTestBench.AllFlags;
3406 }
3407
3408 @Retention(RetentionPolicy.RUNTIME)
3409 @interface Tests {
3410 Test[] value();
3411 }
3412
3413 // Force method inlining during compilation
3414 @Retention(RetentionPolicy.RUNTIME)
3415 @interface ForceInline { }
3416
3417 // Prevent method inlining during compilation
3418 @Retention(RetentionPolicy.RUNTIME)
3419 @interface DontInline { }
3420
3421 // Prevent method compilation
3422 @Retention(RetentionPolicy.RUNTIME)
3423 @interface DontCompile { }
3424
3425 // Number of warmup iterations
3426 @Retention(RetentionPolicy.RUNTIME)
3427 @interface Warmup {
3428 int value();
3429 }
3430
3431 // Mark test as slow
3432 @Retention(RetentionPolicy.RUNTIME)
3433 @interface Slow { }
|