changeset 19:afa2631a7ed5

meth: tests for {permute,filter}Arguments, {exact,generic,varargs,dynamic}invoker
author jrose
date Fri, 19 Jun 2009 03:02:04 -0700
parents ebfb233ce72a
children fa6241266623
files netbeans/meth/test/jdk/java/dyn/MethodHandlesTest.java
diffstat 1 files changed, 223 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/netbeans/meth/test/jdk/java/dyn/MethodHandlesTest.java	Sat Jun 13 00:06:45 2009 -0700
+++ b/netbeans/meth/test/jdk/java/dyn/MethodHandlesTest.java	Fri Jun 19 03:02:04 2009 -0700
@@ -29,18 +29,9 @@
 import sun.dyn.util.Wrapper;
 import java.dyn.*;
 import java.dyn.MethodHandles.Lookup;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Ignore;
-import org.junit.Test;
+import java.lang.reflect.*;
+import java.util.*;
+import org.junit.*;
 import sun.dyn.util.ValueConversions;
 import static org.junit.Assert.*;
 
@@ -52,8 +43,9 @@
 
     @Test
     public void testFirst() throws Throwable {
-        // left blank for debugging
-        testCollectArguments(Object.class, 0, 2);
+        verbosity += 9; try {
+            // left blank for debugging
+        } finally { verbosity -= 9; }
     }
 
     // current failures
@@ -74,6 +66,10 @@
     public void testFail_4() throws Throwable {
         testCollectArguments(int.class, 1, 2);
     }
+    @Test @Ignore("cannot collect leading primitive types")
+    public void testFail_5() throws Throwable {
+        testInvokers(MethodType.makeGeneric(2).changeParameterType(0, int.class));
+    }
 
     public MethodHandlesTest() {
     }
@@ -665,9 +661,9 @@
     }
 
     @Test
