15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /* @test
25 * @summary unit tests for java.lang.invoke.MethodHandles
26 * @library /lib/testlibrary /lib/testlibrary/jsr292
27 * @compile MethodHandlesTest.java remote/RemoteExample.java
28 * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -esa test.java.lang.invoke.MethodHandlesTest
29 */
30
31 package test.java.lang.invoke;
32
33 import test.java.lang.invoke.remote.RemoteExample;
34 import java.lang.invoke.*;
35 import java.lang.invoke.MethodHandles.Lookup;
36 import java.lang.reflect.*;
37 import java.util.*;
38 import org.junit.*;
39 import static org.junit.Assert.*;
40 import com.oracle.testlibrary.jsr292.CodeCacheOverflowProcessor;
41
42
43 /**
44 *
45 * @author jrose
46 */
47 public class MethodHandlesTest {
48 static final Class<?> THIS_CLASS = MethodHandlesTest.class;
49 // How much output?
50 static int verbosity = 0;
51 static {
52 String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");
53 if (vstr == null)
54 vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");
431 public Example(int x, int y, int z, int a) { this.name = x+""+y+""+z+""+a; called("Example.<init>", x, y, z, a); }
432
433 static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial
434 }
435 static final Lookup EXAMPLE = Example.EXAMPLE;
436 public static class PubExample extends Example {
437 public PubExample() { this("PubExample"); }
438 protected PubExample(String prefix) { super(prefix+"#"+nextArg()); }
439 protected void pro_v0() { called("Pub/pro_v0", this); }
440 protected static void pro_s0() { called("Pub/pro_s0"); }
441 }
442 static class SubExample extends Example {
443 @Override public void v0() { called("Sub/v0", this); }
444 @Override void pkg_v0() { called("Sub/pkg_v0", this); }
445 @SuppressWarnings("LeakingThisInConstructor")
446 private SubExample(int x) { called("<init>", this, x); }
447 public SubExample() { super("SubExample#"+nextArg()); }
448 }
449 public static interface IntExample {
450 public void v0();
451 public static class Impl implements IntExample {
452 public void v0() { called("Int/v0", this); }
453 final String name;
454 public Impl() { name = "Impl#"+nextArg(); }
455 @Override public String toString() { return name; }
456 }
457 }
458 static interface SubIntExample extends IntExample { }
459
460 static final Object[][][] ACCESS_CASES = {
461 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false
462 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE
463 { { false, PUBLIC }, { false, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false
464 { { false, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: subclass OK
465 { { true, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[4]: all true
466 };
467
468 static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) {
469 Object[][] cases;
470 if (name.contains("pri_") || isSpecial) {
702 Object orig = argsWithSelf[0];
703 assertEquals(orig.getClass(), res.getClass());
704 if (res instanceof Object[])
705 assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]);
706 assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]}));
707 } else {
708 assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params));
709 }
710 if (verbosity >= 1)
711 System.out.print(':');
712 }
713
714 @Test
715 public void testFindSpecial() throws Throwable {
716 CodeCacheOverflowProcessor.runMHTest(this::testFindSpecial0);
717 }
718
719 public void testFindSpecial0() throws Throwable {
720 if (CAN_SKIP_WORKING) return;
721 startTest("findSpecial");
722 testFindSpecial(SubExample.class, Example.class, void.class, "v0");
723 testFindSpecial(SubExample.class, Example.class, void.class, "pkg_v0");
724 testFindSpecial(RemoteExample.class, PubExample.class, void.class, "Pub/pro_v0");
725 // Do some negative testing:
726 for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
727 testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
728 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus");
729 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
730 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);
731 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
732 }
733 }
734
735 void testFindSpecial(Class<?> specialCaller,
736 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
737 if (specialCaller == RemoteExample.class) {
738 testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params);
739 testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params);
740 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
741 testFindSpecial(true, SUBCLASS, specialCaller, defc, ret, name, params);
742 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
743 return;
744 }
745 testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);
746 testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);
747 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
748 testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);
749 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
750 }
751 void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller,
752 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
753 countTest(positive);
754 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
755 MethodType type = MethodType.methodType(ret, params);
756 Lookup specialLookup = maybeMoveIn(lookup, specialCaller);
757 boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller &&
758 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
759 MethodHandle target = null;
760 Exception noAccess = null;
761 try {
762 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
763 if (verbosity >= 5) System.out.println(" lookup => "+specialLookup);
764 target = specialLookup.findSpecial(defc, methodName, type, specialCaller);
765 } catch (ReflectiveOperationException ex) {
766 noAccess = ex;
767 assertExceptionClass(
1817 MethodType inType = MethodType.methodType(Object.class, types);
1818 MethodType outType = MethodType.methodType(Object.class, permTypes);
1819 MethodHandle target = varargsList(outargs).asType(outType);
1820 MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
1821 if (verbosity >= 5) System.out.println("newTarget = "+newTarget);
1822 Object result = newTarget.invokeWithArguments(args);
1823 Object expected = Arrays.asList(permArgs);
1824 if (!expected.equals(result)) {
1825 System.out.println("*** failed permuteArguments "+Arrays.toString(reorder)+" types="+Arrays.asList(types));
1826 System.out.println("in args: "+Arrays.asList(args));
1827 System.out.println("out args: "+expected);
1828 System.out.println("bad args: "+result);
1829 }
1830 assertEquals(expected, result);
1831 }
1832
1833
1834 @Test // SLOW
1835 public void testSpreadArguments() throws Throwable {
1836 CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments0);
1837 }
1838
1839 public void testSpreadArguments0() throws Throwable {
1840 if (CAN_SKIP_WORKING) return;
1841 startTest("spreadArguments");
1842 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
1843 if (verbosity >= 3)
1844 System.out.println("spreadArguments "+argType);
1845 for (int nargs = 0; nargs < 50; nargs++) {
1846 if (CAN_TEST_LIGHTLY && nargs > 11) break;
1847 for (int pos = 0; pos <= nargs; pos++) {
1848 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
1849 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1850 continue;
1851 testSpreadArguments(argType, pos, nargs);
1852 }
1853 }
1854 }
1855 }
1856 public void testSpreadArguments(Class<?> argType, int pos, int nargs) throws Throwable {
1857 countTest();
1858 Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
1859 MethodHandle target2 = varargsArray(arrayType, nargs);
1860 MethodHandle target = target2.asType(target2.type().generic());
1861 if (verbosity >= 3)
1862 System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
1863 Object[] args = randomArgs(target2.type().parameterArray());
1864 // make sure the target does what we think it does:
1865 if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {
1866 Object[] check = (Object[]) target.invokeWithArguments(args);
1867 assertArrayEquals(args, check);
1868 switch (nargs) {
1869 case 0:
1870 check = (Object[]) (Object) target.invokeExact();
1871 assertArrayEquals(args, check);
1872 break;
1873 case 1:
1874 check = (Object[]) (Object) target.invokeExact(args[0]);
1875 assertArrayEquals(args, check);
1876 break;
1877 case 2:
1878 check = (Object[]) (Object) target.invokeExact(args[0], args[1]);
1879 assertArrayEquals(args, check);
1880 break;
1881 }
1882 }
1883 List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
1884 { // modify newParams in place
1885 List<Class<?>> spreadParams = newParams.subList(pos, nargs);
1886 spreadParams.clear(); spreadParams.add(arrayType);
1887 }
1888 MethodType newType = MethodType.methodType(arrayType, newParams);
1889 MethodHandle result = target2.asSpreader(arrayType, nargs-pos);
1890 assert(result.type() == newType) : Arrays.asList(result, newType);
1891 result = result.asType(newType.generic());
1892 Object returnValue;
1893 if (pos == 0) {
1894 Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1895 returnValue = result.invokeExact(args2);
1896 } else {
1897 Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
1898 args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1899 returnValue = result.invokeWithArguments(args1);
1900 }
1901 String argstr = Arrays.toString(args);
1902 if (!argType.isPrimitive()) {
1903 Object[] rv = (Object[]) returnValue;
1904 String rvs = Arrays.toString(rv);
1905 if (!Arrays.equals(args, rv)) {
1906 System.out.println("method: "+result);
1907 System.out.println("expected: "+argstr);
1908 System.out.println("returned: "+rvs);
1909 assertArrayEquals(args, rv);
1910 }
1911 } else if (argType == int.class) {
1912 String rvs = Arrays.toString((int[]) returnValue);
1913 if (!argstr.equals(rvs)) {
1914 System.out.println("method: "+result);
1915 System.out.println("expected: "+argstr);
1916 System.out.println("returned: "+rvs);
1917 assertEquals(argstr, rvs);
1918 }
1919 } else if (argType == long.class) {
1920 String rvs = Arrays.toString((long[]) returnValue);
1921 if (!argstr.equals(rvs)) {
1922 System.out.println("method: "+result);
1923 System.out.println("expected: "+argstr);
1924 System.out.println("returned: "+rvs);
1925 assertEquals(argstr, rvs);
1926 }
1927 } else {
1928 // cannot test...
1929 }
1930 }
1931
1932 @Test // SLOW
1933 public void testAsCollector() throws Throwable {
1934 CodeCacheOverflowProcessor.runMHTest(this::testAsCollector0);
1935 }
1936
1937 public void testAsCollector0() throws Throwable {
1938 if (CAN_SKIP_WORKING) return;
1939 startTest("asCollector");
1940 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
1941 if (verbosity >= 3)
1942 System.out.println("asCollector "+argType);
1943 for (int nargs = 0; nargs < 50; nargs++) {
1944 if (CAN_TEST_LIGHTLY && nargs > 11) break;
1945 for (int pos = 0; pos <= nargs; pos++) {
1946 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
1947 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1948 continue;
1949 testAsCollector(argType, pos, nargs);
1950 }
1951 }
1952 }
1953 }
1954 public void testAsCollector(Class<?> argType, int pos, int nargs) throws Throwable {
1957 MethodHandle fake = varargsArray(nargs);
1958 fake = changeArgTypes(fake, argType);
1959 MethodType newType = fake.type();
1960 Object[] args = randomArgs(newType.parameterArray());
1961 // here is what should happen:
1962 Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1);
1963 collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length);
1964 // here is the MH which will witness the collected argument tail:
1965 MethodHandle target = varargsArray(pos+1);
1966 target = changeArgTypes(target, 0, pos, argType);
1967 target = changeArgTypes(target, pos, pos+1, Object[].class);
1968 if (verbosity >= 3)
1969 System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
1970 MethodHandle result = target.asCollector(Object[].class, nargs-pos).asType(newType);
1971 Object[] returnValue = (Object[]) result.invokeWithArguments(args);
1972 // assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
1973 // returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
1974 // collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
1975 assertArrayEquals(collectedArgs, returnValue);
1976 }
1977
1978 @Test // SLOW
1979 public void testInsertArguments() throws Throwable {
1980 CodeCacheOverflowProcessor.runMHTest(this::testInsertArguments0);
1981 }
1982
1983 public void testInsertArguments0() throws Throwable {
1984 if (CAN_SKIP_WORKING) return;
1985 startTest("insertArguments");
1986 for (int nargs = 0; nargs < 50; nargs++) {
1987 if (CAN_TEST_LIGHTLY && nargs > 11) break;
1988 for (int ins = 0; ins <= nargs; ins++) {
1989 if (nargs > 10 && ins > 4 && ins < nargs-4 && ins % 10 != 3)
1990 continue;
1991 for (int pos = 0; pos <= nargs; pos++) {
1992 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1993 continue;
1994 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
1995 testInsertArguments(nargs, pos, ins);
1996 }
2100 // Simulate expected effect of filter on arglist:
2101 Object[] filteredArgs = argsToPass.clone();
2102 filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);
2103 List<Object> expected = Arrays.asList(filteredArgs);
2104 Object result = target2.invokeWithArguments(argsToPass);
2105 if (verbosity >= 3)
2106 System.out.println("result: "+result);
2107 if (!expected.equals(result))
2108 System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);
2109 assertEquals(expected, result);
2110 }
2111
2112 @Test
2113 public void testCollectArguments() throws Throwable {
2114 CodeCacheOverflowProcessor.runMHTest(this::testCollectArguments0);
2115 }
2116
2117 public void testCollectArguments0() throws Throwable {
2118 if (CAN_SKIP_WORKING) return;
2119 startTest("collectArguments");
2120 testFoldOrCollectArguments(true);
2121 }
2122
2123 @Test
2124 public void testFoldArguments() throws Throwable {
2125 CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments0);
2126 }
2127
2128 public void testFoldArguments0() throws Throwable {
2129 if (CAN_SKIP_WORKING) return;
2130 startTest("foldArguments");
2131 testFoldOrCollectArguments(false);
2132 }
2133
2134 void testFoldOrCollectArguments(boolean isCollect) throws Throwable {
2135 for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) {
2136 for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) {
2137 int maxArity = 10;
2138 if (collectType != String.class) maxArity = 5;
2139 if (lastType != Object.class) maxArity = 4;
2140 for (int nargs = 0; nargs <= maxArity; nargs++) {
2141 ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class));
2142 int maxMix = 20;
2143 if (collectType != Object.class) maxMix = 0;
2144 Map<Object,Integer> argTypesSeen = new HashMap<>();
2145 for (int mix = 0; mix <= maxMix; mix++) {
2146 if (!mixArgs(argTypes, mix, argTypesSeen)) continue;
2147 for (int collect = 0; collect <= nargs; collect++) {
2148 for (int pos = 0; pos <= nargs - collect; pos++) {
2149 testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect);
2150 }
2151 }
2152 }
2153 }
2154 }
2155 }
2156 }
2157
2158 boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) {
2159 assert(mix >= 0);
2160 if (mix == 0) return true; // no change
2161 if ((mix >>> argTypes.size()) != 0) return false;
2162 for (int i = 0; i < argTypes.size(); i++) {
2163 if (i >= 31) break;
2164 boolean bit = (mix & (1 << i)) != 0;
2165 if (bit) {
2166 Class<?> type = argTypes.get(i);
2167 if (type == Object.class)
2168 type = String.class;
2169 else if (type == String.class)
2170 type = int.class;
2171 else
2172 type = Object.class;
2173 argTypes.set(i, type);
2174 }
2175 }
2176 Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix);
2177 if (prev != null) {
2178 if (verbosity >= 4) System.out.println("mix "+prev+" repeated "+mix+": "+argTypes);
2179 return false;
2180 }
2181 if (verbosity >= 3) System.out.println("mix "+mix+" = "+argTypes);
2182 return true;
2183 }
2184
2185 void testFoldOrCollectArguments(List<Class<?>> argTypes, // argument types minus the inserted combineType
2186 int pos, int fold, // position and length of the folded arguments
2187 Class<?> combineType, // type returned from the combiner
2188 Class<?> lastType, // type returned from the target
2189 boolean isCollect) throws Throwable {
2190 int nargs = argTypes.size();
2191 if (pos != 0 && !isCollect) return; // can fold only at pos=0 for now
2192 countTest();
2193 List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold);
2194 List<Class<?>> targetArgTypes = new ArrayList<>(argTypes);
2195 if (isCollect) // does targret see arg[pos..pos+cc-1]?
2196 targetArgTypes.subList(pos, pos + fold).clear();
2197 if (combineType != void.class)
2198 targetArgTypes.add(pos, combineType);
2199 MethodHandle target = varargsList(targetArgTypes, lastType);
2200 MethodHandle combine = varargsList(combineArgTypes, combineType);
2201 List<Object> argsToPass = Arrays.asList(randomArgs(argTypes));
2202 if (verbosity >= 3)
2203 System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine);
2204 MethodHandle target2;
2205 if (isCollect)
2206 target2 = MethodHandles.collectArguments(target, pos, combine);
2207 else
2208 target2 = MethodHandles.foldArguments(target, combine);
2209 // Simulate expected effect of combiner on arglist:
2210 List<Object> expectedList = new ArrayList<>(argsToPass);
2211 List<Object> argsToFold = expectedList.subList(pos, pos + fold);
2212 if (verbosity >= 3)
2213 System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2);
2214 Object foldedArgs = combine.invokeWithArguments(argsToFold);
2215 if (isCollect)
2216 argsToFold.clear();
2217 if (combineType != void.class)
2218 argsToFold.add(0, foldedArgs);
2219 Object result = target2.invokeWithArguments(argsToPass);
2220 if (verbosity >= 3)
2221 System.out.println("result: "+result);
2222 Object expected = target.invokeWithArguments(expectedList);
2223 if (!expected.equals(result))
2224 System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected);
2225 assertEquals(expected, result);
2226 }
2227
2228 @Test
2524 int pc = test1.type().parameterCount();
2525 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc));
2526 }
2527 MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback);
2528 assertEquals(target.type(), mh.type());
2529 boolean equals;
2530 switch (nargs) {
2531 case 0: equals = true; break;
2532 case 1: equals = MISSING_ARG.equals(argList[0]); break;
2533 default: equals = argList[0].equals(argList[1]); break;
2534 }
2535 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
2536 if (verbosity >= 3)
2537 System.out.println(logEntry(willCall, argList));
2538 Object result = mh.invokeWithArguments(argList1);
2539 assertCalled(willCall, argList);
2540 }
2541 }
2542
2543 @Test
2544 public void testThrowException() throws Throwable {
2545 CodeCacheOverflowProcessor.runMHTest(this::testThrowException0);
2546 }
2547
2548 public void testThrowException0() throws Throwable {
2549 if (CAN_SKIP_WORKING) return;
2550 startTest("throwException");
2551 testThrowException(int.class, new ClassCastException("testing"));
2552 testThrowException(void.class, new java.io.IOException("testing"));
2553 testThrowException(String.class, new LinkageError("testing"));
2554 }
2555
2556 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable {
2557 countTest();
2558 Class<? extends Throwable> exType = thrown.getClass();
2559 MethodHandle target = MethodHandles.throwException(returnType, exType);
2560 //System.out.println("throwing with "+target+" : "+thrown);
2561 MethodType expectedType = MethodType.methodType(returnType, exType);
2562 assertEquals(expectedType, target.type());
2563 target = target.asType(target.type().generic());
2564 Throwable caught = null;
2565 try {
2566 Object res = target.invokeExact((Object) thrown);
2567 fail("got "+res+" instead of throwing "+thrown);
2568 } catch (Throwable ex) {
2569 if (ex != thrown) {
2570 if (ex instanceof Error) throw (Error)ex;
2571 if (ex instanceof RuntimeException) throw (RuntimeException)ex;
2572 }
2573 caught = ex;
2574 }
2575 assertSame(thrown, caught);
2576 }
2577
2578 @Test
2579 public void testInterfaceCast() throws Throwable {
2580 CodeCacheOverflowProcessor.runMHTest(this::testInterfaceCast0);
2581 }
2582
2583 public void testInterfaceCast0() throws Throwable {
2584 //if (CAN_SKIP_WORKING) return;
2585 startTest("interfaceCast");
2586 assert( (((Object)"foo") instanceof CharSequence));
2587 assert(!(((Object)"foo") instanceof Iterable));
2588 for (MethodHandle mh : new MethodHandle[]{
2589 MethodHandles.identity(String.class),
2590 MethodHandles.identity(CharSequence.class),
2591 MethodHandles.identity(Iterable.class)
2592 }) {
2593 if (verbosity > 0) System.out.println("-- mh = "+mh);
2594 for (Class<?> ctype : new Class<?>[]{
2595 Object.class, String.class, CharSequence.class,
2596 Number.class, Iterable.class
2597 }) {
2598 if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName());
2599 // doret docast
2600 testInterfaceCast(mh, ctype, false, false);
2601 testInterfaceCast(mh, ctype, true, false);
2602 testInterfaceCast(mh, ctype, false, true);
2603 testInterfaceCast(mh, ctype, true, true);
2604 }
|
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /* @test
25 * @summary unit tests for java.lang.invoke.MethodHandles
26 * @library /lib/testlibrary /lib/testlibrary/jsr292
27 * @compile MethodHandlesTest.java remote/RemoteExample.java
28 * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -esa test.java.lang.invoke.MethodHandlesTest
29 */
30
31 package test.java.lang.invoke;
32
33 import test.java.lang.invoke.remote.RemoteExample;
34 import java.lang.invoke.*;
35 import static java.lang.invoke.MethodType.methodType;
36 import java.lang.invoke.MethodHandles.Lookup;
37 import java.lang.reflect.*;
38 import java.util.*;
39 import org.junit.*;
40 import static org.junit.Assert.*;
41 import com.oracle.testlibrary.jsr292.CodeCacheOverflowProcessor;
42
43
44 /**
45 *
46 * @author jrose
47 */
48 public class MethodHandlesTest {
49 static final Class<?> THIS_CLASS = MethodHandlesTest.class;
50 // How much output?
51 static int verbosity = 0;
52 static {
53 String vstr = System.getProperty(THIS_CLASS.getSimpleName()+".verbosity");
54 if (vstr == null)
55 vstr = System.getProperty(THIS_CLASS.getName()+".verbosity");
432 public Example(int x, int y, int z, int a) { this.name = x+""+y+""+z+""+a; called("Example.<init>", x, y, z, a); }
433
434 static final Lookup EXAMPLE = MethodHandles.lookup(); // for testing findSpecial
435 }
436 static final Lookup EXAMPLE = Example.EXAMPLE;
437 public static class PubExample extends Example {
438 public PubExample() { this("PubExample"); }
439 protected PubExample(String prefix) { super(prefix+"#"+nextArg()); }
440 protected void pro_v0() { called("Pub/pro_v0", this); }
441 protected static void pro_s0() { called("Pub/pro_s0"); }
442 }
443 static class SubExample extends Example {
444 @Override public void v0() { called("Sub/v0", this); }
445 @Override void pkg_v0() { called("Sub/pkg_v0", this); }
446 @SuppressWarnings("LeakingThisInConstructor")
447 private SubExample(int x) { called("<init>", this, x); }
448 public SubExample() { super("SubExample#"+nextArg()); }
449 }
450 public static interface IntExample {
451 public void v0();
452 public default void vd() { called("vd", this); }
453 public static class Impl implements IntExample {
454 public void v0() { called("Int/v0", this); }
455 final String name;
456 public Impl() { name = "Impl#"+nextArg(); }
457 @Override public String toString() { return name; }
458 }
459 }
460 static interface SubIntExample extends IntExample { }
461
462 static final Object[][][] ACCESS_CASES = {
463 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { false, PRIVATE }, { false, EXAMPLE } }, //[0]: all false
464 { { false, PUBLIC }, { false, SUBCLASS }, { false, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[1]: only PRIVATE
465 { { false, PUBLIC }, { false, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[2]: PUBLIC false
466 { { false, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[3]: subclass OK
467 { { true, PUBLIC }, { true, SUBCLASS }, { true, PACKAGE }, { true, PRIVATE }, { true, EXAMPLE } }, //[4]: all true
468 };
469
470 static Object[][] accessCases(Class<?> defc, String name, boolean isSpecial) {
471 Object[][] cases;
472 if (name.contains("pri_") || isSpecial) {
704 Object orig = argsWithSelf[0];
705 assertEquals(orig.getClass(), res.getClass());
706 if (res instanceof Object[])
707 assertArrayEquals((Object[])res, (Object[])argsWithSelf[0]);
708 assert(Arrays.deepEquals(new Object[]{res}, new Object[]{argsWithSelf[0]}));
709 } else {
710 assert(false) : Arrays.asList(positive, lookup, rcvc, defc, ret, name, deepToString(params));
711 }
712 if (verbosity >= 1)
713 System.out.print(':');
714 }
715
716 @Test
717 public void testFindSpecial() throws Throwable {
718 CodeCacheOverflowProcessor.runMHTest(this::testFindSpecial0);
719 }
720
721 public void testFindSpecial0() throws Throwable {
722 if (CAN_SKIP_WORKING) return;
723 startTest("findSpecial");
724 testFindSpecial(SubExample.class, Example.class, void.class, false, "v0");
725 testFindSpecial(SubExample.class, Example.class, void.class, false, "pkg_v0");
726 testFindSpecial(RemoteExample.class, PubExample.class, void.class, false, "Pub/pro_v0");
727 testFindSpecial(Example.class, IntExample.class, void.class, true, "vd");
728 // Do some negative testing:
729 for (Lookup lookup : new Lookup[]{ PRIVATE, EXAMPLE, PACKAGE, PUBLIC }) {
730 testFindSpecial(false, lookup, Object.class, Example.class, void.class, "v0");
731 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "bogus");
732 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", int.class);
733 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "<init>", Void.class);
734 testFindSpecial(false, lookup, SubExample.class, Example.class, void.class, "s0");
735 testFindSpecial(false, lookup, Example.class, IntExample.class, void.class, "v0");
736 }
737 }
738
739 void testFindSpecial(Class<?> specialCaller,
740 Class<?> defc, Class<?> ret, boolean dflt, String name, Class<?>... params) throws Throwable {
741 if (specialCaller == RemoteExample.class) {
742 testFindSpecial(false, EXAMPLE, specialCaller, defc, ret, name, params);
743 testFindSpecial(false, PRIVATE, specialCaller, defc, ret, name, params);
744 testFindSpecial(false, PACKAGE, specialCaller, defc, ret, name, params);
745 testFindSpecial(true, SUBCLASS, specialCaller, defc, ret, name, params);
746 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
747 return;
748 }
749 testFindSpecial(true, EXAMPLE, specialCaller, defc, ret, name, params);
750 testFindSpecial(true, PRIVATE, specialCaller, defc, ret, name, params);
751 testFindSpecial(false || dflt, PACKAGE, specialCaller, defc, ret, name, params);
752 testFindSpecial(false, SUBCLASS, specialCaller, defc, ret, name, params);
753 testFindSpecial(false, PUBLIC, specialCaller, defc, ret, name, params);
754 }
755 void testFindSpecial(boolean positive, Lookup lookup, Class<?> specialCaller,
756 Class<?> defc, Class<?> ret, String name, Class<?>... params) throws Throwable {
757 countTest(positive);
758 String methodName = name.substring(1 + name.indexOf('/')); // foo/bar => foo
759 MethodType type = MethodType.methodType(ret, params);
760 Lookup specialLookup = maybeMoveIn(lookup, specialCaller);
761 boolean specialAccessOK = (specialLookup.lookupClass() == specialCaller &&
762 (specialLookup.lookupModes() & Lookup.PRIVATE) != 0);
763 MethodHandle target = null;
764 Exception noAccess = null;
765 try {
766 if (verbosity >= 4) System.out.println("lookup via "+lookup+" of "+defc+" "+name+type);
767 if (verbosity >= 5) System.out.println(" lookup => "+specialLookup);
768 target = specialLookup.findSpecial(defc, methodName, type, specialCaller);
769 } catch (ReflectiveOperationException ex) {
770 noAccess = ex;
771 assertExceptionClass(
1821 MethodType inType = MethodType.methodType(Object.class, types);
1822 MethodType outType = MethodType.methodType(Object.class, permTypes);
1823 MethodHandle target = varargsList(outargs).asType(outType);
1824 MethodHandle newTarget = MethodHandles.permuteArguments(target, inType, reorder);
1825 if (verbosity >= 5) System.out.println("newTarget = "+newTarget);
1826 Object result = newTarget.invokeWithArguments(args);
1827 Object expected = Arrays.asList(permArgs);
1828 if (!expected.equals(result)) {
1829 System.out.println("*** failed permuteArguments "+Arrays.toString(reorder)+" types="+Arrays.asList(types));
1830 System.out.println("in args: "+Arrays.asList(args));
1831 System.out.println("out args: "+expected);
1832 System.out.println("bad args: "+result);
1833 }
1834 assertEquals(expected, result);
1835 }
1836
1837
1838 @Test // SLOW
1839 public void testSpreadArguments() throws Throwable {
1840 CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments0);
1841 CodeCacheOverflowProcessor.runMHTest(this::testSpreadArguments1);
1842 }
1843
1844 public void testSpreadArguments0() throws Throwable {
1845 if (CAN_SKIP_WORKING) return;
1846 startTest("spreadArguments");
1847 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
1848 if (verbosity >= 3)
1849 System.out.println("spreadArguments "+argType);
1850 Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
1851 for (int nargs = 0; nargs < 50; nargs++) {
1852 if (CAN_TEST_LIGHTLY && nargs > 11) break;
1853 for (int pos = 0; pos <= nargs; pos++) {
1854 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
1855 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1856 continue;
1857 testSpreadArguments(argType, arrayType, pos, nargs);
1858 }
1859 }
1860 }
1861 }
1862 public void testSpreadArguments(Class<?> argType, Class<?> arrayType, int pos, int nargs) throws Throwable {
1863 countTest();
1864 MethodHandle target2 = varargsArray(arrayType, nargs);
1865 MethodHandle target = target2.asType(target2.type().generic());
1866 if (verbosity >= 3)
1867 System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
1868 Object[] args = randomArgs(target2.type().parameterArray());
1869 // make sure the target does what we think it does:
1870 checkTarget(argType, pos, nargs, target, args);
1871 List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
1872 { // modify newParams in place
1873 List<Class<?>> spreadParams = newParams.subList(pos, nargs);
1874 spreadParams.clear(); spreadParams.add(arrayType);
1875 }
1876 MethodType newType = MethodType.methodType(arrayType, newParams);
1877 MethodHandle result = target2.asSpreader(arrayType, nargs-pos);
1878 assert(result.type() == newType) : Arrays.asList(result, newType);
1879 result = result.asType(newType.generic());
1880 Object returnValue;
1881 if (pos == 0) {
1882 Object args2 = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1883 returnValue = result.invokeExact(args2);
1884 } else {
1885 Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
1886 args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, args.length));
1887 returnValue = result.invokeWithArguments(args1);
1888 }
1889 checkReturnValue(argType, args, result, returnValue);
1890 }
1891 public void testSpreadArguments1() throws Throwable {
1892 if (CAN_SKIP_WORKING) return;
1893 startTest("spreadArguments/pos");
1894 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
1895 if (verbosity >= 3)
1896 System.out.println("spreadArguments "+argType);
1897 Class<?> arrayType = java.lang.reflect.Array.newInstance(argType, 0).getClass();
1898 for (int nargs = 0; nargs < 50; nargs++) {
1899 if (CAN_TEST_LIGHTLY && nargs > 11) break;
1900 for (int pos = 0; pos <= nargs; pos++) {
1901 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
1902 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
1903 continue;
1904 for (int spr = 1; spr < nargs - pos; ++spr) {
1905 if (spr > 4 && spr != 7 && spr != 11 && spr != 20 && spr < nargs - pos - 4) continue;
1906 testSpreadArguments(argType, arrayType, pos, spr, nargs);
1907 }
1908 }
1909 }
1910 }
1911 }
1912 public void testSpreadArguments(Class<?> argType, Class<?> arrayType, int pos, int spread, int nargs) throws Throwable {
1913 countTest();
1914 MethodHandle target2 = varargsArray(arrayType, nargs);
1915 MethodHandle target = target2.asType(target2.type().generic());
1916 if (verbosity >= 3)
1917 System.out.println("spread into " + target2 + " [" + pos + ".." + (pos + spread) + "[");
1918 Object[] args = randomArgs(target2.type().parameterArray());
1919 // make sure the target does what we think it does:
1920 checkTarget(argType, pos, nargs, target, args);
1921 List<Class<?>> newParams = new ArrayList<>(target2.type().parameterList());
1922 { // modify newParams in place
1923 List<Class<?>> spreadParams = newParams.subList(pos, pos + spread);
1924 spreadParams.clear();
1925 spreadParams.add(arrayType);
1926 }
1927 MethodType newType = MethodType.methodType(arrayType, newParams);
1928 MethodHandle result = target2.asSpreader(pos, arrayType, spread);
1929 assert (result.type() == newType) : Arrays.asList(result, newType);
1930 result = result.asType(newType.generic());
1931 // args1 has nargs-spread entries, plus one for the to-be-spread array
1932 int args1Length = nargs - (spread - 1);
1933 Object[] args1 = new Object[args1Length];
1934 System.arraycopy(args, 0, args1, 0, pos);
1935 args1[pos] = ValueConversions.changeArrayType(arrayType, Arrays.copyOfRange(args, pos, pos + spread));
1936 System.arraycopy(args, pos + spread, args1, pos + 1, nargs - spread - pos);
1937 Object returnValue = result.invokeWithArguments(args1);
1938 checkReturnValue(argType, args, result, returnValue);
1939 }
1940 private static void checkTarget(Class<?> argType, int pos, int nargs, MethodHandle target, Object[] args) throws Throwable {
1941 if (pos == 0 && nargs < 5 && !argType.isPrimitive()) {
1942 Object[] check = (Object[]) target.invokeWithArguments(args);
1943 assertArrayEquals(args, check);
1944 switch (nargs) {
1945 case 0:
1946 check = (Object[]) (Object) target.invokeExact();
1947 assertArrayEquals(args, check);
1948 break;
1949 case 1:
1950 check = (Object[]) (Object) target.invokeExact(args[0]);
1951 assertArrayEquals(args, check);
1952 break;
1953 case 2:
1954 check = (Object[]) (Object) target.invokeExact(args[0], args[1]);
1955 assertArrayEquals(args, check);
1956 break;
1957 }
1958 }
1959 }
1960 private static void checkReturnValue(Class<?> argType, Object[] args, MethodHandle result, Object returnValue) {
1961 String argstr = Arrays.toString(args);
1962 if (!argType.isPrimitive()) {
1963 Object[] rv = (Object[]) returnValue;
1964 String rvs = Arrays.toString(rv);
1965 if (!Arrays.equals(args, rv)) {
1966 System.out.println("method: "+result);
1967 System.out.println("expected: "+argstr);
1968 System.out.println("returned: "+rvs);
1969 assertArrayEquals(args, rv);
1970 }
1971 } else if (argType == int.class) {
1972 String rvs = Arrays.toString((int[]) returnValue);
1973 if (!argstr.equals(rvs)) {
1974 System.out.println("method: "+result);
1975 System.out.println("expected: "+argstr);
1976 System.out.println("returned: "+rvs);
1977 assertEquals(argstr, rvs);
1978 }
1979 } else if (argType == long.class) {
1980 String rvs = Arrays.toString((long[]) returnValue);
1981 if (!argstr.equals(rvs)) {
1982 System.out.println("method: "+result);
1983 System.out.println("expected: "+argstr);
1984 System.out.println("returned: "+rvs);
1985 assertEquals(argstr, rvs);
1986 }
1987 } else {
1988 // cannot test...
1989 }
1990 }
1991
1992 @Test // SLOW
1993 public void testAsCollector() throws Throwable {
1994 CodeCacheOverflowProcessor.runMHTest(this::testAsCollector0);
1995 CodeCacheOverflowProcessor.runMHTest(this::testAsCollector1);
1996 }
1997
1998 public void testAsCollector0() throws Throwable {
1999 if (CAN_SKIP_WORKING) return;
2000 startTest("asCollector");
2001 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
2002 if (verbosity >= 3)
2003 System.out.println("asCollector "+argType);
2004 for (int nargs = 0; nargs < 50; nargs++) {
2005 if (CAN_TEST_LIGHTLY && nargs > 11) break;
2006 for (int pos = 0; pos <= nargs; pos++) {
2007 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
2008 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
2009 continue;
2010 testAsCollector(argType, pos, nargs);
2011 }
2012 }
2013 }
2014 }
2015 public void testAsCollector(Class<?> argType, int pos, int nargs) throws Throwable {
2018 MethodHandle fake = varargsArray(nargs);
2019 fake = changeArgTypes(fake, argType);
2020 MethodType newType = fake.type();
2021 Object[] args = randomArgs(newType.parameterArray());
2022 // here is what should happen:
2023 Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1);
2024 collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length);
2025 // here is the MH which will witness the collected argument tail:
2026 MethodHandle target = varargsArray(pos+1);
2027 target = changeArgTypes(target, 0, pos, argType);
2028 target = changeArgTypes(target, pos, pos+1, Object[].class);
2029 if (verbosity >= 3)
2030 System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
2031 MethodHandle result = target.asCollector(Object[].class, nargs-pos).asType(newType);
2032 Object[] returnValue = (Object[]) result.invokeWithArguments(args);
2033 // assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
2034 // returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
2035 // collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
2036 assertArrayEquals(collectedArgs, returnValue);
2037 }
2038 public void testAsCollector1() throws Throwable {
2039 if (CAN_SKIP_WORKING) return;
2040 startTest("asCollector/pos");
2041 for (Class<?> argType : new Class<?>[]{Object.class, Integer.class, int.class}) {
2042 if (verbosity >= 3)
2043 System.out.println("asCollector/pos "+argType);
2044 for (int nargs = 0; nargs < 50; nargs++) {
2045 if (CAN_TEST_LIGHTLY && nargs > 11) break;
2046 for (int pos = 0; pos <= nargs; pos++) {
2047 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
2048 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
2049 continue;
2050 for (int coll = 1; coll < nargs - pos; ++coll) {
2051 if (coll > 4 && coll != 7 && coll != 11 && coll != 20 && coll < nargs - pos - 4) continue;
2052 testAsCollector(argType, pos, coll, nargs);
2053 }
2054 }
2055 }
2056 }
2057 }
2058 public void testAsCollector(Class<?> argType, int pos, int collect, int nargs) throws Throwable {
2059 countTest();
2060 // fake up a MH with the same type as the desired adapter:
2061 MethodHandle fake = varargsArray(nargs);
2062 fake = changeArgTypes(fake, argType);
2063 MethodType newType = fake.type();
2064 Object[] args = randomArgs(newType.parameterArray());
2065 // here is what should happen:
2066 // new arg list has "collect" less arguments, but one extra for collected arguments array
2067 int collectedLength = nargs-(collect-1);
2068 Object[] collectedArgs = new Object[collectedLength];
2069 System.arraycopy(args, 0, collectedArgs, 0, pos);
2070 collectedArgs[pos] = Arrays.copyOfRange(args, pos, pos+collect);
2071 System.arraycopy(args, pos+collect, collectedArgs, pos+1, args.length-(pos+collect));
2072 // here is the MH which will witness the collected argument part (not tail!):
2073 MethodHandle target = varargsArray(collectedLength);
2074 target = changeArgTypes(target, 0, pos, argType);
2075 target = changeArgTypes(target, pos, pos+1, Object[].class);
2076 target = changeArgTypes(target, pos+1, collectedLength, argType);
2077 if (verbosity >= 3)
2078 System.out.println("collect "+collect+" from "+Arrays.asList(args)+" ["+pos+".."+(pos+collect)+"[");
2079 MethodHandle result = target.asCollector(pos, Object[].class, collect).asType(newType);
2080 Object[] returnValue = (Object[]) result.invokeWithArguments(args);
2081 assertArrayEquals(collectedArgs, returnValue);
2082 }
2083
2084 @Test // SLOW
2085 public void testInsertArguments() throws Throwable {
2086 CodeCacheOverflowProcessor.runMHTest(this::testInsertArguments0);
2087 }
2088
2089 public void testInsertArguments0() throws Throwable {
2090 if (CAN_SKIP_WORKING) return;
2091 startTest("insertArguments");
2092 for (int nargs = 0; nargs < 50; nargs++) {
2093 if (CAN_TEST_LIGHTLY && nargs > 11) break;
2094 for (int ins = 0; ins <= nargs; ins++) {
2095 if (nargs > 10 && ins > 4 && ins < nargs-4 && ins % 10 != 3)
2096 continue;
2097 for (int pos = 0; pos <= nargs; pos++) {
2098 if (nargs > 10 && pos > 4 && pos < nargs-4 && pos % 10 != 3)
2099 continue;
2100 if (CAN_TEST_LIGHTLY && pos > 2 && pos < nargs-2) continue;
2101 testInsertArguments(nargs, pos, ins);
2102 }
2206 // Simulate expected effect of filter on arglist:
2207 Object[] filteredArgs = argsToPass.clone();
2208 filteredArgs[pos] = filter.invokeExact(filteredArgs[pos]);
2209 List<Object> expected = Arrays.asList(filteredArgs);
2210 Object result = target2.invokeWithArguments(argsToPass);
2211 if (verbosity >= 3)
2212 System.out.println("result: "+result);
2213 if (!expected.equals(result))
2214 System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+Arrays.asList(argsToPass)+" => "+result+" != "+expected);
2215 assertEquals(expected, result);
2216 }
2217
2218 @Test
2219 public void testCollectArguments() throws Throwable {
2220 CodeCacheOverflowProcessor.runMHTest(this::testCollectArguments0);
2221 }
2222
2223 public void testCollectArguments0() throws Throwable {
2224 if (CAN_SKIP_WORKING) return;
2225 startTest("collectArguments");
2226 testFoldOrCollectArguments(true, false);
2227 }
2228
2229 @Test
2230 public void testFoldArguments() throws Throwable {
2231 CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments0);
2232 CodeCacheOverflowProcessor.runMHTest(this::testFoldArguments1);
2233 }
2234
2235 public void testFoldArguments0() throws Throwable {
2236 if (CAN_SKIP_WORKING) return;
2237 startTest("foldArguments");
2238 testFoldOrCollectArguments(false, false);
2239 }
2240
2241 public void testFoldArguments1() throws Throwable {
2242 if (CAN_SKIP_WORKING) return;
2243 startTest("foldArguments/pos");
2244 testFoldOrCollectArguments(false, true);
2245 }
2246
2247 void testFoldOrCollectArguments(boolean isCollect, boolean withFoldPos) throws Throwable {
2248 assert !(isCollect && withFoldPos); // exclude illegal argument combination
2249 for (Class<?> lastType : new Class<?>[]{ Object.class, String.class, int.class }) {
2250 for (Class<?> collectType : new Class<?>[]{ Object.class, String.class, int.class, void.class }) {
2251 int maxArity = 10;
2252 if (collectType != String.class) maxArity = 5;
2253 if (lastType != Object.class) maxArity = 4;
2254 for (int nargs = 0; nargs <= maxArity; nargs++) {
2255 ArrayList<Class<?>> argTypes = new ArrayList<>(Collections.nCopies(nargs, Object.class));
2256 int maxMix = 20;
2257 if (collectType != Object.class) maxMix = 0;
2258 Map<Object,Integer> argTypesSeen = new HashMap<>();
2259 for (int mix = 0; mix <= maxMix; mix++) {
2260 if (!mixArgs(argTypes, mix, argTypesSeen)) continue;
2261 for (int collect = 0; collect <= nargs; collect++) {
2262 for (int pos = 0; pos <= nargs - collect; pos++) {
2263 testFoldOrCollectArguments(argTypes, pos, collect, collectType, lastType, isCollect, withFoldPos);
2264 }
2265 }
2266 }
2267 }
2268 }
2269 }
2270 }
2271
2272 boolean mixArgs(List<Class<?>> argTypes, int mix, Map<Object,Integer> argTypesSeen) {
2273 assert(mix >= 0);
2274 if (mix == 0) return true; // no change
2275 if ((mix >>> argTypes.size()) != 0) return false;
2276 for (int i = 0; i < argTypes.size(); i++) {
2277 if (i >= 31) break;
2278 boolean bit = (mix & (1 << i)) != 0;
2279 if (bit) {
2280 Class<?> type = argTypes.get(i);
2281 if (type == Object.class)
2282 type = String.class;
2283 else if (type == String.class)
2284 type = int.class;
2285 else
2286 type = Object.class;
2287 argTypes.set(i, type);
2288 }
2289 }
2290 Integer prev = argTypesSeen.put(new ArrayList<>(argTypes), mix);
2291 if (prev != null) {
2292 if (verbosity >= 4) System.out.println("mix "+prev+" repeated "+mix+": "+argTypes);
2293 return false;
2294 }
2295 if (verbosity >= 3) System.out.println("mix "+mix+" = "+argTypes);
2296 return true;
2297 }
2298
2299 void testFoldOrCollectArguments(List<Class<?>> argTypes, // argument types minus the inserted combineType
2300 int pos, int fold, // position and length of the folded arguments
2301 Class<?> combineType, // type returned from the combiner
2302 Class<?> lastType, // type returned from the target
2303 boolean isCollect,
2304 boolean withFoldPos) throws Throwable {
2305 int nargs = argTypes.size();
2306 if (pos != 0 && !isCollect && !withFoldPos) return; // test MethodHandles.foldArguments(MH,MH) only for pos=0
2307 countTest();
2308 List<Class<?>> combineArgTypes = argTypes.subList(pos, pos + fold);
2309 List<Class<?>> targetArgTypes = new ArrayList<>(argTypes);
2310 if (isCollect) // does target see arg[pos..pos+cc-1]?
2311 targetArgTypes.subList(pos, pos + fold).clear();
2312 if (combineType != void.class)
2313 targetArgTypes.add(pos, combineType);
2314 MethodHandle target = varargsList(targetArgTypes, lastType);
2315 MethodHandle combine = varargsList(combineArgTypes, combineType);
2316 List<Object> argsToPass = Arrays.asList(randomArgs(argTypes));
2317 if (verbosity >= 3)
2318 System.out.println((isCollect ? "collect" : "fold")+" "+target+" with "+combine);
2319 MethodHandle target2;
2320 if (isCollect)
2321 target2 = MethodHandles.collectArguments(target, pos, combine);
2322 else
2323 target2 = withFoldPos ? MethodHandles.foldArguments(target, pos, combine) : MethodHandles.foldArguments(target, combine);
2324 // Simulate expected effect of combiner on arglist:
2325 List<Object> expectedList = new ArrayList<>(argsToPass);
2326 List<Object> argsToFold = expectedList.subList(pos, pos + fold);
2327 if (verbosity >= 3)
2328 System.out.println((isCollect ? "collect" : "fold")+": "+argsToFold+" into "+target2);
2329 Object foldedArgs = combine.invokeWithArguments(argsToFold);
2330 if (isCollect)
2331 argsToFold.clear();
2332 if (combineType != void.class)
2333 argsToFold.add(0, foldedArgs);
2334 Object result = target2.invokeWithArguments(argsToPass);
2335 if (verbosity >= 3)
2336 System.out.println("result: "+result);
2337 Object expected = target.invokeWithArguments(expectedList);
2338 if (!expected.equals(result))
2339 System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result+" != "+expected);
2340 assertEquals(expected, result);
2341 }
2342
2343 @Test
2639 int pc = test1.type().parameterCount();
2640 test1 = MethodHandles.insertArguments(test, testArgs, Arrays.copyOfRange(argList1, testArgs, pc));
2641 }
2642 MethodHandle mh = MethodHandles.guardWithTest(test1, target, fallback);
2643 assertEquals(target.type(), mh.type());
2644 boolean equals;
2645 switch (nargs) {
2646 case 0: equals = true; break;
2647 case 1: equals = MISSING_ARG.equals(argList[0]); break;
2648 default: equals = argList[0].equals(argList[1]); break;
2649 }
2650 String willCall = (equals ? "targetIfEquals" : "fallbackIfNotEquals");
2651 if (verbosity >= 3)
2652 System.out.println(logEntry(willCall, argList));
2653 Object result = mh.invokeWithArguments(argList1);
2654 assertCalled(willCall, argList);
2655 }
2656 }
2657
2658 @Test
2659 public void testGenericLoopCombinator() throws Throwable {
2660 CodeCacheOverflowProcessor.runMHTest(this::testGenericLoopCombinator0);
2661 }
2662 public void testGenericLoopCombinator0() throws Throwable {
2663 if (CAN_SKIP_WORKING) return;
2664 startTest("loop");
2665 // Test as follows:
2666 // * Have an increasing number of loop-local state. Local state type diversity grows with the number.
2667 // * Initializers set the starting value of loop-local state from the corresponding loop argument.
2668 // * For each local state element, there is a predicate - for all state combinations, exercise all predicates.
2669 // * Steps modify each local state element in each iteration.
2670 // * Finalizers group all local state elements into a resulting array. Verify end values.
2671 // * Exercise both pre- and post-checked loops.
2672 // Local state types, start values, predicates, and steps:
2673 // * int a, 0, a < 7, a = a + 1
2674 // * double b, 7.0, b > 0.5, b = b / 2.0
2675 // * String c, "start", c.length <= 9, c = c + a
2676 final Class<?>[] argTypes = new Class<?>[] {int.class, double.class, String.class};
2677 final Object[][] args = new Object[][] {
2678 new Object[]{0 },
2679 new Object[]{0, 7.0 },
2680 new Object[]{0, 7.0, "start"}
2681 };
2682 // These are the expected final state tuples for argument type tuple / predicate combinations, for pre- and
2683 // post-checked loops:
2684 final Object[][] preCheckedResults = new Object[][] {
2685 new Object[]{7 }, // (int) / int
2686 new Object[]{7, 0.0546875 }, // (int,double) / int
2687 new Object[]{5, 0.4375 }, // (int,double) / double
2688 new Object[]{7, 0.0546875, "start1234567"}, // (int,double,String) / int
2689 new Object[]{5, 0.4375, "start1234" }, // (int,double,String) / double
2690 new Object[]{6, 0.109375, "start12345" } // (int,double,String) / String
2691 };
2692 final Object[][] postCheckedResults = new Object[][] {
2693 new Object[]{7 }, // (int) / int
2694 new Object[]{7, 0.109375 }, // (int,double) / int
2695 new Object[]{4, 0.4375 }, // (int,double) / double
2696 new Object[]{7, 0.109375, "start123456"}, // (int,double,String) / int
2697 new Object[]{4, 0.4375, "start123" }, // (int,double,String) / double
2698 new Object[]{5, 0.21875, "start12345" } // (int,double,String) / String
2699 };
2700 final Lookup l = MethodHandles.lookup();
2701 final Class<?> MHT = MethodHandlesTest.class;
2702 final Class<?> B = boolean.class;
2703 final Class<?> I = int.class;
2704 final Class<?> D = double.class;
2705 final Class<?> S = String.class;
2706 final MethodHandle hip = l.findStatic(MHT, "loopIntPred", methodType(B, I));
2707 final MethodHandle hdp = l.findStatic(MHT, "loopDoublePred", methodType(B, I, D));
2708 final MethodHandle hsp = l.findStatic(MHT, "loopStringPred", methodType(B, I, D, S));
2709 final MethodHandle his = l.findStatic(MHT, "loopIntStep", methodType(I, I));
2710 final MethodHandle hds = l.findStatic(MHT, "loopDoubleStep", methodType(D, I, D));
2711 final MethodHandle hss = l.findStatic(MHT, "loopStringStep", methodType(S, I, D, S));
2712 final MethodHandle[] preds = new MethodHandle[] {hip, hdp, hsp};
2713 final MethodHandle[] steps = new MethodHandle[] {his, hds, hss};
2714 for (int nargs = 1, useResultsStart = 0; nargs <= argTypes.length; useResultsStart += nargs++) {
2715 Class<?>[] useArgTypes = Arrays.copyOf(argTypes, nargs, Class[].class);
2716 MethodHandle[] usePreds = Arrays.copyOf(preds, nargs, MethodHandle[].class);
2717 MethodHandle[] useSteps = Arrays.copyOf(steps, nargs, MethodHandle[].class);
2718 Object[] useArgs = args[nargs - 1];
2719 Object[][] usePreCheckedResults = new Object[nargs][];
2720 Object[][] usePostCheckedResults = new Object[nargs][];
2721 System.arraycopy(preCheckedResults, useResultsStart, usePreCheckedResults, 0, nargs);
2722 System.arraycopy(postCheckedResults, useResultsStart, usePostCheckedResults, 0, nargs);
2723 testGenericLoopCombinator(nargs, useArgTypes, usePreds, useSteps, useArgs, usePreCheckedResults,
2724 usePostCheckedResults);
2725 }
2726 }
2727 void testGenericLoopCombinator(int nargs, Class<?>[] argTypes, MethodHandle[] preds, MethodHandle[] steps,
2728 Object[] args, Object[][] preCheckedResults, Object[][] postCheckedResults)
2729 throws Throwable {
2730 List<Class<?>> lArgTypes = Arrays.asList(argTypes);
2731 // Predicate and step handles are passed in as arguments, initializer and finalizer handles are constructed here
2732 // from the available information.
2733 MethodHandle[] inits = new MethodHandle[nargs];
2734 for (int i = 0; i < nargs; ++i) {
2735 MethodHandle h;
2736 // Initializers are meant to return whatever they are passed at a given argument position. This means that
2737 // additional arguments may have to be appended and prepended.
2738 h = MethodHandles.identity(argTypes[i]);
2739 if (i < nargs - 1) {
2740 h = MethodHandles.dropArguments(h, 1, lArgTypes.subList(i + 1, nargs));
2741 }
2742 if (i > 0) {
2743 h = MethodHandles.dropArguments(h, 0, lArgTypes.subList(0, i));
2744 }
2745 inits[i] = h;
2746 }
2747 // Finalizers are all meant to collect all of the loop-local state in a single array and return that. Local
2748 // state is passed before the loop args. Construct such a finalizer by first taking a varargsArray collector for
2749 // the number of local state arguments, and then appending the loop args as to-be-dropped arguments.
2750 MethodHandle[] finis = new MethodHandle[nargs];
2751 MethodHandle genericFini = MethodHandles.dropArguments(
2752 varargsArray(nargs).asType(methodType(Object[].class, lArgTypes)), nargs, lArgTypes);
2753 Arrays.fill(finis, genericFini);
2754 // The predicate and step handles' signatures need to be extended. They currently just accept local state args;
2755 // append possibly missing local state args and loop args using dropArguments.
2756 for (int i = 0; i < nargs; ++i) {
2757 List<Class<?>> additionalLocalStateArgTypes = lArgTypes.subList(i + 1, nargs);
2758 preds[i] = MethodHandles.dropArguments(
2759 MethodHandles.dropArguments(preds[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes);
2760 steps[i] = MethodHandles.dropArguments(
2761 MethodHandles.dropArguments(steps[i], i + 1, additionalLocalStateArgTypes), nargs, lArgTypes);
2762 }
2763 // Iterate over all of the predicates, using only one of them at a time.
2764 for (int i = 0; i < nargs; ++i) {
2765 MethodHandle[] usePreds;
2766 if (nargs == 1) {
2767 usePreds = preds;
2768 } else {
2769 // Create an all-null preds array, and only use one predicate in this iteration. The null entries will
2770 // be substituted with true predicates by the loop combinator.
2771 usePreds = new MethodHandle[nargs];
2772 usePreds[i] = preds[i];
2773 }
2774 // Go for it.
2775 if (verbosity >= 3) {
2776 System.out.println("calling loop for argument types " + lArgTypes + " with predicate at index " + i);
2777 if (verbosity >= 5) {
2778 System.out.println("predicates: " + Arrays.asList(usePreds));
2779 }
2780 }
2781 MethodHandle[] preInits = new MethodHandle[nargs + 1];
2782 MethodHandle[] prePreds = new MethodHandle[nargs + 1];
2783 MethodHandle[] preSteps = new MethodHandle[nargs + 1];
2784 MethodHandle[] preFinis = new MethodHandle[nargs + 1];
2785 System.arraycopy(inits, 0, preInits, 1, nargs);
2786 System.arraycopy(usePreds, 0, prePreds, 0, nargs); // preds are offset by 1 for pre-checked loops
2787 System.arraycopy(steps, 0, preSteps, 1, nargs);
2788 System.arraycopy(finis, 0, preFinis, 0, nargs); // finis are also offset by 1 for pre-checked loops
2789 // Convert to clause-major form.
2790 MethodHandle[][] preClauses = new MethodHandle[nargs+1][4];
2791 MethodHandle[][] postClauses = new MethodHandle[nargs][4];
2792 toClauseMajor(preClauses, preInits, preSteps, prePreds, preFinis);
2793 toClauseMajor(postClauses, inits, steps, usePreds, finis);
2794 MethodHandle pre = MethodHandles.loop(preClauses);
2795 MethodHandle post = MethodHandles.loop(postClauses);
2796 Object[] preResults = (Object[]) pre.invokeWithArguments(args);
2797 if (verbosity >= 4) {
2798 System.out.println("pre-checked: expected " + Arrays.asList(preCheckedResults[i]) + ", actual " +
2799 Arrays.asList(preResults));
2800 }
2801 Object[] postResults = (Object[]) post.invokeWithArguments(args);
2802 if (verbosity >= 4) {
2803 System.out.println("post-checked: expected " + Arrays.asList(postCheckedResults[i]) + ", actual " +
2804 Arrays.asList(postResults));
2805 }
2806 assertArrayEquals(preCheckedResults[i], preResults);
2807 assertArrayEquals(postCheckedResults[i], postResults);
2808 }
2809 }
2810 static void toClauseMajor(MethodHandle[][] clauses, MethodHandle[] init, MethodHandle[] step, MethodHandle[] pred, MethodHandle[] fini) {
2811 for (int i = 0; i < clauses.length; ++i) {
2812 clauses[i][0] = init[i];
2813 clauses[i][1] = step[i];
2814 clauses[i][2] = pred[i];
2815 clauses[i][3] = fini[i];
2816 }
2817 }
2818 static boolean loopIntPred(int a) {
2819 if (verbosity >= 5) {
2820 System.out.println("int pred " + a + " -> " + (a < 7));
2821 }
2822 return a < 7;
2823 }
2824 static boolean loopDoublePred(int a, double b) {
2825 if (verbosity >= 5) {
2826 System.out.println("double pred (a=" + a + ") " + b + " -> " + (b > 0.5));
2827 }
2828 return b > 0.5;
2829 }
2830 static boolean loopStringPred(int a, double b, String c) {
2831 if (verbosity >= 5) {
2832 System.out.println("String pred (a=" + a + ",b=" + b + ") " + c + " -> " + (c.length() <= 9));
2833 }
2834 return c.length() <= 9;
2835 }
2836 static int loopIntStep(int a) {
2837 if (verbosity >= 5) {
2838 System.out.println("int step " + a + " -> " + (a + 1));
2839 }
2840 return a + 1;
2841 }
2842 static double loopDoubleStep(int a, double b) {
2843 if (verbosity >= 5) {
2844 System.out.println("double step (a=" + a + ") " + b + " -> " + (b / 2.0));
2845 }
2846 return b / 2.0;
2847 }
2848 static String loopStringStep(int a, double b, String c) {
2849 if (verbosity >= 5) {
2850 System.out.println("String step (a=" + a + ",b=" + b + ") " + c + " -> " + (c + a));
2851 }
2852 return c + a;
2853 }
2854
2855 @Test
2856 public void testThrowException() throws Throwable {
2857 CodeCacheOverflowProcessor.runMHTest(this::testThrowException0);
2858 }
2859
2860 public void testThrowException0() throws Throwable {
2861 if (CAN_SKIP_WORKING) return;
2862 startTest("throwException");
2863 testThrowException(int.class, new ClassCastException("testing"));
2864 testThrowException(void.class, new java.io.IOException("testing"));
2865 testThrowException(String.class, new LinkageError("testing"));
2866 }
2867
2868 void testThrowException(Class<?> returnType, Throwable thrown) throws Throwable {
2869 countTest();
2870 Class<? extends Throwable> exType = thrown.getClass();
2871 MethodHandle target = MethodHandles.throwException(returnType, exType);
2872 //System.out.println("throwing with "+target+" : "+thrown);
2873 MethodType expectedType = MethodType.methodType(returnType, exType);
2874 assertEquals(expectedType, target.type());
2875 target = target.asType(target.type().generic());
2876 Throwable caught = null;
2877 try {
2878 Object res = target.invokeExact((Object) thrown);
2879 fail("got "+res+" instead of throwing "+thrown);
2880 } catch (Throwable ex) {
2881 if (ex != thrown) {
2882 if (ex instanceof Error) throw (Error)ex;
2883 if (ex instanceof RuntimeException) throw (RuntimeException)ex;
2884 }
2885 caught = ex;
2886 }
2887 assertSame(thrown, caught);
2888 }
2889
2890 @Test
2891 public void testTryFinally() throws Throwable {
2892 CodeCacheOverflowProcessor.runMHTest(this::testTryFinally0);
2893 }
2894 public void testTryFinally0() throws Throwable {
2895 if (CAN_SKIP_WORKING) return;
2896 startTest("tryFinally");
2897 String inputMessage = "returned";
2898 String augmentedMessage = "augmented";
2899 String thrownMessage = "thrown";
2900 String rethrownMessage = "rethrown";
2901 // Test these cases:
2902 // * target returns, cleanup passes through
2903 // * target returns, cleanup augments
2904 // * target throws, cleanup augments and returns
2905 // * target throws, cleanup augments and rethrows
2906 MethodHandle target = MethodHandles.identity(String.class);
2907 MethodHandle targetThrow = MethodHandles.dropArguments(
2908 MethodHandles.throwException(String.class, Exception.class).bindTo(new Exception(thrownMessage)), 0, String.class);
2909 MethodHandle cleanupPassThrough = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0,
2910 Throwable.class, String.class);
2911 MethodHandle cleanupAugment = MethodHandles.dropArguments(MethodHandles.constant(String.class, augmentedMessage),
2912 0, Throwable.class, String.class, String.class);
2913 MethodHandle cleanupCatch = MethodHandles.dropArguments(MethodHandles.constant(String.class, thrownMessage), 0,
2914 Throwable.class, String.class, String.class);
2915 MethodHandle cleanupThrow = MethodHandles.dropArguments(MethodHandles.throwException(String.class, Exception.class).
2916 bindTo(new Exception(rethrownMessage)), 0, Throwable.class, String.class, String.class);
2917 testTryFinally(target, cleanupPassThrough, inputMessage, inputMessage, false);
2918 testTryFinally(target, cleanupAugment, inputMessage, augmentedMessage, false);
2919 testTryFinally(targetThrow, cleanupCatch, inputMessage, thrownMessage, true);
2920 testTryFinally(targetThrow, cleanupThrow, inputMessage, rethrownMessage, true);
2921 // Test the same cases as above for void targets and cleanups.
2922 MethodHandles.Lookup lookup = MethodHandles.lookup();
2923 Class<?> C = this.getClass();
2924 MethodType targetType = methodType(void.class, String[].class);
2925 MethodType cleanupType = methodType(void.class, Throwable.class, String[].class);
2926 MethodHandle vtarget = lookup.findStatic(C, "vtarget", targetType);
2927 MethodHandle vtargetThrow = lookup.findStatic(C, "vtargetThrow", targetType);
2928 MethodHandle vcleanupPassThrough = lookup.findStatic(C, "vcleanupPassThrough", cleanupType);
2929 MethodHandle vcleanupAugment = lookup.findStatic(C, "vcleanupAugment", cleanupType);
2930 MethodHandle vcleanupCatch = lookup.findStatic(C, "vcleanupCatch", cleanupType);
2931 MethodHandle vcleanupThrow = lookup.findStatic(C, "vcleanupThrow", cleanupType);
2932 testTryFinally(vtarget, vcleanupPassThrough, inputMessage, inputMessage, false);
2933 testTryFinally(vtarget, vcleanupAugment, inputMessage, augmentedMessage, false);
2934 testTryFinally(vtargetThrow, vcleanupCatch, inputMessage, thrownMessage, true);
2935 testTryFinally(vtargetThrow, vcleanupThrow, inputMessage, rethrownMessage, true);
2936 }
2937 void testTryFinally(MethodHandle target, MethodHandle cleanup, String input, String msg, boolean mustCatch)
2938 throws Throwable {
2939 countTest();
2940 MethodHandle tf = MethodHandles.tryFinally(target, cleanup);
2941 String result = null;
2942 boolean isVoid = target.type().returnType() == void.class;
2943 String[] argArray = new String[]{input};
2944 try {
2945 if (isVoid) {
2946 tf.invoke(argArray);
2947 } else {
2948 result = (String) tf.invoke(input);
2949 }
2950 } catch (Throwable t) {
2951 assertTrue(mustCatch);
2952 assertEquals(msg, t.getMessage());
2953 return;
2954 }
2955 assertFalse(mustCatch);
2956 if (isVoid) {
2957 assertEquals(msg, argArray[0]);
2958 } else {
2959 assertEquals(msg, result);
2960 }
2961 }
2962 static void vtarget(String[] a) {
2963 // naught, akin to identity
2964 }
2965 static void vtargetThrow(String[] a) throws Exception {
2966 throw new Exception("thrown");
2967 }
2968 static void vcleanupPassThrough(Throwable t, String[] a) {
2969 assertNull(t);
2970 // naught, akin to identity
2971 }
2972 static void vcleanupAugment(Throwable t, String[] a) {
2973 assertNull(t);
2974 a[0] = "augmented";
2975 }
2976 static void vcleanupCatch(Throwable t, String[] a) {
2977 assertNotNull(t);
2978 a[0] = "caught";
2979 }
2980 static void vcleanupThrow(Throwable t, String[] a) throws Exception {
2981 assertNotNull(t);
2982 throw new Exception("rethrown");
2983 }
2984
2985 @Test
2986 public void testInterfaceCast() throws Throwable {
2987 CodeCacheOverflowProcessor.runMHTest(this::testInterfaceCast0);
2988 }
2989
2990 public void testInterfaceCast0() throws Throwable {
2991 if (CAN_SKIP_WORKING) return;
2992 startTest("interfaceCast");
2993 assert( (((Object)"foo") instanceof CharSequence));
2994 assert(!(((Object)"foo") instanceof Iterable));
2995 for (MethodHandle mh : new MethodHandle[]{
2996 MethodHandles.identity(String.class),
2997 MethodHandles.identity(CharSequence.class),
2998 MethodHandles.identity(Iterable.class)
2999 }) {
3000 if (verbosity > 0) System.out.println("-- mh = "+mh);
3001 for (Class<?> ctype : new Class<?>[]{
3002 Object.class, String.class, CharSequence.class,
3003 Number.class, Iterable.class
3004 }) {
3005 if (verbosity > 0) System.out.println("---- ctype = "+ctype.getName());
3006 // doret docast
3007 testInterfaceCast(mh, ctype, false, false);
3008 testInterfaceCast(mh, ctype, true, false);
3009 testInterfaceCast(mh, ctype, false, true);
3010 testInterfaceCast(mh, ctype, true, true);
3011 }
|