< prev index next >

test/compiler/valhalla/valuetypes/ValueTypeTestBench.java

Print this page




  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


< prev index next >