11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 // 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.internal.misc:+open
31 * @modules java.base/jvm.internal.value
32 * @compile -XDenableValueTypes ValueCapableClass1.java ValueCapableClass2.java ValueTypeTestBench.java
33 * @run main ClassFileInstaller sun.hotspot.WhiteBox
34 * @run main ClassFileInstaller jdk.test.lib.Platform
35 * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
36 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+VerifyAdapterSharing
37 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten
38 * compiler.valhalla.valuetypes.ValueTypeTestBench
39 * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
40 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation
41 * -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueArrayFlatten
42 * compiler.valhalla.valuetypes.ValueTypeTestBench
43 * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
44 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+AlwaysIncrementalInline
45 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten
46 * compiler.valhalla.valuetypes.ValueTypeTestBench
47 */
48
49 package compiler.valhalla.valuetypes;
50
51 import compiler.whitebox.CompilerWhiteBoxTest;
52 import jdk.internal.misc.Unsafe;
53 import jdk.test.lib.Asserts;
54 import jdk.test.lib.Platform;
55 import jdk.test.lib.process.ProcessTools;
56 import jdk.test.lib.process.OutputAnalyzer;
57 import jdk.test.lib.Utils;
58 import sun.hotspot.WhiteBox;
59
60 import java.lang.annotation.Retention;
61 import java.lang.annotation.RetentionPolicy;
62 import java.lang.annotation.Repeatable;
63 import java.lang.invoke.*;
64 import java.lang.reflect.Method;
65 import java.util.ArrayList;
66 import java.util.Arrays;
67 import java.util.Hashtable;
68 import java.util.List;
69 import java.util.regex.Matcher;
70 import java.util.regex.Pattern;
71 import jdk.experimental.value.*;
72
73 // Test value types
74 __ByValue final class MyValue1 {
75 static int s;
76 static final long sf = ValueTypeTestBench.rL;
77 final int x;
78 final long y;
79 final short z;
80 final MyValue2 v1;
81 final MyValue2 v2;
82 static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true);
83 final int c;
84
85 private MyValue1(int x, long y, short z, MyValue2 v1, MyValue2 v2, int c) {
86 s = x;
87 this.x = x;
88 this.y = y;
89 this.z = z;
90 this.v1 = v1;
91 this.v2 = v2;
92 this.c = c;
93 }
94
95 private MyValue1() {
96 s = 0;
97 this.x = 0;
98 this.y = 0;
99 this.z = 0;
100 this.v1 = MyValue2.createDefaultInline();
101 this.v2 = MyValue2.createDefaultInline();
102 this.c = 0;
103 }
104
105 @DontInline
106 __ValueFactory static MyValue1 createDefaultDontInline() {
107 return __MakeDefault MyValue1();
108 }
109
110 @ForceInline
111 __ValueFactory static MyValue1 createDefaultInline() {
112 return __MakeDefault MyValue1();
113 }
114
115 @DontInline
116 static MyValue1 createWithFieldsDontInline(int x, long y) {
117 MyValue1 v = createDefaultInline();
118 v = setX(v, x);
119 v = setY(v, y);
120 v = setZ(v, (short)x);
121 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y));
122 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y));
123 v = setC(v, ValueTypeTestBench.rI);
124 return v;
125 }
126
127 @ForceInline
128 static MyValue1 createWithFieldsInline(int x, long y) {
129 MyValue1 v = createDefaultInline();
130 v = setX(v, x);
131 v = setY(v, y);
132 v = setZ(v, (short)x);
133 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y));
134 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y));
135 v = setC(v, ValueTypeTestBench.rI);
136 return v;
137 }
138
139 @ForceInline
140 public long hash() {
141 return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash();
142 }
143
144 @DontCompile
145 public long hashInterpreted() {
146 return s + sf + x + y + z + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted();
147 }
148
149 @ForceInline
150 public void print() {
151 System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z + ", v1[");
152 v1.print();
153 System.out.print("], v2[");
154 v2.print();
155 System.out.print("], v3[");
156 v3.print();
157 System.out.print("], c=" + c);
158 }
159
160 @ForceInline
161 __ValueFactory static MyValue1 setX(MyValue1 v, int x) {
162 v.x = x;
163 return v;
164 }
165
166 @ForceInline
167 __ValueFactory static MyValue1 setY(MyValue1 v, long y) {
168 v.y = y;
169 return v;
170 }
171
172 @ForceInline
173 __ValueFactory static MyValue1 setZ(MyValue1 v, short z) {
174 v.z = z;
175 return v;
176 }
177
178 @ForceInline
179 __ValueFactory static MyValue1 setC(MyValue1 v, int c) {
180 v.c = c;
181 return v;
182 }
183
184 @ForceInline
185 __ValueFactory static MyValue1 setV1(MyValue1 v, MyValue2 v1) {
186 v.v1 = v1;
187 return v;
188 }
189
190 @ForceInline
191 __ValueFactory static MyValue1 setV2(MyValue1 v, MyValue2 v2) {
192 v.v2 = v2;
193 return v;
194 }
195 }
196
197 __ByValue final class MyValue2 {
198 final int x;
460 Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1);
461 }
462
463 // Merge value types created in a loop (not inlined)
464 @Test(failOn = ALLOC + STORE + TRAP)
465 public long test10(int x, long y) {
466 MyValue1 v = MyValue1.createWithFieldsDontInline(x, y);
467 for (int i = 0; i < 10; ++i) {
468 v = MyValue1.createWithFieldsDontInline(v.x + 1, v.y + 1);
469 }
470 return v.hash();
471 }
472
473 @DontCompile
474 public void test10_verifier(boolean warmup) {
475 long result = test10(rI, rL);
476 Asserts.assertEQ(result, hash(rI + 10, rL + 10));
477 }
478
479 // Merge value types created in a loop (inlined)
480 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
481 public long test11(int x, long y) {
482 MyValue1 v = MyValue1.createWithFieldsInline(x, y);
483 for (int i = 0; i < 10; ++i) {
484 v = MyValue1.createWithFieldsInline(v.x + 1, v.y + 1);
485 }
486 return v.hash();
487 }
488
489 @DontCompile
490 public void test11_verifier(boolean warmup) {
491 long result = test11(rI, rL);
492 Asserts.assertEQ(result, hash(rI + 10, rL + 10));
493 }
494
495 // Test loop with uncommon trap referencing a value type
496 @Test(match = {TRAP, SCOBJ}, matchCount = {1, -1 /* at least 1 */}, failOn = LOAD)
497 public long test12(boolean b) {
498 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
499 MyValue1[] va = new MyValue1[Math.abs(rI) % 10];
500 for (int i = 0; i < va.length; ++i) {
639
640 @DontCompile
641 public long sumValue(MyValue1 v, MyValue1 dummy) {
642 return v.hash();
643 }
644
645 @DontCompile
646 public void test19_verifier(boolean warmup) {
647 long result = test19();
648 Asserts.assertEQ(result, hash());
649 }
650
651 // Create a value type (array) in compiled code and pass it to the
652 // interpreter via a call. The value type is live at the uncommon
653 // trap: verify that deoptimization causes the value type to be
654 // correctly allocated.
655 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE)
656 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {2}, failOn = LOAD)
657 public long test20(boolean deopt) {
658 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
659 MyValue1[] va = new MyValue1[3];
660 if (deopt) {
661 // uncommon trap
662 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20"));
663 }
664 return v.hashInterpreted() + va[0].hashInterpreted() +
665 va[1].hashInterpreted() + va[2].hashInterpreted();
666 }
667
668 @DontCompile
669 public void test20_verifier(boolean warmup) {
670 MyValue1[] va = new MyValue1[42];
671 long result = test20(!warmup);
672 Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash());
673 }
674
675 // Value type fields in regular object
676 MyValue1 val1;
677 MyValue2 val2;
678 final MyValue1 val3;
679 static MyValue1 val4;
680 static final MyValue1 val5 = MyValue1.createWithFieldsInline(rI, rL);
681
682 // Test value type fields in objects
683 @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP))
684 public long test21(int x, long y) {
685 // Compute hash of value type fields
686 long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
687 // Update fields
688 val1 = MyValue1.createWithFieldsInline(x, y);
689 val2 = MyValue2.createWithFieldsInline(x, true);
690 val4 = MyValue1.createWithFieldsInline(x, y);
1143 }
1144
1145 // Test returning a value type array received from the interpreter
1146 @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP)
1147 public MyValue1[] test44(MyValue1[] va) {
1148 return va;
1149 }
1150
1151 @DontCompile
1152 public void test44_verifier(boolean warmup) {
1153 MyValue1[] va = new MyValue1[10];
1154 for (int i = 0; i < 10; ++i) {
1155 va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i);
1156 }
1157 va = test44(va);
1158 for (int i = 0; i < 10; ++i) {
1159 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
1160 }
1161 }
1162
1163 @Test(failOn = (TRAP))
1164 public MyValue1[] test45(boolean b) {
1165 MyValue1[] va;
1166 if (b) {
1167 va = new MyValue1[5];
1168 for (int i = 0; i < 5; ++i) {
1169 va[i] = MyValue1.createWithFieldsInline(rI, rL);
1170 }
1171 } else {
1172 va = new MyValue1[10];
1173 for (int i = 0; i < 10; ++i) {
1174 va[i] = MyValue1.createWithFieldsInline(rI + i, rL + i);
1175 }
1176 }
1177 long sum = va[0].hashInterpreted();
1178 if (b) {
1179 va[0] = MyValue1.createWithFieldsDontInline(rI, sum);
1180 } else {
1181 va[0] = MyValue1.createWithFieldsDontInline(rI + 1, sum + 1);
1182 }
1194 va = test45(false);
1195 Asserts.assertEQ(va.length, 10);
1196 Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1));
1197 for (int i = 1; i < 10; ++i) {
1198 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
1199 }
1200 }
1201
1202 // Test creation of value type array with single element
1203 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD + LOOP + TRAP))
1204 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOCA + LOAD + LOOP + TRAP))
1205 public MyValue1 test46() {
1206 MyValue1[] va = new MyValue1[1];
1207 return va[0];
1208 }
1209
1210 @DontCompile
1211 public void test46_verifier(boolean warmup) {
1212 MyValue1[] va = new MyValue1[1];
1213 MyValue1 v = test46();
1214 Asserts.assertEQ(v.hash(), va[0].hash());
1215 }
1216
1217 // Test default initialization of value type arrays
1218 @Test(failOn = LOAD)
1219 public MyValue1[] test47(int len) {
1220 return new MyValue1[len];
1221 }
1222
1223 @DontCompile
1224 public void test47_verifier(boolean warmup) {
1225 int len = Math.abs(rI % 10);
1226 MyValue1[] va = new MyValue1[len];
1227 MyValue1[] var = test47(len);
1228 for (int i = 0; i < len; ++i) {
1229 Asserts.assertEQ(va[i].hash(), var[i].hash());
1230 }
1231 }
1232
1233 // Test creation of value type array with zero length
1234 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
1235 public MyValue1[] test48() {
1236 return new MyValue1[0];
1237 }
1238
1239 @DontCompile
1240 public void test48_verifier(boolean warmup) {
1241 MyValue1[] va = test48();
1242 Asserts.assertEQ(va.length, 0);
1243 }
1244
1245 static MyValue1[] test49_va;
1246
1247 // Test that value type array loaded from field has correct type
1248 @Test(failOn = (LOOP))
1249 public long test49() {
1259 }
1260
1261 // test vdefault
1262 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP)
1263 public long test50() {
1264 MyValue2 v = MyValue2.createDefaultInline();
1265 return v.hash();
1266 }
1267
1268 @DontCompile
1269 public void test50_verifier(boolean warmup) {
1270 long result = test50();
1271 Asserts.assertEQ(result, MyValue2.createDefaultInline().hash());
1272 }
1273
1274 // test vdefault
1275 @Test(failOn = ALLOC + STORE + LOOP + TRAP)
1276 public long test51() {
1277 MyValue1 v1 = MyValue1.createDefaultInline();
1278 MyValue1 v2 = MyValue1.createDefaultDontInline();
1279 return v1.hash() + v2.hash();
1280 }
1281
1282 @DontCompile
1283 public void test51_verifier(boolean warmup) {
1284 long result = test51();
1285 Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hash());
1286 }
1287
1288 // test vwithfield
1289 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP)
1290 public long test52() {
1291 MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
1292 return v.hash();
1293 }
1294
1295 @DontCompile
1296 public void test52_verifier(boolean warmup) {
1297 long result = test52();
1298 Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, true).hash());
1299 }
1300
1301 // test vwithfield
1302 @Test(failOn = ALLOC + STORE + LOOP + TRAP)
1303 public long test53() {
1304 MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL);
1305 MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL);
1417 public void test58() {
1418 MyValue1 v1 = MyValue1.createWithFieldsInline(0, 0);
1419 MyValue1 v2 = MyValue1.createWithFieldsInline(1, 1);
1420 // Trigger OSR compilation and loop peeling
1421 for (int i = 0; i < 100_000; ++i) {
1422 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) {
1423 // Uncommon trap
1424 throw new RuntimeException("test58 failed");
1425 }
1426 v1 = MyValue1.createWithFieldsInline(2*(i+1), 0);
1427 v2 = MyValue1.createWithFieldsInline(i+2, i+2);
1428 }
1429 }
1430
1431 @DontCompile
1432 public void test58_verifier(boolean warmup) {
1433 test58();
1434 }
1435
1436 // When calling a method on __Value, passing fields as arguments is impossible
1437 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount={1, 0})
1438 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = STORE + LOAD)
1439 public String test59(MyValue1 v) {
1440 return v.toString();
1441 }
1442
1443 @DontCompile
1444 public void test59_verifier(boolean warmup) {
1445 boolean failed = false;
1446 try {
1447 test59(val1);
1448 failed = true;
1449 } catch (UnsupportedOperationException uoe) {
1450 }
1451 Asserts.assertFalse(failed);
1452 }
1453
1454 // Same as above, but the method on __Value is inlined
1455 // hashCode allocates an exception so can't really check the graph shape
1456 @Test()
1457 public int test60(MyValue1 v) {
1458 return v.hashCode();
1654 private static final int ValueTypeArrayFlattenOn = 0x4;
1655 private static final int ValueTypeArrayFlattenOff = 0x8;
1656 private static final int AlwaysIncrementalInlineOff = 0x10;
1657 private static final int AlwaysIncrementalInlineOn = 0x20;
1658 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | AlwaysIncrementalInlineOff | AlwaysIncrementalInlineOn;
1659 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
1660 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
1661 private static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline");
1662 private static final int COMP_LEVEL_ANY = -1;
1663 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
1664 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
1665 private static final int WARMUP = 251;
1666 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
1667 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
1668 private static boolean XCOMP = Platform.isComp();
1669
1670 // Regular expressions used to match nodes in the PrintIdeal output
1671 private static final String START = "(\\d+\\t(.*";
1672 private static final String MID = ".*)+\\t===.*";
1673 private static final String END = ")|";
1674 private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
1675 private static final String ALLOCA = START + "CallStaticJava" + MID + "_new_array_Java" + END;
1676 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
1677 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END;
1678 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
1679 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END;
1680 private static final String LOOP = START + "Loop" + MID + "" + END;
1681 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap" + END;
1682 private static final String RETURN = START + "Return" + MID + "returns" + END;
1683 private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END;
1684 private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END;
1685 private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END;
1686 private static final String SCOBJ = "(.*# ScObj.*" + END;
1687
1688 static {
1689 // Gather all test methods and put them in Hashtable
1690 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
1691 Test[] annos = m.getAnnotationsByType(Test.class);
1692 if (annos.length != 0) {
1693 tests.put("ValueTypeTestBench::" + m.getName(), m);
1694 }
1695 }
1696 }
1697
1698 private static void execute_vm(String... args) throws Throwable {
1699 Asserts.assertFalse(tests.isEmpty(), "no tests to execute");
1700 ArrayList<String> all_args = new ArrayList(List.of(args));
1701 // Run tests in own process and verify output
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 // 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.internal.misc:+open
31 * @compile -XDenableValueTypes ValueCapableClass1.java ValueCapableClass2.java ValueTypeTestBench.java
32 * @run main ClassFileInstaller sun.hotspot.WhiteBox
33 * @run main ClassFileInstaller jdk.test.lib.Platform
34 * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
35 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+VerifyAdapterSharing
36 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten
37 * -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1 -XX:+FullGCALotWithValueTypes
38 * compiler.valhalla.valuetypes.ValueTypeTestBench
39 * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
40 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation
41 * -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueArrayFlatten
42 * compiler.valhalla.valuetypes.ValueTypeTestBench
43 * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
44 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+AlwaysIncrementalInline
45 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten
46 * -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
47 * compiler.valhalla.valuetypes.ValueTypeTestBench
48 */
49
50 package compiler.valhalla.valuetypes;
51
52 import compiler.whitebox.CompilerWhiteBoxTest;
53 import jdk.internal.misc.Unsafe;
54 import jdk.test.lib.Asserts;
55 import jdk.test.lib.Platform;
56 import jdk.test.lib.process.ProcessTools;
57 import jdk.test.lib.process.OutputAnalyzer;
58 import jdk.test.lib.Utils;
59 import sun.hotspot.WhiteBox;
60
61 import java.lang.annotation.Retention;
62 import java.lang.annotation.RetentionPolicy;
63 import java.lang.annotation.Repeatable;
64 import java.lang.invoke.*;
65 import java.lang.reflect.Method;
66 import java.util.ArrayList;
67 import java.util.Arrays;
68 import java.util.Hashtable;
69 import java.util.List;
70 import java.util.regex.Matcher;
71 import java.util.regex.Pattern;
72 import jdk.experimental.value.*;
73
74 // Test value types
75 __ByValue final class MyValue1 {
76 static int s;
77 static final long sf = ValueTypeTestBench.rL;
78 final int x;
79 final long y;
80 final short z;
81 final Integer o;
82 final int[] oa;
83 final MyValue2 v1;
84 final MyValue2 v2;
85 static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true);
86 final int c;
87
88 private MyValue1(int x, long y, short z, Integer o, int[] oa, MyValue2 v1, MyValue2 v2, int c) {
89 s = x;
90 this.x = x;
91 this.y = y;
92 this.z = z;
93 this.o = o;
94 this.oa = oa;
95 this.v1 = v1;
96 this.v2 = v2;
97 this.c = c;
98 }
99
100 private MyValue1() {
101 s = 0;
102 this.x = 0;
103 this.y = 0;
104 this.z = 0;
105 this.o = null;
106 this.oa = null;
107 this.v1 = MyValue2.createDefaultInline();
108 this.v2 = MyValue2.createDefaultInline();
109 this.c = 0;
110 }
111
112 @DontInline
113 __ValueFactory static MyValue1 createDefaultDontInline() {
114 return __MakeDefault MyValue1();
115 }
116
117 @ForceInline
118 __ValueFactory static MyValue1 createDefaultInline() {
119 return __MakeDefault MyValue1();
120 }
121
122 @DontInline
123 static MyValue1 createWithFieldsDontInline(int x, long y) {
124 MyValue1 v = createDefaultInline();
125 v = setX(v, x);
126 v = setY(v, y);
127 v = setZ(v, (short)x);
128 v = setO(v, new Integer(x));
129 int[] oa = {x};
130 v = setOA(v, oa);
131 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y));
132 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y));
133 v = setC(v, ValueTypeTestBench.rI);
134 return v;
135 }
136
137 @ForceInline
138 static MyValue1 createWithFieldsInline(int x, long y) {
139 MyValue1 v = createDefaultInline();
140 v = setX(v, x);
141 v = setY(v, y);
142 v = setZ(v, (short)x);
143 v = setO(v, new Integer(x));
144 int[] oa = {x};
145 v = setOA(v, oa);
146 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y));
147 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y));
148 v = setC(v, ValueTypeTestBench.rI);
149 return v;
150 }
151
152 // Hash only primitive and value type fields to avoid NullPointerException
153 @ForceInline
154 public long hashPrimitive() {
155 return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash();
156 }
157
158 @ForceInline
159 public long hash() {
160 return hashPrimitive() + o + oa[0];
161 }
162
163 @DontCompile
164 public long hashInterpreted() {
165 return s + sf + x + y + z + o + oa[0] + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted();
166 }
167
168 @ForceInline
169 public void print() {
170 System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z + ", o=" + (o != null ? (Integer)o : "NULL") + ", v1[");
171 v1.print();
172 System.out.print("], v2[");
173 v2.print();
174 System.out.print("], v3[");
175 v3.print();
176 System.out.print("], c=" + c);
177 }
178
179 @ForceInline
180 __ValueFactory static MyValue1 setX(MyValue1 v, int x) {
181 v.x = x;
182 return v;
183 }
184
185 @ForceInline
186 __ValueFactory static MyValue1 setY(MyValue1 v, long y) {
187 v.y = y;
188 return v;
189 }
190
191 @ForceInline
192 __ValueFactory static MyValue1 setZ(MyValue1 v, short z) {
193 v.z = z;
194 return v;
195 }
196
197 @ForceInline
198 __ValueFactory static MyValue1 setO(MyValue1 v, Integer o) {
199 v.o = o;
200 return v;
201 }
202
203 @ForceInline
204 __ValueFactory static MyValue1 setOA(MyValue1 v, int[] oa) {
205 v.oa = oa;
206 return v;
207 }
208
209 @ForceInline
210 __ValueFactory static MyValue1 setC(MyValue1 v, int c) {
211 v.c = c;
212 return v;
213 }
214
215 @ForceInline
216 __ValueFactory static MyValue1 setV1(MyValue1 v, MyValue2 v1) {
217 v.v1 = v1;
218 return v;
219 }
220
221 @ForceInline
222 __ValueFactory static MyValue1 setV2(MyValue1 v, MyValue2 v2) {
223 v.v2 = v2;
224 return v;
225 }
226 }
227
228 __ByValue final class MyValue2 {
229 final int x;
491 Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1);
492 }
493
494 // Merge value types created in a loop (not inlined)
495 @Test(failOn = ALLOC + STORE + TRAP)
496 public long test10(int x, long y) {
497 MyValue1 v = MyValue1.createWithFieldsDontInline(x, y);
498 for (int i = 0; i < 10; ++i) {
499 v = MyValue1.createWithFieldsDontInline(v.x + 1, v.y + 1);
500 }
501 return v.hash();
502 }
503
504 @DontCompile
505 public void test10_verifier(boolean warmup) {
506 long result = test10(rI, rL);
507 Asserts.assertEQ(result, hash(rI + 10, rL + 10));
508 }
509
510 // Merge value types created in a loop (inlined)
511 @Test(failOn = ALLOC + LOAD + STORE + TRAP)
512 public long test11(int x, long y) {
513 MyValue1 v = MyValue1.createWithFieldsInline(x, y);
514 for (int i = 0; i < 10; ++i) {
515 v = MyValue1.createWithFieldsInline(v.x + 1, v.y + 1);
516 }
517 return v.hash();
518 }
519
520 @DontCompile
521 public void test11_verifier(boolean warmup) {
522 long result = test11(rI, rL);
523 Asserts.assertEQ(result, hash(rI + 10, rL + 10));
524 }
525
526 // Test loop with uncommon trap referencing a value type
527 @Test(match = {TRAP, SCOBJ}, matchCount = {1, -1 /* at least 1 */}, failOn = LOAD)
528 public long test12(boolean b) {
529 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
530 MyValue1[] va = new MyValue1[Math.abs(rI) % 10];
531 for (int i = 0; i < va.length; ++i) {
670
671 @DontCompile
672 public long sumValue(MyValue1 v, MyValue1 dummy) {
673 return v.hash();
674 }
675
676 @DontCompile
677 public void test19_verifier(boolean warmup) {
678 long result = test19();
679 Asserts.assertEQ(result, hash());
680 }
681
682 // Create a value type (array) in compiled code and pass it to the
683 // interpreter via a call. The value type is live at the uncommon
684 // trap: verify that deoptimization causes the value type to be
685 // correctly allocated.
686 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE)
687 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {2}, failOn = LOAD)
688 public long test20(boolean deopt) {
689 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
690 MyValue2[] va = new MyValue2[3];
691 if (deopt) {
692 // uncommon trap
693 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20"));
694 }
695 return v.hashInterpreted() + va[0].hashInterpreted() +
696 va[1].hashInterpreted() + va[2].hashInterpreted();
697 }
698
699 @DontCompile
700 public void test20_verifier(boolean warmup) {
701 MyValue2[] va = new MyValue2[42];
702 long result = test20(!warmup);
703 Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash());
704 }
705
706 // Value type fields in regular object
707 MyValue1 val1;
708 MyValue2 val2;
709 final MyValue1 val3;
710 static MyValue1 val4;
711 static final MyValue1 val5 = MyValue1.createWithFieldsInline(rI, rL);
712
713 // Test value type fields in objects
714 @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP))
715 public long test21(int x, long y) {
716 // Compute hash of value type fields
717 long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
718 // Update fields
719 val1 = MyValue1.createWithFieldsInline(x, y);
720 val2 = MyValue2.createWithFieldsInline(x, true);
721 val4 = MyValue1.createWithFieldsInline(x, y);
1174 }
1175
1176 // Test returning a value type array received from the interpreter
1177 @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP)
1178 public MyValue1[] test44(MyValue1[] va) {
1179 return va;
1180 }
1181
1182 @DontCompile
1183 public void test44_verifier(boolean warmup) {
1184 MyValue1[] va = new MyValue1[10];
1185 for (int i = 0; i < 10; ++i) {
1186 va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i);
1187 }
1188 va = test44(va);
1189 for (int i = 0; i < 10; ++i) {
1190 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
1191 }
1192 }
1193
1194 // Merge value type arrays created from two branches
1195 @Test(failOn = (TRAP))
1196 public MyValue1[] test45(boolean b) {
1197 MyValue1[] va;
1198 if (b) {
1199 va = new MyValue1[5];
1200 for (int i = 0; i < 5; ++i) {
1201 va[i] = MyValue1.createWithFieldsInline(rI, rL);
1202 }
1203 } else {
1204 va = new MyValue1[10];
1205 for (int i = 0; i < 10; ++i) {
1206 va[i] = MyValue1.createWithFieldsInline(rI + i, rL + i);
1207 }
1208 }
1209 long sum = va[0].hashInterpreted();
1210 if (b) {
1211 va[0] = MyValue1.createWithFieldsDontInline(rI, sum);
1212 } else {
1213 va[0] = MyValue1.createWithFieldsDontInline(rI + 1, sum + 1);
1214 }
1226 va = test45(false);
1227 Asserts.assertEQ(va.length, 10);
1228 Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1));
1229 for (int i = 1; i < 10; ++i) {
1230 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
1231 }
1232 }
1233
1234 // Test creation of value type array with single element
1235 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD + LOOP + TRAP))
1236 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOCA + LOAD + LOOP + TRAP))
1237 public MyValue1 test46() {
1238 MyValue1[] va = new MyValue1[1];
1239 return va[0];
1240 }
1241
1242 @DontCompile
1243 public void test46_verifier(boolean warmup) {
1244 MyValue1[] va = new MyValue1[1];
1245 MyValue1 v = test46();
1246 Asserts.assertEQ(v.hashPrimitive(), va[0].hashPrimitive());
1247 }
1248
1249 // Test default initialization of value type arrays
1250 @Test(failOn = LOAD)
1251 public MyValue1[] test47(int len) {
1252 return new MyValue1[len];
1253 }
1254
1255 @DontCompile
1256 public void test47_verifier(boolean warmup) {
1257 int len = Math.abs(rI % 10);
1258 MyValue1[] va = new MyValue1[len];
1259 MyValue1[] var = test47(len);
1260 for (int i = 0; i < len; ++i) {
1261 Asserts.assertEQ(va[i].hashPrimitive(), var[i].hashPrimitive());
1262 }
1263 }
1264
1265 // Test creation of value type array with zero length
1266 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
1267 public MyValue1[] test48() {
1268 return new MyValue1[0];
1269 }
1270
1271 @DontCompile
1272 public void test48_verifier(boolean warmup) {
1273 MyValue1[] va = test48();
1274 Asserts.assertEQ(va.length, 0);
1275 }
1276
1277 static MyValue1[] test49_va;
1278
1279 // Test that value type array loaded from field has correct type
1280 @Test(failOn = (LOOP))
1281 public long test49() {
1291 }
1292
1293 // test vdefault
1294 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP)
1295 public long test50() {
1296 MyValue2 v = MyValue2.createDefaultInline();
1297 return v.hash();
1298 }
1299
1300 @DontCompile
1301 public void test50_verifier(boolean warmup) {
1302 long result = test50();
1303 Asserts.assertEQ(result, MyValue2.createDefaultInline().hash());
1304 }
1305
1306 // test vdefault
1307 @Test(failOn = ALLOC + STORE + LOOP + TRAP)
1308 public long test51() {
1309 MyValue1 v1 = MyValue1.createDefaultInline();
1310 MyValue1 v2 = MyValue1.createDefaultDontInline();
1311 return v1.hashPrimitive() + v2.hashPrimitive();
1312 }
1313
1314 @DontCompile
1315 public void test51_verifier(boolean warmup) {
1316 long result = test51();
1317 Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hashPrimitive());
1318 }
1319
1320 // test vwithfield
1321 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP)
1322 public long test52() {
1323 MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
1324 return v.hash();
1325 }
1326
1327 @DontCompile
1328 public void test52_verifier(boolean warmup) {
1329 long result = test52();
1330 Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, true).hash());
1331 }
1332
1333 // test vwithfield
1334 @Test(failOn = ALLOC + STORE + LOOP + TRAP)
1335 public long test53() {
1336 MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL);
1337 MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL);
1449 public void test58() {
1450 MyValue1 v1 = MyValue1.createWithFieldsInline(0, 0);
1451 MyValue1 v2 = MyValue1.createWithFieldsInline(1, 1);
1452 // Trigger OSR compilation and loop peeling
1453 for (int i = 0; i < 100_000; ++i) {
1454 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) {
1455 // Uncommon trap
1456 throw new RuntimeException("test58 failed");
1457 }
1458 v1 = MyValue1.createWithFieldsInline(2*(i+1), 0);
1459 v2 = MyValue1.createWithFieldsInline(i+2, i+2);
1460 }
1461 }
1462
1463 @DontCompile
1464 public void test58_verifier(boolean warmup) {
1465 test58();
1466 }
1467
1468 // When calling a method on __Value, passing fields as arguments is impossible
1469 @Test(failOn = ALLOC + STORE + LOAD)
1470 public String test59(MyValue1 v) {
1471 return v.toString();
1472 }
1473
1474 @DontCompile
1475 public void test59_verifier(boolean warmup) {
1476 boolean failed = false;
1477 try {
1478 test59(val1);
1479 failed = true;
1480 } catch (UnsupportedOperationException uoe) {
1481 }
1482 Asserts.assertFalse(failed);
1483 }
1484
1485 // Same as above, but the method on __Value is inlined
1486 // hashCode allocates an exception so can't really check the graph shape
1487 @Test()
1488 public int test60(MyValue1 v) {
1489 return v.hashCode();
1685 private static final int ValueTypeArrayFlattenOn = 0x4;
1686 private static final int ValueTypeArrayFlattenOff = 0x8;
1687 private static final int AlwaysIncrementalInlineOff = 0x10;
1688 private static final int AlwaysIncrementalInlineOn = 0x20;
1689 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | AlwaysIncrementalInlineOff | AlwaysIncrementalInlineOn;
1690 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
1691 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
1692 private static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline");
1693 private static final int COMP_LEVEL_ANY = -1;
1694 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
1695 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
1696 private static final int WARMUP = 251;
1697 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
1698 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
1699 private static boolean XCOMP = Platform.isComp();
1700
1701 // Regular expressions used to match nodes in the PrintIdeal output
1702 private static final String START = "(\\d+\\t(.*";
1703 private static final String MID = ".*)+\\t===.*";
1704 private static final String END = ")|";
1705 private static final String ALLOC = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*nop.*\\R)*.*_new_instance_Java" + END;
1706 private static final String ALLOCA = "(.*precise klass \\[Qcompiler/valhalla/valuetypes/MyValue.*\\R(.*nop.*\\R)*.*_new_array_Java" + END;
1707 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
1708 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END;
1709 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
1710 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END;
1711 private static final String LOOP = START + "Loop" + MID + "" + END;
1712 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END;
1713 private static final String RETURN = START + "Return" + MID + "returns" + END;
1714 private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END;
1715 private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END;
1716 private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END;
1717 private static final String SCOBJ = "(.*# ScObj.*" + END;
1718
1719 static {
1720 // Gather all test methods and put them in Hashtable
1721 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
1722 Test[] annos = m.getAnnotationsByType(Test.class);
1723 if (annos.length != 0) {
1724 tests.put("ValueTypeTestBench::" + m.getName(), m);
1725 }
1726 }
1727 }
1728
1729 private static void execute_vm(String... args) throws Throwable {
1730 Asserts.assertFalse(tests.isEmpty(), "no tests to execute");
1731 ArrayList<String> all_args = new ArrayList(List.of(args));
1732 // Run tests in own process and verify output
|