< prev index next >

test/compiler/valhalla/valuetypes/ValueTypeTestBench.java

Print this page




  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.management.InputArguments;
  56 import jdk.test.lib.Platform;
  57 import jdk.test.lib.process.ProcessTools;
  58 import jdk.test.lib.process.OutputAnalyzer;
  59 import jdk.test.lib.Utils;
  60 import sun.hotspot.WhiteBox;
  61 
  62 import java.lang.annotation.Retention;
  63 import java.lang.annotation.RetentionPolicy;
  64 import java.lang.annotation.Repeatable;
  65 import java.lang.invoke.*;
  66 import java.lang.reflect.Method;
  67 import java.util.ArrayList;
  68 import java.util.Arrays;
  69 import java.util.Hashtable;

  70 import java.util.List;

  71 import java.util.regex.Matcher;
  72 import java.util.regex.Pattern;
  73 import jdk.experimental.value.*;
  74 
  75 // Test value types
  76 __ByValue final class MyValue1 {
  77     static int s;
  78     static final long sf = ValueTypeTestBench.rL;
  79     final int x;
  80     final long y;
  81     final short z;
  82     final Integer o;
  83     final int[] oa;
  84     final MyValue2 v1;
  85     final MyValue2 v2;
  86     static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true);
  87     final int c;
  88 
  89     private MyValue1(int x, long y, short z, Integer o, int[] oa, MyValue2 v1, MyValue2 v2, int c) {
  90         s = x;


 284 
 285     @ForceInline
 286     __ValueFactory static MyValue2 setY(MyValue2 v, byte y) {
 287         v.y = y;
 288         return v;
 289     }
 290 
 291     @ForceInline
 292     __ValueFactory static MyValue2 setC(MyValue2 v, long c) {
 293         v.c = c;
 294         return v;
 295     }
 296 
 297     @ForceInline
 298     __ValueFactory static MyValue2 setB(MyValue2 v, boolean b) {
 299         v.b = b;
 300         return v;
 301     }
 302 }
 303 


















































































































































































































































 304 public class ValueTypeTestBench {
 305     // Print ideal graph after execution of each test
 306     private static final boolean PRINT_GRAPH = true;
 307 
 308     // Random test values
 309     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
 310     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
 311 
 312     public ValueTypeTestBench() {
 313         val3 = MyValue1.createWithFieldsInline(rI, rL);
 314     }
 315 
 316     // MethodHandles and value-capable class instance needed for testing vbox/vunbox
 317     private static final MethodHandle vccUnboxLoadLongMH = generateVCCUnboxLoadLongMH();
 318     private static final MethodHandle vccUnboxLoadIntMH = generateVCCUnboxLoadIntMH();
 319     private static final MethodHandle vccUnboxBoxMH = generateVCCUnboxBoxMH();
 320     private static final MethodHandle vccUnboxBoxLoadIntMH = generateVCCUnboxBoxLoadIntMH();
 321     private static final MethodHandle nullvccUnboxLoadLongMH = generateNullVCCUnboxLoadLongMH();
 322     private static final MethodHandle objectUnboxLoadLongMH = generateObjectUnboxLoadLongMH();
 323     private static final MethodHandle objectBoxMH = generateObjectBoxMH();


1488     @Test()
1489     public int test60(MyValue1 v) {
1490         return v.hashCode();
1491     }
1492 
1493     @DontCompile
1494     public void test60_verifier(boolean warmup) {
1495         boolean failed = false;
1496         try {
1497             test60(val1);
1498             failed = true;
1499         } catch (UnsupportedOperationException uoe) {
1500         }
1501         Asserts.assertFalse(failed);
1502     }
1503 
1504     /* The compiler is supposed to determine that the value to be
1505      * unboxed in nullcvvUnboxLoadLong is always null. Therefore, the
1506      * compiler generates only the path leading to the corresponding
1507      * uncommon trap. */
1508     @Test(valid = AlwaysIncrementalInlineOff, failOn = RETURN)
1509     @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
1510     public long test61() throws Throwable {
1511         return (long)nullvccUnboxLoadLongMH.invokeExact();
1512     }
1513 
1514     @DontCompile
1515     public void test61_verifier(boolean warmup) throws Throwable {
1516         try {
1517             long result = test61();
1518             throw new RuntimeException("Test failed because no exception was thrown");
1519         } catch (NullPointerException e) {
1520         }
1521     }
1522 
1523     public static MethodHandle generateNullVCCUnboxLoadLongMH() {
1524         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
1525                 "nullvccUnboxLoadLong",
1526                 MethodType.methodType(long.class),
1527                 CODE -> {
1528                     CODE.
1529                     aconst_null().
1530                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
1531                     getfield(ValueCapableClass1.class, "t", "J").
1532                     lreturn();
1533                 }
1534                 );
1535     }
1536 
1537     /* The compiler is supposed to determine that the allocated
1538      * ValueCapableClass1 instance is never null (and therefore not
1539      * generate a null check). Also, the source and target type match
1540      * (known at compile time), so no type check is needed either.*/
1541     @Test(valid = AlwaysIncrementalInlineOff, failOn = NPE)
1542     @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
1543     public long test62() throws Throwable {
1544         return (long)checkedvccUnboxLoadLongMH.invokeExact();
1545     }
1546 
1547     @DontCompile
1548     public void test62_verifier(boolean warmup) throws Throwable {
1549         long result = test62();
1550         Asserts.assertEQ(result, 17L);
1551     }
1552 
1553     public static MethodHandle generateCheckedVCCUnboxLoadLongMH() {
1554         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
1555                 "checkedVCCUnboxLoadLongMH",
1556                 MethodType.methodType(long.class),
1557                 CODE -> {
1558                     CODE.
1559                     invokestatic(ValueCapableClass1.class, "createInline", "()Lcompiler/valhalla/valuetypes/ValueCapableClass1;", false).
1560                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
1561                     vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J").
1562                     lreturn();
1563                 }
1564                 );
1565     }
1566 
1567     /* The compiler is supposed to emit a runtime null check because
1568      * it does not have enough information to determine that the value
1569      * to be unboxed is not null (and either that it is null). The
1570      * declared type of the */
1571     @Test(valid = AlwaysIncrementalInlineOff, match = {NPE}, matchCount = {1})
1572     @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
1573     public long test63(ValueCapableClass1 vcc) throws Throwable {
1574         return (long)vccUnboxLoadLongMH.invokeExact(vcc);
1575     }
1576 
1577     @DontCompile
1578     public void test63_verifier(boolean warmup) throws Throwable {
1579         try {
1580             long result = test63(null);
1581             throw new RuntimeException("Test failed because no exception was thrown");
1582         } catch (NullPointerException e) {
1583         }
1584     }
1585 
1586     /* Attempt to unbox an object that is not a subclass of the
1587      * value-capable class derived from the value type specified in
1588      * the vunbox bytecode. */
1589     @Test(valid = AlwaysIncrementalInlineOff, match = {NPE,CCE}, matchCount = {1,1})
1590     @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
1591     public long test64(Object vcc) throws Throwable {
1592         return (long)objectUnboxLoadLongMH.invokeExact(vcc);
1593     }
1594 
1595     @DontCompile
1596     public void test64_verifier(boolean warmup) throws Throwable {
1597         try {
1598             long result = test64(new Object());
1599             throw new RuntimeException("Test failed because no exception was thrown");
1600         } catch (ClassCastException e) {
1601         }
1602 
1603         try {
1604             long result = test64(vcc2);
1605             throw new RuntimeException("Test failed because no exception was thrown");
1606         } catch (ClassCastException e) {
1607         }
1608 
1609         Asserts.assertEQ(test64(vcc), rL);
1610     }
1611 
1612     private static MethodHandle generateObjectUnboxLoadLongMH() {
1613         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
1614                 "ObjectUnboxLoadLong",
1615                 MethodType.methodType(long.class, Object.class),
1616                 CODE -> {
1617                     CODE.
1618                     aload_0().
1619                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
1620                     vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J").
1621                     lreturn();
1622                 }
1623                 );
1624     }
1625 
1626     /* Generate an if-then-else construct with one path that contains
1627      * an invalid boxing operation (boxing of a value-type to a
1628      * non-matching value-capable class).*/
1629     @Test(valid = AlwaysIncrementalInlineOff, match = {NPE,CCE}, matchCount = {2,3})
1630     @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
1631     public long test65(Object obj, boolean warmup) throws Throwable {
1632         return (long)objectBoxMH.invokeExact(obj, warmup);
1633     }
1634 
1635     @DontCompile
1636     public void test65_verifier(boolean warmup) throws Throwable {
1637         try {
1638             long result = test65(vcc2, true);
1639             throw new RuntimeException("Test failed because no exception was thrown");
1640         } catch (ClassCastException e) {
1641         }
1642 
1643         Asserts.assertEQ(test65(vcc, true), rL);
1644 
1645         try {
1646             long result = test65(vcc2, false);
1647             throw new RuntimeException("Test failed because no exception was thrown");
1648         } catch (ClassCastException e) {
1649         }
1650 


1661                 MethodType.methodType(long.class, Object.class, boolean.class),
1662                 CODE -> {
1663                     CODE.
1664                     iload_1().
1665                     iconst_1().
1666                     if_icmpne((short)14).
1667                     aload_0().
1668                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
1669                     vbox(ValueCapableClass1.class).
1670                     getfield(ValueCapableClass1.class, "t", "J").
1671                     lreturn().
1672                     aload_0().
1673                     vunbox(ValueType.forClass(ValueCapableClass2.class).valueClass()).
1674                     vbox(ValueCapableClass1.class).
1675                     getfield(ValueCapableClass1.class, "t", "J").
1676                     lreturn();
1677                 }
1678                 );
1679     }
1680 































































































































































































































