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()) { |