-    public void testConvertArguments_pairwise() throws Throwable {
+    public void testConvertArguments() throws Throwable {
         if (CAN_SKIP_WORKING)  return;
-        startTest("convertArguments/pairwise");
+        startTest("convertArguments");
         testConvert(Callee.ofType(1), null, "id", int.class);
         testConvert(Callee.ofType(1), null, "id", String.class);
         testConvert(Callee.ofType(1), null, "id", Integer.class);
@@ -724,6 +720,47 @@
     }
 
     @Test
+    public void testPermuteArguments() throws Throwable {
+        if (CAN_SKIP_WORKING)  return;
+        startTest("permuteArguments");
+        for (int inargs = 1; inargs <= 4; inargs++) {
+            Object[] args = randomArgs(inargs, Integer.class);
+            int numcases = 1;
+            for (int outargs = 0; outargs <= 4; outargs++) {
+                int[] reorder = new int[outargs];
+                for (int cas = 0; cas < numcases; cas++) {
+                    for (int i = 0, c = cas; i < outargs; i++) {
+                        reorder[i] = c % inargs;
+                        c /= inargs;
+                    }
+                    testPermuteArguments(args, reorder);
+                }
+                numcases *= inargs;
+            }
+        }
+    }
+
+    void testPermuteArguments(Object[] args, int[] reorder) throws Throwable {
+        countTest();
+        int inargs = args.length, outargs = reorder.length;
+        if (verbosity >= 2)
+            System.out.println("permuteArguments "+Arrays.toString(reorder));
+        Object[] permArgs = new Object[outargs];
+        for (int i = 0; i < outargs; i++)
+            permArgs[i] = args[reorder[i]];
+        if (verbosity >= 3) {
+            System.out.println("in args:  "+Arrays.asList(args));
+            System.out.println("out args: "+Arrays.asList(permArgs));
+        }
+        MethodHandle target = ValueConversions.varargsList(outargs);
+        target = MethodHandles.permuteArguments(target, MethodType.makeGeneric(inargs), reorder);
+        Object result = MethodHandles.invoke(target, args);
+        Object expected = Arrays.asList(permArgs);
+        assertEquals(expected, result);
+    }
+
+
+    @Test
     public void testSpreadArguments() throws Throwable {
         if (CAN_SKIP_WORKING)  return;
         startTest("spreadArguments");
@@ -857,6 +894,40 @@
     }
 
     @Test
+    public void testFilterArguments() throws Throwable {
+        if (CAN_SKIP_WORKING)  return;
+        startTest("filterArguments");
+        for (int nargs = 1; nargs <= 6; nargs++) {
+            for (int pos = 0; pos < nargs; pos++) {
+                testFilterArguments(nargs, pos);
+            }
+        }
+    }
+
+    void testFilterArguments(int nargs, int pos) throws Throwable {
+        countTest();
+        MethodHandle target = ValueConversions.varargsList(nargs);
+        MethodHandle filter = ValueConversions.varargsList(1);
+        filter = MethodHandles.convertArguments(filter, filter.type().generic());
+        Object[] argsToPass = randomArgs(nargs, Object.class);
+        if (verbosity >= 2)
+            System.out.println("filter "+target+" at "+pos+" with "+filter);
+        MethodHandle[] filters = new MethodHandle[pos*2+1];
+        filters[pos] = filter;
+        MethodHandle target2 = MethodHandles.filterArguments(target, filters);
+        // Simulate expected effect of filter on arglist:
+        Object[] filteredArgs = argsToPass.clone();
+        filteredArgs[pos] = filter.invoke(filteredArgs[pos]);
+        List<Object> expected = Arrays.asList(filteredArgs);
+        Object result = MethodHandles.invoke(target2, argsToPass);
+        if (verbosity >= 2)
+            System.out.println("result: "+result);
+        if (!expected.equals(result))
+            System.out.println("*** fail at n/p = "+nargs+"/"+pos+": "+argsToPass+" => "+result);
+        assertEquals(expected, result);
+    }
+
+    @Test
     public void testFoldArguments() throws Throwable {
         if (CAN_SKIP_WORKING)  return;
         startTest("foldArguments");
@@ -924,6 +995,142 @@
         assertEquals(resList, res2List);
     }
 
+    @Test
+    public void testInvokers() throws Throwable {
+        if (CAN_SKIP_WORKING)  return;
+        startTest("exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker");
+        // exactInvoker, genericInvoker, varargsInvoker[0..N], dynamicInvoker
+        Set<MethodType> done = new HashSet<MethodType>();
+        for (int i = 0; i <= 6; i++) {
+            MethodType gtype = MethodType.makeGeneric(i);
+            for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
+                for (int j = -1; j < i; j++) {
+                    MethodType type = gtype;
+                    if (j < 0)
+                        type = type.changeReturnType(argType);
+                    else if (argType == void.class)
+                        continue;
+                    else
+                        type = type.changeParameterType(j, argType);
+                    if (argType.isPrimitive() && j != i-1)  continue; // FIXME Fail_5
+                    if (done.add(type))
+                        testInvokers(type);
+                    MethodType vtype = type.changeReturnType(void.class);
+                    if (done.add(vtype))
+                        testInvokers(vtype);
+                }
+            }
+        }
+    }
+
+    public void testInvokers(MethodType type) throws Throwable {
+        if (verbosity >= 2)
+            System.out.println("test invokers for "+type);
+        int nargs = type.parameterCount();
+        boolean testRetCode = type.returnType() != void.class;
+        MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "invokee",
+                                MethodType.makeGeneric(0, true));
+        target = MethodHandles.collectArguments(target, type);
+        Object[] args = randomArgs(type.parameterArray());
+        List<Object> targetPlusArgs = new ArrayList<Object>(Arrays.asList(args));
+        targetPlusArgs.add(0, target);
+        int code = (Integer) invokee(args);
+        Object log = logEntry("invokee", args);
+        assertEquals(log.hashCode(), code);
+        assertCalled("invokee", args);
+        MethodHandle inv;
+        Object result;
+        // exact invoker
+        countTest();
+        calledLog.clear();
+        inv = MethodHandles.exactInvoker(type);
+        result = MethodHandles.invoke(inv, targetPlusArgs.toArray());
+        if (testRetCode)  assertEquals(code, result);
+        assertCalled("invokee", args);
+        // generic invoker
+        countTest();
+        inv = MethodHandles.genericInvoker(type);
+        if (nargs <= 3) {
+            calledLog.clear();
+            switch (nargs) {
+            case 0:
+                result = inv.invoke(target);
+                break;
+            case 1:
+                result = inv.invoke(target, args[0]);
+                break;
+            case 2:
+                result = inv.invoke(target, args[0], args[1]);
+                break;
+            case 3:
+                result = inv.invoke(target, args[0], args[1], args[2]);
+                break;
+            }
+            if (testRetCode)  assertEquals(code, result);
+            assertCalled("invokee", args);
+        }
+        calledLog.clear();
+        result = MethodHandles.invoke(inv, targetPlusArgs.toArray());
+        if (testRetCode)  assertEquals(code, result);
+        assertCalled("invokee", args);
+        // varargs invoker #0
+        calledLog.clear();
+        inv = MethodHandles.varargsInvoker(type, 0);
+        result = inv.invoke(target, args);
+        if (testRetCode)  assertEquals(code, result);
+        assertCalled("invokee", args);
+        if (nargs >= 1) {
+            // varargs invoker #1
+            calledLog.clear();
+            inv = MethodHandles.varargsInvoker(type, 1);
+            result = inv.invoke(target, args[0], Arrays.copyOfRange(args, 1, nargs));
+            if (testRetCode)  assertEquals(code, result);
+            assertCalled("invokee", args);
+        }
+        if (nargs >= 2) {
+            // varargs invoker #2
+            calledLog.clear();
+            inv = MethodHandles.varargsInvoker(type, 2);
+            result = inv.invoke(target, args[0], args[1], Arrays.copyOfRange(args, 2, nargs));
+            if (testRetCode)  assertEquals(code, result);
+            assertCalled("invokee", args);
+        }
+        if (nargs >= 3) {
+            // varargs invoker #3
+            calledLog.clear();
+            inv = MethodHandles.varargsInvoker(type, 3);
+            result = inv.invoke(target, args[0], args[1], args[2], Arrays.copyOfRange(args, 3, nargs));
+            if (testRetCode)  assertEquals(code, result);
+            assertCalled("invokee", args);
+        }
+        for (int k = 0; k <= nargs; k++) {
+            // varargs invoker #0..N
+            countTest();
+            calledLog.clear();
+            inv = MethodHandles.varargsInvoker(type, k);
+            List<Object> targetPlusVarArgs = new ArrayList<Object>(targetPlusArgs);
+            List<Object> tailList = targetPlusVarArgs.subList(1+k, 1+nargs);
+            Object[] tail = tailList.toArray();
+            tailList.clear(); tailList.add(tail);
+            result = MethodHandles.invoke(inv, targetPlusVarArgs.toArray());
+            if (testRetCode)  assertEquals(code, result);
+            assertCalled("invokee", args);
+        }
+        // dynamic invoker
+        countTest();
+        CallSite site = new CallSite(MethodHandlesTest.class, "foo", type);
+        inv = MethodHandles.dynamicInvoker(site);
+        site.setTarget(target);
+        calledLog.clear();
+        result = MethodHandles.invoke(inv, args);
+        if (testRetCode)  assertEquals(code, result);
+        assertCalled("invokee", args);
+    }
+
+    static Object invokee(Object... args) {
+        return called("invokee", args).hashCode();
+    }
+
     private static final String MISSING_ARG = "missingArg";
     static Object targetIfEquals() {
         return called("targetIfEquals");