1681     // ========== Test infrastructure ==========
1682 
1683     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
1684     private static final int ValueTypePassFieldsAsArgsOn = 0x1;
1685     private static final int ValueTypePassFieldsAsArgsOff = 0x2;
1686     private static final int ValueTypeArrayFlattenOn = 0x4;
1687     private static final int ValueTypeArrayFlattenOff = 0x8;
1688     private static final int AlwaysIncrementalInlineOff = 0x10;
1689     private static final int AlwaysIncrementalInlineOn = 0x20;
1690     static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | AlwaysIncrementalInlineOff | AlwaysIncrementalInlineOn;


1691     private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
1692     private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
1693     private static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline");

1694     private static final int COMP_LEVEL_ANY = -1;
1695     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
1696     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
1697     private static final int WARMUP = 251;
1698     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
1699     private static boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
1700     private static boolean XCOMP = Platform.isComp();
1701 
1702     // Regular expressions used to match nodes in the PrintIdeal output
1703     private static final String START = "(\\d+\\t(.*";
1704     private static final String MID = ".*)+\\t===.*";
1705     private static final String END = ")|";
1706     private static final String ALLOC  = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END;
1707     private static final String ALLOCA = "(.*precise klass \\[Qcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END;
1708     private static final String LOAD   = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
1709     private static final String LOADP  = START + "Load(P|N)" + MID + "valuetype\\*" + END;
1710     private static final String STORE  = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
1711     private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END;
1712     private static final String LOOP   = START + "Loop" + MID + "" + END;
1713     private static final String TRAP   = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END;
1714     private static final String RETURN = START + "Return" + MID + "returns" + END;
1715     private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END;
1716     private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END;
1717     private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END;

1718     private static final String SCOBJ = "(.*# ScObj.*" + END;
1719 
1720     static {
1721         // Gather all test methods and put them in Hashtable
1722         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
1723             Test[] annos = m.getAnnotationsByType(Test.class);
1724             if (annos.length != 0) {
1725                 tests.put("ValueTypeTestBench::" + m.getName(), m);
1726             }
1727         }
1728     }
1729 
1730     private static void execute_vm(String... args) throws Throwable {
1731         Asserts.assertFalse(tests.isEmpty(), "no tests to execute");
1732         ArrayList<String> all_args = new ArrayList(List.of(args));
1733         // Run tests in own process and verify output
1734         all_args.add(ValueTypeTestBench.class.getName());
1735         all_args.add("run");
1736         // Spawn process with default JVM options from the test's run command
1737         String[] vmInputArgs = InputArguments.getVmInputArgs();
1738         String[] cmds = Arrays.copyOf(vmInputArgs, vmInputArgs.length + all_args.size());
1739         System.arraycopy(all_args.toArray(), 0, cmds, vmInputArgs.length, all_args.size());
1740         OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds);
1741         // If ideal graph printing is enabled/supported, verify output
1742         String output = oa.getOutput();
1743         oa.shouldHaveExitValue(0);
1744         boolean verifyIR = output.contains("PrintIdeal enabled") &&
1745                 !output.contains("ValueTypePassFieldsAsArgs is not supported on this platform");
1746         if (verifyIR) {
1747             parseOutput(output);
1748         } else {
1749             System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
1750         }
1751     }
1752 
1753     public static void main(String[] args) throws Throwable {
1754         //tests.values().removeIf(p -> !p.getName().equals("test64")); // Run single test
1755         if (args.length == 0) {
1756             execute_vm("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-BackgroundCompilation",
1757                     "-XX:+PrintCompilation", "-XX:+PrintInlining", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",

1758                     "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
1759                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
1760                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*",
1761                     "-XX:CompileCommand=compileonly,java.lang.Object::<init>",
1762                     "-XX:CompileCommand=inline,java.lang.__Value::hashCode");

1763         } else {
1764             // Execute tests
1765             ValueTypeTestBench bench = new ValueTypeTestBench();
1766             bench.run();
1767         }
1768     }
1769 
1770     public static void parseOutput(String output) throws Exception {
1771         String split = "b        compiler.valhalla.valuetypes.";
1772         String[] compilations = output.split(split);





1773         // Print header
1774         System.out.println(compilations[0]);
1775         // Iterate over compilation output
1776         for (String graph : compilations) {
1777             String[] lines = graph.split("\\n");
1778             if (lines[0].contains("@")) {
1779                 continue; // Ignore OSR compilations
1780             }
1781             String testName = lines[0].split(" ")[0];














1782             Method test = tests.get(testName);
1783             if (test == null) {
1784                 // Skip helper methods
1785                 continue;
1786             }

1787             if (PRINT_GRAPH) {
1788                 System.out.println("\nGraph for " + graph);
1789             }
1790             // Parse graph using regular expressions to determine if it contains forbidden nodes
1791             Test[] annos = test.getAnnotationsByType(Test.class);
1792             Test anno = null;
1793             for (Test a : annos) {
1794                 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) {
1795                     assert anno == null;
1796                     anno = a;
1797                 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) {
1798                     assert anno == null;
1799                     anno = a;
1800                 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) {
1801                     assert anno == null;
1802                     anno = a;
1803                 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) {
1804                     assert anno == null;
1805                     anno = a;
1806                 } else if ((a.valid() & AlwaysIncrementalInlineOff) != 0 && !AlwaysIncrementalInline) {
1807                     assert anno == null;
1808                     anno = a;
1809                 } else if ((a.valid() & AlwaysIncrementalInlineOn) != 0 && AlwaysIncrementalInline) {






1810                     assert anno == null;
1811                     anno = a;
1812                 }
1813             }
1814             assert anno != null;
1815             String regexFail = anno.failOn();
1816             if (!regexFail.isEmpty()) {
1817                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
1818                 Matcher matcher = pattern.matcher(graph);
1819                 boolean found = matcher.find();
1820                 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : ""));
1821             }
1822             String[] regexMatch = anno.match();
1823             int[] matchCount = anno.matchCount();
1824             for (int i = 0; i < regexMatch.length; ++i) {
1825                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
1826                 Matcher matcher = pattern.matcher(graph);
1827                 int count = 0;
1828                 String nodes = "";
1829                 while (matcher.find()) {




  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:+ValueTypeReturnedAsFields -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:-ValueTypeReturnedAsFields -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:+ValueTypeReturnedAsFields -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.management.InputArguments;
  56 import jdk.test.lib.Platform;
  57 import jdk.test.lib.process.ProcessTools;
  58 import jdk.test.lib.process.OutputAnalyzer;
  59 import jdk.test.lib.Utils;
  60 import sun.hotspot.WhiteBox;
  61 
  62 import java.lang.annotation.Retention;
  63 import java.lang.annotation.RetentionPolicy;
  64 import java.lang.annotation.Repeatable;
  65 import java.lang.invoke.*;
  66 import java.lang.reflect.Method;
  67 import java.util.ArrayList;
  68 import java.util.Arrays;
  69 import java.util.Hashtable;
  70 import java.util.LinkedHashMap;
  71 import java.util.List;
  72 import java.util.Map;
  73 import java.util.regex.Matcher;
  74 import java.util.regex.Pattern;
  75 import jdk.experimental.value.*;
  76 
  77 // Test value types
  78 __ByValue final class MyValue1 {
  79     static int s;
  80     static final long sf = ValueTypeTestBench.rL;
  81     final int x;
  82     final long y;
  83     final short z;
  84     final Integer o;
  85     final int[] oa;
  86     final MyValue2 v1;
  87     final MyValue2 v2;
  88     static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true);
  89     final int c;
  90 
  91     private MyValue1(int x, long y, short z, Integer o, int[] oa, MyValue2 v1, MyValue2 v2, int c) {
  92         s = x;


 286 
 287     @ForceInline
 288     __ValueFactory static MyValue2 setY(MyValue2 v, byte y) {
 289         v.y = y;
 290         return v;
 291     }
 292 
 293     @ForceInline
 294     __ValueFactory static MyValue2 setC(MyValue2 v, long c) {
 295         v.c = c;
 296         return v;
 297     }
 298 
 299     @ForceInline
 300     __ValueFactory static MyValue2 setB(MyValue2 v, boolean b) {
 301         v.b = b;
 302         return v;
 303     }
 304 }
 305 
 306 // Value type definition to stress test return of a value in registers
 307 // (uses all registers of calling convention on x86_64)
 308 __ByValue final class MyValue3 {
 309     final boolean b;
 310     final char c;
 311     final byte bb;
 312     final short s;
 313     final int i1;
 314     final long l;
 315     final float f1;
 316     final double f2;
 317     final float f3;
 318     final double f4;
 319     final float f5;
 320     final double f6;
 321     final float f7;
 322     final double f8;
 323 
 324     private MyValue3(boolean b,
 325                      char c,
 326                      byte bb,
 327                      short s,
 328                      int i1,
 329                      long l,
 330                      float f1,
 331                      double f2,
 332                      float f3,
 333                      double f4,
 334                      float f5,
 335                      double f6,
 336                      float f7,
 337                      double f8) {
 338         this.b = b;
 339         this.c = c;
 340         this.bb = bb;
 341         this.s = s;
 342         this.i1 = i1;
 343         this.l = l;
 344         this.f1 = f1;
 345         this.f2 = f2;
 346         this.f3 = f3;
 347         this.f4 = f4;
 348         this.f5 = f5;
 349         this.f6 = f6;
 350         this.f7 = f7;
 351         this.f8 = f8;
 352     }
 353 
 354     private MyValue3() {
 355         this.b = false;
 356         this.c = 0;
 357         this.bb = 0;
 358         this.s = 0;
 359         this.i1 = 0;
 360         this.l = 0;
 361         this.f1 = 0;
 362         this.f2 = 0;
 363         this.f3 = 0;
 364         this.f4 = 0;
 365         this.f5 = 0;
 366         this.f6 = 0;
 367         this.f7 = 0;
 368         this.f8 = 0;
 369     }
 370 
 371     @ForceInline
 372     __ValueFactory static MyValue3 setB(MyValue3 v, boolean b) {
 373         v.b = b;
 374         return v;
 375     }
 376 
 377     @ForceInline
 378     __ValueFactory static MyValue3 setC(MyValue3 v, char c) {
 379         v.c = c;
 380         return v;
 381     }
 382 
 383     @ForceInline
 384     __ValueFactory static MyValue3 setBB(MyValue3 v, byte bb) {
 385         v.bb = bb;
 386         return v;
 387     }
 388 
 389     @ForceInline
 390     __ValueFactory static MyValue3 setS(MyValue3 v, short s) {
 391         v.s = s;
 392         return v;
 393     }
 394 
 395     @ForceInline
 396     __ValueFactory static MyValue3 setI1(MyValue3 v, int i1) {
 397         v.i1 = i1;
 398         return v;
 399     }
 400 
 401     @ForceInline
 402     __ValueFactory static MyValue3 setL(MyValue3 v, long l) {
 403         v.l = l;
 404         return v;
 405     }
 406 
 407     @ForceInline
 408     __ValueFactory static MyValue3 setF1(MyValue3 v, float f1) {
 409         v.f1 = f1;
 410         return v;
 411     }
 412 
 413     @ForceInline
 414     __ValueFactory static MyValue3 setF2(MyValue3 v, double f2) {
 415         v.f2 = f2;
 416         return v;
 417     }
 418 
 419     @ForceInline
 420     __ValueFactory static MyValue3 setF3(MyValue3 v, float f3) {
 421         v.f3 = f3;
 422         return v;
 423     }
 424 
 425     @ForceInline
 426     __ValueFactory static MyValue3 setF4(MyValue3 v, double f4) {
 427         v.f4 = f4;
 428         return v;
 429     }
 430 
 431     @ForceInline
 432     __ValueFactory static MyValue3 setF5(MyValue3 v, float f5) {
 433         v.f5 = f5;
 434         return v;
 435     }
 436 
 437     @ForceInline
 438     __ValueFactory static MyValue3 setF6(MyValue3 v, double f6) {
 439         v.f6 = f6;
 440         return v;
 441     }
 442 
 443     @ForceInline
 444     __ValueFactory static MyValue3 setF7(MyValue3 v, float f7) {
 445         v.f7 = f7;
 446         return v;
 447     }
 448 
 449     @ForceInline
 450     __ValueFactory static MyValue3 setF8(MyValue3 v, double f8) {
 451         v.f8 = f8;
 452         return v;
 453     }
 454 
 455     @ForceInline
 456     __ValueFactory public static MyValue3 createDefault() {
 457         return __MakeDefault MyValue3();
 458     }
 459 
 460     @ForceInline
 461     public static MyValue3 create() {
 462         java.util.Random r = Utils.getRandomInstance();
 463         MyValue3 v = createDefault();
 464         v = setB(v, r.nextBoolean());
 465         v = setC(v, (char)r.nextInt());
 466         v = setBB(v, (byte)r.nextInt());
 467         v = setS(v, (short)r.nextInt());
 468         v = setI1(v, r.nextInt());
 469         v = setL(v, r.nextLong());
 470         v = setF1(v, r.nextFloat());
 471         v = setF2(v, r.nextDouble());
 472         v = setF3(v, r.nextFloat());
 473         v = setF4(v, r.nextDouble());
 474         v = setF5(v, r.nextFloat());
 475         v = setF6(v, r.nextDouble());
 476         v = setF7(v, r.nextFloat());
 477         v = setF8(v, r.nextDouble());
 478         return v;
 479     }
 480 
 481     public void verify(MyValue3 other) {
 482         Asserts.assertEQ(b, other.b);
 483         Asserts.assertEQ(c, other.c);
 484         Asserts.assertEQ(bb, other.bb);
 485         Asserts.assertEQ(s, other.s);
 486         Asserts.assertEQ(i1, other.i1);
 487         Asserts.assertEQ(l, other.l);
 488         Asserts.assertEQ(f1, other.f1);
 489         Asserts.assertEQ(f2, other.f2);
 490         Asserts.assertEQ(f3, other.f3);
 491         Asserts.assertEQ(f4, other.f4);
 492         Asserts.assertEQ(f5, other.f5);
 493         Asserts.assertEQ(f6, other.f6);
 494         Asserts.assertEQ(f7, other.f7);
 495         Asserts.assertEQ(f8, other.f8);
 496     }
 497 }
 498 
 499 // Value type definition with too many fields to return in registers
 500 __ByValue final class MyValue4 {
 501     final MyValue3 v1;
 502     final MyValue3 v2;
 503 
 504     private MyValue4(MyValue3 v1, MyValue3 v2) {
 505         this.v1 = v1;
 506         this.v2 = v2;
 507     }
 508 
 509     private MyValue4() {
 510         this.v1 = MyValue3.createDefault();
 511         this.v2 = MyValue3.createDefault();
 512     }
 513 
 514     @ForceInline
 515     __ValueFactory static MyValue4 setV1(MyValue4 v, MyValue3 v1) {
 516         v.v1 = v1;
 517         return v;
 518     }
 519 
 520     @ForceInline
 521     __ValueFactory static MyValue4 setV2(MyValue4 v, MyValue3 v2) {
 522         v.v2 = v2;
 523         return v;
 524     }
 525 
 526     @ForceInline
 527     __ValueFactory public static MyValue4 createDefault() {
 528         return __MakeDefault MyValue4();
 529     }
 530 
 531     @ForceInline
 532     public static MyValue4 create() {
 533         MyValue4 v = createDefault();
 534         MyValue3 v1 = MyValue3.create();
 535         v = setV1(v, v1);
 536         MyValue3 v2 = MyValue3.create();
 537         v = setV2(v, v2);
 538         return v;
 539     }
 540 
 541     public void verify(MyValue4 other) {
 542         v1.verify(other.v1);
 543         v2.verify(other.v2);
 544     }
 545 }
 546 
 547 
 548 public class ValueTypeTestBench {
 549     // Print ideal graph after execution of each test
 550     private static final boolean PRINT_GRAPH = true;
 551 
 552     // Random test values
 553     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
 554     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
 555 
 556     public ValueTypeTestBench() {
 557         val3 = MyValue1.createWithFieldsInline(rI, rL);
 558     }
 559 
 560     // MethodHandles and value-capable class instance needed for testing vbox/vunbox
 561     private static final MethodHandle vccUnboxLoadLongMH = generateVCCUnboxLoadLongMH();
 562     private static final MethodHandle vccUnboxLoadIntMH = generateVCCUnboxLoadIntMH();
 563     private static final MethodHandle vccUnboxBoxMH = generateVCCUnboxBoxMH();
 564     private static final MethodHandle vccUnboxBoxLoadIntMH = generateVCCUnboxBoxLoadIntMH();
 565     private static final MethodHandle nullvccUnboxLoadLongMH = generateNullVCCUnboxLoadLongMH();
 566     private static final MethodHandle objectUnboxLoadLongMH = generateObjectUnboxLoadLongMH();
 567     private static final MethodHandle objectBoxMH = generateObjectBoxMH();


1732     @Test()
1733     public int test60(MyValue1 v) {
1734         return v.hashCode();
1735     }
1736 
1737     @DontCompile
1738     public void test60_verifier(boolean warmup) {
1739         boolean failed = false;
1740         try {
1741             test60(val1);
1742             failed = true;
1743         } catch (UnsupportedOperationException uoe) {
1744         }
1745         Asserts.assertFalse(failed);
1746     }
1747 
1748     /* The compiler is supposed to determine that the value to be
1749      * unboxed in nullcvvUnboxLoadLong is always null. Therefore, the
1750      * compiler generates only the path leading to the corresponding
1751      * uncommon trap. */
1752     @Test(failOn = RETURN)

1753     public long test61() throws Throwable {
1754         return (long)nullvccUnboxLoadLongMH.invokeExact();
1755     }
1756 
1757     @DontCompile
1758     public void test61_verifier(boolean warmup) throws Throwable {
1759         try {
1760             long result = test61();
1761             throw new RuntimeException("Test failed because no exception was thrown");
1762         } catch (NullPointerException e) {
1763         }
1764     }
1765 
1766     public static MethodHandle generateNullVCCUnboxLoadLongMH() {
1767         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
1768                 "nullvccUnboxLoadLong",
1769                 MethodType.methodType(long.class),
1770                 CODE -> {
1771                     CODE.
1772                     aconst_null().
1773                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
1774                     getfield(ValueCapableClass1.class, "t", "J").
1775                     lreturn();
1776                 }
1777                 );
1778     }
1779 
1780     /* The compiler is supposed to determine that the allocated
1781      * ValueCapableClass1 instance is never null (and therefore not
1782      * generate a null check). Also, the source and target type match
1783      * (known at compile time), so no type check is needed either.*/
1784     @Test(failOn = NPE)

1785     public long test62() throws Throwable {
1786         return (long)checkedvccUnboxLoadLongMH.invokeExact();
1787     }
1788 
1789     @DontCompile
1790     public void test62_verifier(boolean warmup) throws Throwable {
1791         long result = test62();
1792         Asserts.assertEQ(result, 17L);
1793     }
1794 
1795     public static MethodHandle generateCheckedVCCUnboxLoadLongMH() {
1796         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
1797                 "checkedVCCUnboxLoadLongMH",
1798                 MethodType.methodType(long.class),
1799                 CODE -> {
1800                     CODE.
1801                     invokestatic(ValueCapableClass1.class, "createInline", "()Lcompiler/valhalla/valuetypes/ValueCapableClass1;", false).
1802                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
1803                     vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J").
1804                     lreturn();
1805                 }
1806                 );
1807     }
1808 
1809     /* The compiler is supposed to emit a runtime null check because
1810      * it does not have enough information to determine that the value
1811      * to be unboxed is not null (and either that it is null). The
1812      * declared type of the */
1813     @Test(match = {NPE}, matchCount = {1})

1814     public long test63(ValueCapableClass1 vcc) throws Throwable {
1815         return (long)vccUnboxLoadLongMH.invokeExact(vcc);
1816     }
1817 
1818     @DontCompile
1819     public void test63_verifier(boolean warmup) throws Throwable {
1820         try {
1821             long result = test63(null);
1822             throw new RuntimeException("Test failed because no exception was thrown");
1823         } catch (NullPointerException e) {
1824         }
1825     }
1826 
1827     /* Attempt to unbox an object that is not a subclass of the
1828      * value-capable class derived from the value type specified in
1829      * the vunbox bytecode. */
1830     @Test(match = {NPE,CCE}, matchCount = {1,1})

1831     public long test64(Object vcc) throws Throwable {
1832         return (long)objectUnboxLoadLongMH.invokeExact(vcc);
1833     }
1834 
1835     @DontCompile
1836     public void test64_verifier(boolean warmup) throws Throwable {
1837         try {
1838             long result = test64(new Object());
1839             throw new RuntimeException("Test failed because no exception was thrown");
1840         } catch (ClassCastException e) {
1841         }
1842 
1843         try {
1844             long result = test64(vcc2);
1845             throw new RuntimeException("Test failed because no exception was thrown");
1846         } catch (ClassCastException e) {
1847         }
1848 
1849         Asserts.assertEQ(test64(vcc), rL);
1850     }
1851 
1852     private static MethodHandle generateObjectUnboxLoadLongMH() {
1853         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
1854                 "ObjectUnboxLoadLong",
1855                 MethodType.methodType(long.class, Object.class),
1856                 CODE -> {
1857                     CODE.
1858                     aload_0().
1859                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
1860                     vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J").
1861                     lreturn();
1862                 }
1863                 );
1864     }
1865 
1866     /* Generate an if-then-else construct with one path that contains
1867      * an invalid boxing operation (boxing of a value-type to a
1868      * non-matching value-capable class).*/
1869     @Test(match = {NPE,CCE}, matchCount = {2,3})

1870     public long test65(Object obj, boolean warmup) throws Throwable {
1871         return (long)objectBoxMH.invokeExact(obj, warmup);
1872     }
1873 
1874     @DontCompile
1875     public void test65_verifier(boolean warmup) throws Throwable {
1876         try {
1877             long result = test65(vcc2, true);
1878             throw new RuntimeException("Test failed because no exception was thrown");
1879         } catch (ClassCastException e) {
1880         }
1881 
1882         Asserts.assertEQ(test65(vcc, true), rL);
1883 
1884         try {
1885             long result = test65(vcc2, false);
1886             throw new RuntimeException("Test failed because no exception was thrown");
1887         } catch (ClassCastException e) {
1888         }
1889 


1900                 MethodType.methodType(long.class, Object.class, boolean.class),
1901                 CODE -> {
1902                     CODE.
1903                     iload_1().
1904                     iconst_1().
1905                     if_icmpne((short)14).
1906                     aload_0().
1907                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
1908                     vbox(ValueCapableClass1.class).
1909                     getfield(ValueCapableClass1.class, "t", "J").
1910                     lreturn().
1911                     aload_0().
1912                     vunbox(ValueType.forClass(ValueCapableClass2.class).valueClass()).
1913                     vbox(ValueCapableClass1.class).
1914                     getfield(ValueCapableClass1.class, "t", "J").
1915                     lreturn();
1916                 }
1917                 );
1918     }
1919 
1920     // Test deoptimization at call return with return value in registers
1921     @DontCompile
1922     public MyValue2 test66_interp(boolean deopt) {
1923         if (deopt) {
1924             // uncommon trap
1925             WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test66"));
1926         }
1927         return MyValue2.createWithFieldsInline(rI, true);
1928     }
1929 
1930     @Test()
1931     public MyValue2 test66(boolean flag) {
1932         return test66_interp(flag);
1933     }
1934 
1935     @DontCompile
1936     public void test66_verifier(boolean warmup) {
1937         MyValue2 result = test66(!warmup);
1938         MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
1939         Asserts.assertEQ(result.hash(), v.hash());
1940     }
1941 
1942     // Return value types in registers from interpreter -> compiled
1943     final MyValue3 test67_vt = MyValue3.create();
1944     @DontCompile
1945     public MyValue3 test67_interp() {
1946         return test67_vt;
1947     }
1948 
1949     MyValue3 test67_vt2;
1950     @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP)
1951     @Test(valid = ValueTypeReturnedAsFieldsOff)
1952     public void test67() {
1953         test67_vt2 = test67_interp();
1954     }
1955 
1956     @DontCompile
1957     public void test67_verifier(boolean warmup) {
1958         test67();
1959         test67_vt.verify(test67_vt2);
1960     }
1961 
1962     // Return value types in registers from compiled -> interpreter
1963     final MyValue3 test68_vt = MyValue3.create();
1964     @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + TRAP)
1965     @Test(valid = ValueTypeReturnedAsFieldsOff)
1966     public MyValue3 test68() {
1967         return test68_vt;
1968     }
1969 
1970     @DontCompile
1971     public void test68_verifier(boolean warmup) {
1972         MyValue3 vt = test68();
1973         test68_vt.verify(vt);
1974     }
1975 
1976     // Return value types in registers from compiled -> compiled
1977     final MyValue3 test69_vt = MyValue3.create();
1978     @DontInline
1979     public MyValue3 test69_comp() {
1980         return test69_vt;
1981     }
1982 
1983     MyValue3 test69_vt2;
1984     @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP)
1985     @Test(valid = ValueTypeReturnedAsFieldsOff)
1986     public void test69() {
1987         test69_vt2 = test69_comp();
1988     }
1989 
1990     @DontCompile
1991     public void test69_verifier(boolean warmup) throws Exception {
1992         Method helper_m = getClass().getDeclaredMethod("test69_comp");
1993         if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) {
1994             WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION);
1995             Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test69_comp not compiled");
1996         }
1997         test69();
1998         test69_vt.verify(test69_vt2);
1999     }
2000 
2001     // Same tests as above but with a value type that cannot be returned in registers
2002 
2003     // Return value types in registers from interpreter -> compiled
2004     final MyValue4 test70_vt = MyValue4.create();
2005     @DontCompile
2006     public MyValue4 test70_interp() {
2007         return test70_vt;
2008     }
2009 
2010     MyValue4 test70_vt2;
2011     @Test
2012     public void test70() {
2013         test70_vt2 = test70_interp();
2014     }
2015 
2016     @DontCompile
2017     public void test70_verifier(boolean warmup) {
2018         test70();
2019         test70_vt.verify(test70_vt2);
2020     }
2021 
2022     // Return value types in registers from compiled -> interpreter
2023     final MyValue4 test71_vt = MyValue4.create();
2024     @Test
2025     public MyValue4 test71() {
2026         return test71_vt;
2027     }
2028 
2029     @DontCompile
2030     public void test71_verifier(boolean warmup) {
2031         MyValue4 vt = test71();
2032         test71_vt.verify(vt);
2033     }
2034 
2035     // Return value types in registers from compiled -> compiled
2036     final MyValue4 test72_vt = MyValue4.create();
2037     @DontInline
2038     public MyValue4 test72_comp() {
2039         return test72_vt;
2040     }
2041 
2042     MyValue4 test72_vt2;
2043     @Test
2044     public void test72() {
2045         test72_vt2 = test72_comp();
2046     }
2047 
2048     @DontCompile
2049     public void test72_verifier(boolean warmup) throws Exception {
2050         Method helper_m = getClass().getDeclaredMethod("test72_comp");
2051         if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) {
2052             WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION);
2053             Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test72_comp not compiled");
2054         }
2055         test72();
2056         test72_vt.verify(test72_vt2);
2057     }
2058 
2059     // Return values and method handles tests
2060 
2061     // Everything inlined
2062     final MyValue3 test73_vt = MyValue3.create();
2063     @ForceInline
2064     MyValue3 test73_target() {
2065         return test73_vt;
2066     }
2067 
2068     static final MethodHandle test73_mh;
2069 
2070     @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + CALL)
2071     @Test(valid = ValueTypeReturnedAsFieldsOff, match = { ALLOC, STORE }, matchCount = { 1, 12 })
2072     MyValue3 test73() throws Throwable {
2073         return (MyValue3)test73_mh.invokeExact(this);
2074     }
2075 
2076     @DontCompile
2077     public void test73_verifier(boolean warmup) throws Throwable {
2078         MyValue3 vt = test73();
2079         test73_vt.verify(vt);
2080     }
2081 
2082     // Leaf method not inlined but returned type is known
2083     final MyValue3 test74_vt = MyValue3.create();
2084     @DontInline
2085     MyValue3 test74_target() {
2086         return test74_vt;
2087     }
2088 
2089     static final MethodHandle test74_mh;
2090 
2091     @Test
2092     MyValue3 test74() throws Throwable {
2093         return (MyValue3)test74_mh.invokeExact(this);
2094     }
2095 
2096     @DontCompile
2097     public void test74_verifier(boolean warmup) throws Throwable {
2098         Method helper_m = getClass().getDeclaredMethod("test74_target");
2099         if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) {
2100             WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION);
2101             Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test74_target not compiled");
2102         }
2103         MyValue3 vt = test74();
2104         test74_vt.verify(vt);
2105     }
2106 
2107     // Leaf method not inlined and returned type not known
2108     final MyValue3 test75_vt = MyValue3.create();
2109     @DontInline
2110     MyValue3 test75_target() {
2111         return test75_vt;
2112     }
2113 
2114     static final MethodHandle test75_mh;
2115 
2116     @Test
2117     MyValue3 test75() throws Throwable {
2118         return (MyValue3)test75_mh.invokeExact(this);
2119     }
2120 
2121     @DontCompile
2122     public void test75_verifier(boolean warmup) throws Throwable {
2123         // hack so C2 doesn't know the target of the invoke call
2124         Class c = Class.forName("java.lang.invoke.DirectMethodHandle");
2125         Method m = c.getDeclaredMethod("internalMemberName", Object.class);
2126         WHITE_BOX.testSetDontInlineMethod(m, warmup);
2127         MyValue3 vt = test75();
2128         test75_vt.verify(vt);
2129     }
2130 
2131     static {
2132         try {
2133             MethodHandles.Lookup lookup = MethodHandles.lookup();
2134             MethodType mt = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue3;", ValueTypeTestBench.class.getClassLoader());
2135             test73_mh = lookup.findVirtual(ValueTypeTestBench.class, "test73_target", mt);
2136             test74_mh = lookup.findVirtual(ValueTypeTestBench.class, "test74_target", mt);
2137             test75_mh = lookup.findVirtual(ValueTypeTestBench.class, "test75_target", mt);
2138         } catch (NoSuchMethodException|IllegalAccessException e) {
2139             throw new RuntimeException("method handle lookup fails");
2140         }
2141     }
2142 
2143     // ========== Test infrastructure ==========
2144 
2145     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
2146     private static final int ValueTypePassFieldsAsArgsOn = 0x1;
2147     private static final int ValueTypePassFieldsAsArgsOff = 0x2;
2148     private static final int ValueTypeArrayFlattenOn = 0x4;
2149     private static final int ValueTypeArrayFlattenOff = 0x8;
2150     private static final int AlwaysIncrementalInlineOff = 0x10;
2151     private static final int AlwaysIncrementalInlineOn = 0x20;
2152     private static final int ValueTypeReturnedAsFieldsOn = 0x40;
2153     private static final int ValueTypeReturnedAsFieldsOff = 0x80;
2154     static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | AlwaysIncrementalInlineOff | AlwaysIncrementalInlineOn | ValueTypeReturnedAsFieldsOn;
2155     private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
2156     private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
2157     private static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline");
2158     private static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields");
2159     private static final int COMP_LEVEL_ANY = -1;
2160     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
2161     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
2162     private static final int WARMUP = 251;
2163     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
2164     private static boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
2165     private static boolean XCOMP = Platform.isComp();
2166 
2167     // Regular expressions used to match nodes in the PrintIdeal output
2168     private static final String START = "(\\d+\\t(.*";
2169     private static final String MID = ".*)+\\t===.*";
2170     private static final String END = ")|";
2171     private static final String ALLOC  = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END;
2172     private static final String ALLOCA = "(.*precise klass \\[Qcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END;
2173     private static final String LOAD   = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
2174     private static final String LOADP  = START + "Load(P|N)" + MID + "valuetype\\*" + END;
2175     private static final String STORE  = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
2176     private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END;
2177     private static final String LOOP   = START + "Loop" + MID + "" + END;
2178     private static final String TRAP   = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END;
2179     private static final String RETURN = START + "Return" + MID + "returns" + END;
2180     private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END;
2181     private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END;
2182     private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END;
2183     private static final String CALL = START + "CallStaticJava" + MID + END;
2184     private static final String SCOBJ = "(.*# ScObj.*" + END;
2185 
2186     static {
2187         // Gather all test methods and put them in Hashtable
2188         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
2189             Test[] annos = m.getAnnotationsByType(Test.class);
2190             if (annos.length != 0) {
2191                 tests.put("ValueTypeTestBench::" + m.getName(), m);
2192             }
2193         }
2194     }
2195 
2196     private static void execute_vm(String... args) throws Throwable {
2197         Asserts.assertFalse(tests.isEmpty(), "no tests to execute");
2198         ArrayList<String> all_args = new ArrayList(List.of(args));
2199         // Run tests in own process and verify output
2200         all_args.add(ValueTypeTestBench.class.getName());
2201         all_args.add("run");
2202         // Spawn process with default JVM options from the test's run command
2203         String[] vmInputArgs = InputArguments.getVmInputArgs();
2204         String[] cmds = Arrays.copyOf(vmInputArgs, vmInputArgs.length + all_args.size());
2205         System.arraycopy(all_args.toArray(), 0, cmds, vmInputArgs.length, all_args.size());
2206         OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds);
2207         // If ideal graph printing is enabled/supported, verify output
2208         String output = oa.getOutput();
2209         oa.shouldHaveExitValue(0);
2210         boolean verifyIR = output.contains("PrintIdeal enabled") &&
2211                 !output.contains("ValueTypePassFieldsAsArgs is not supported on this platform");
2212         if (verifyIR) {
2213             parseOutput(output);
2214         } else {
2215             System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
2216         }
2217     }
2218 
2219     public static void main(String[] args) throws Throwable {
2220         //tests.values().removeIf(p -> !p.getName().equals("test64")); // Run single test
2221         if (args.length == 0) {
2222             execute_vm("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-BackgroundCompilation",
2223                     "-XX:+PrintCompilation", "-XX:+PrintInlining", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
2224                     "-XX:CICompilerCount=1",
2225                     "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
2226                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
2227                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*",
2228                     "-XX:CompileCommand=compileonly,java.lang.Object::<init>",
2229                     "-XX:CompileCommand=inline,java.lang.__Value::hashCode",
2230                     "-XX:CompileCommand=compileonly,java.lang.invoke.*::*");
2231         } else {
2232             // Execute tests
2233             ValueTypeTestBench bench = new ValueTypeTestBench();
2234             bench.run();
2235         }
2236     }
2237 
2238     public static void parseOutput(String output) throws Exception {
2239         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");
2240         Matcher m = comp_re.matcher(output);
2241         Map<String,String> compilations = new LinkedHashMap<>();
2242         int prev = 0;
2243         String methodName = null;
2244         while (m.find()) {
2245             if (prev == 0) {
2246                 // Print header
2247                 System.out.print(output.substring(0, m.start()+1));
2248             } else if (methodName != null) {
2249                 compilations.put(methodName, output.substring(prev, m.start()+1));



2250             }
2251             if (m.group("osr") != null) {
2252                 methodName = null;
2253             } else {
2254                 methodName = m.group("name");
2255             }
2256             prev = m.end();
2257         }
2258         if (prev == 0) {
2259             // Print header
2260             System.out.print(output);
2261         } else if (methodName != null) {
2262             compilations.put(methodName, output.substring(prev));
2263         }
2264         // Iterate over compilation output
2265         for (String testName : compilations.keySet()) {
2266             Method test = tests.get(testName);
2267             if (test == null) {
2268                 // Skip helper methods
2269                 continue;
2270             }
2271             String graph = compilations.get(testName);
2272             if (PRINT_GRAPH) {
2273                 System.out.println("\nGraph for " + testName + "\n" + graph);
2274             }
2275             // Parse graph using regular expressions to determine if it contains forbidden nodes
2276             Test[] annos = test.getAnnotationsByType(Test.class);
2277             Test anno = null;
2278             for (Test a : annos) {
2279                 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) {
2280                     assert anno == null;
2281                     anno = a;
2282                 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) {
2283                     assert anno == null;
2284                     anno = a;
2285                 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) {
2286                     assert anno == null;
2287                     anno = a;
2288                 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) {
2289                     assert anno == null;
2290                     anno = a;
2291                 } else if ((a.valid() & AlwaysIncrementalInlineOff) != 0 && !AlwaysIncrementalInline) {
2292                     assert anno == null;
2293                     anno = a;
2294                 } else if ((a.valid() & AlwaysIncrementalInlineOn) != 0 && AlwaysIncrementalInline) {
2295                     assert anno == null;
2296                     anno = a;
2297                 } else if ((a.valid() & ValueTypeReturnedAsFieldsOn) != 0 && ValueTypeReturnedAsFields) {
2298                     assert anno == null;
2299                     anno = a;
2300                 } else if ((a.valid() & ValueTypeReturnedAsFieldsOff) != 0 && !ValueTypeReturnedAsFields) {
2301                     assert anno == null;
2302                     anno = a;
2303                 }
2304             }
2305             assert anno != null;
2306             String regexFail = anno.failOn();
2307             if (!regexFail.isEmpty()) {
2308                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
2309                 Matcher matcher = pattern.matcher(graph);
2310                 boolean found = matcher.find();
2311                 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : ""));
2312             }
2313             String[] regexMatch = anno.match();
2314             int[] matchCount = anno.matchCount();
2315             for (int i = 0; i < regexMatch.length; ++i) {
2316                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
2317                 Matcher matcher = pattern.matcher(graph);
2318                 int count = 0;
2319                 String nodes = "";
2320                 while (matcher.find()) {


< prev index next >