changeset 16:bff20cf185b1

meth: {collect,spread,fold}Arguments working; better test output
author jrose
date Wed, 10 Jun 2009 04:17:20 -0700
parents 800a2c2ff01d
children 4a545756cc3d
files netbeans/meth/test/jdk/java/dyn/MethodHandlesTest.java
diffstat 1 files changed, 122 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/netbeans/meth/test/jdk/java/dyn/MethodHandlesTest.java	Mon Jun 08 23:03:59 2009 -0700
+++ b/netbeans/meth/test/jdk/java/dyn/MethodHandlesTest.java	Wed Jun 10 04:17:20 2009 -0700
@@ -53,17 +53,26 @@
     @Test
     public void testFirst() {
         // left blank for debugging
+        testCollectArguments(Object.class, 0, 2);
     }
 
     // current failures
     @Test @Ignore("failure in call to makeRawRetypeOnly in ToGeneric")
     public void testFail_1() {
-        testSpreadArguments(int.class, 6);
+        testSpreadArguments(int.class, 0, 6);
     }
     @Test @Ignore("failure in JVM when expanding the stack")
     public void testFail_2() {
         // if CONV_OP_IMPLEMENTED_MASK includes OP_SPREAD_ARGS, this crashes:
-        testSpreadArguments(Object.class, 2);
+        testSpreadArguments(Object.class, 0, 2);
+    }
+    @Test @Ignore("IllArgEx failure in call to ToGeneric.make")
+    public void testFail_3() {
+        testSpreadArguments(int.class, 1, 2);
+    }
+    @Test @Ignore("IllArgEx failure in call to ToGeneric.make")
+    public void testFail_4() {
+        testCollectArguments(int.class, 1, 2);
     }
 
     public MethodHandlesTest() {
@@ -189,6 +198,19 @@
         return x.getClass().getSimpleName();
     }
 
+    static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
+        return changeArgTypes(target, 0, 999, argType);
+    }
+    static MethodHandle changeArgTypes(MethodHandle target,
+            int beg, int end, Class<?> argType) {
+        MethodType targetType = target.type();
+        end = Math.min(end, targetType.parameterCount());
+        ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>(targetType.parameterList());
+        Collections.fill(argTypes.subList(beg, end), argType);
+        MethodType ttype2 = MethodType.make(targetType.returnType(), argTypes);
+        return MethodHandles.convertArguments(target, ttype2);
+    }
+
     // This lookup is good for all members in and under MethodHandlesTest.
     static final Lookup PRIVATE = MethodHandles.lookup();
     // This lookup is good for package-private members but not private ones.
@@ -313,8 +335,9 @@
         } catch (NoAccessException ex) {
             noAccess = ex;
         }
-//        System.out.println("findStatic "+lookup+": "+defc+"."+name+"/"+type+" => "+target
-//                +(noAccess == null ? "" : " !! "+noAccess));
+        if (verbosity >= 2)
+            System.out.println("findStatic "+lookup+": "+defc+"."+name+"/"+type+" => "+target
+                    +(noAccess == null ? "" : " !! "+noAccess));
         if (positive && noAccess != null)  throw noAccess;
         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
         if (!positive)  return; // negative test failed as expected
@@ -374,8 +397,9 @@
         } catch (NoAccessException ex) {
             noAccess = ex;
         }
-//        System.out.println("findVirtual "+lookup+": "+defc+"."+name+"/"+type+" => "+target
-//                +(noAccess == null ? "" : " !! "+noAccess));
+        if (verbosity >= 2)
+            System.out.println("findVirtual "+lookup+": "+defc+"."+name+"/"+type+" => "+target
+                    +(noAccess == null ? "" : " !! "+noAccess));
         if (positive && noAccess != null)  throw noAccess;
         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
         if (!positive)  return; // negative test failed as expected
@@ -419,8 +443,9 @@
         } catch (NoAccessException ex) {
             noAccess = ex;
         }
-//        System.out.println("findSpecial "+defc+"."+name+"/"+type+" => "+target
-//                +(noAccess == null ? "" : " !! "+noAccess));
+        if (verbosity >= 2)
+            System.out.println("findSpecial "+defc+"."+name+"/"+type+" => "+target
+                    +(noAccess == null ? "" : " !! "+noAccess));
         if (positive && noAccess != null)  throw noAccess;
         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
         if (!positive)  return; // negative test failed as expected
@@ -474,8 +499,9 @@
         } catch (NoAccessException ex) {
             noAccess = ex;
         }
-//        System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
-//                +(noAccess == null ? "" : " !! "+noAccess));
+        if (verbosity >= 2)
+            System.out.println("bind "+receiver+"."+name+"/"+type+" => "+target
+                    +(noAccess == null ? "" : " !! "+noAccess));
         if (positive && noAccess != null)  throw noAccess;
         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
         if (!positive)  return; // negative test failed as expected
@@ -536,8 +562,9 @@
         } catch (NoAccessException ex) {
             noAccess = ex;
         }
-        System.out.println("unreflect "+defc+"."+name+"/"+type+" => "+target
-                +(noAccess == null ? "" : " !! "+noAccess));
+        if (verbosity >= 2)
+            System.out.println("unreflect "+defc+"."+name+"/"+type+" => "+target
+                    +(noAccess == null ? "" : " !! "+noAccess));
         if (positive && noAccess != null)  throw noAccess;
         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
         if (!positive)  return; // negative test failed as expected
@@ -682,8 +709,9 @@
         } catch (RuntimeException ex) {
             error = ex;
         }
-        //System.out.println("convert "+id+ " to "+newType+" => "+target
-        //        +(error == null ? "" : " !! "+error));
+        if (verbosity >= 2)
+            System.out.println("convert "+id+ " to "+newType+" => "+target
+                    +(error == null ? "" : " !! "+error));
         if (positive && error != null)  throw error;
         assertEquals(positive ? "positive test" : "negative test erroneously passed", positive, target != null);
         if (!positive)  return; // negative test failed as expected
@@ -704,16 +732,22 @@
                 System.out.println("spreadArguments "+argType);
             for (int nargs = 0; nargs < 10; nargs++) {
                 if (argType == int.class && nargs >= 6)  continue; // FIXME Fail_1
-                testSpreadArguments(argType, nargs);
+                for (int pos = 0; pos < nargs; pos++) {
+                    if (argType == int.class && pos > 0)  continue; // FIXME Fail_3
+                    testSpreadArguments(argType, pos, nargs);
+                }
             }
         }
     }
-    public void testSpreadArguments(Class<?> argType, int nargs) {
+    public void testSpreadArguments(Class<?> argType, int pos, int nargs) {
+        countTest();
         MethodHandle target = ValueConversions.varargsArray(nargs);
         MethodHandle target2 = changeArgTypes(target, argType);
+        if (verbosity >= 2)
+            System.out.println("spread into "+target2+" ["+pos+".."+nargs+"]");
         Object[] args = randomArgs(target2.type().parameterArray());
         // make sure the target does what we think it does:
-        if (nargs < 5) {
+        if (pos == 0 && nargs < 5) {
             Object[] check = (Object[]) MethodHandles.invoke(target, args);
             assertArrayEquals(args, check);
             switch (nargs) {
@@ -731,29 +765,61 @@
                     break;
             }
         }
-        MethodType newType = MethodType.make(Object.class, Object[].class);
+        List<Class<?>> newParams = new ArrayList<Class<?>>(target2.type().parameterList());
+        {   // modify newParams in place
+            List<Class<?>> spreadParams = newParams.subList(pos, nargs);
+            spreadParams.clear(); spreadParams.add(Object[].class);
+        }
+        MethodType newType = MethodType.make(Object.class, newParams);
         MethodHandle result = MethodHandles.spreadArguments(target2, newType);
-        Object[] returnValue = (Object[]) result.invoke(args);
+        Object[] returnValue;
+        if (pos == 0) {
+            returnValue = (Object[]) result.invoke(args);
+        } else {
+            Object[] args1 = Arrays.copyOfRange(args, 0, pos+1);
+            args1[pos] = Arrays.copyOfRange(args, pos, args.length);
+            returnValue = (Object[]) MethodHandles.invoke(result, args1);
+        }
         assertArrayEquals(args, returnValue);
     }
 
-    static MethodHandle changeArgTypes(MethodHandle target, Class<?> argType) {
-        ArrayList<Class<?>> argTypes = new ArrayList<Class<?>>();
-        for (int j = 0; j < target.type().parameterCount(); j++)
-            argTypes.add(argType);
-        MethodType ttype2 = MethodType.make(target.type().returnType(), argTypes);
-        return MethodHandles.convertArguments(target, ttype2);
+    @Test
+    public void testCollectArguments() {
+        if (CAN_SKIP_WORKING)  return;
+        startTest("collectArguments");
+        for (Class<?> argType : new Class[]{Object.class, Integer.class, int.class}) {
+            if (verbosity >= 2)
+                System.out.println("collectArguments "+argType);
+            for (int nargs = 0; nargs < 10; nargs++) {
+                for (int pos = 0; pos < nargs; pos++) {
+                    if (argType == int.class)  continue; // FIXME Fail_4
+                    testCollectArguments(argType, pos, nargs);
+                }
+            }
+        }
     }
-
-    @Test @Ignore("unimplemented")
-    public void testCollectArguments() {
-        startTest("collectArguments");
-        MethodHandle target = null;
-        MethodType newType = null;
-        MethodHandle expResult = null;
+    public void testCollectArguments(Class<?> argType, int pos, int nargs) {
+        countTest();
+        // fake up a MH with the same type as the desired adapter:
+        MethodHandle fake = ValueConversions.varargsArray(nargs);
+        fake = changeArgTypes(fake, argType);
+        MethodType newType = fake.type();
+        Object[] args = randomArgs(newType.parameterArray());
+        // here is what should happen:
+        Object[] collectedArgs = Arrays.copyOfRange(args, 0, pos+1);
+        collectedArgs[pos] = Arrays.copyOfRange(args, pos, args.length);
+        // here is the MH which will witness the collected argument tail:
+        MethodHandle target = ValueConversions.varargsArray(pos+1);
+        target = changeArgTypes(target, 0, pos, argType);
+        target = changeArgTypes(target, pos, pos+1, Object[].class);
+        if (verbosity >= 2)
+            System.out.println("collect from "+Arrays.asList(args)+" ["+pos+".."+nargs+"]");
         MethodHandle result = MethodHandles.collectArguments(target, newType);
-        assertEquals(expResult, result);
-        fail("The test case is a prototype.");
+        Object[] returnValue = (Object[]) MethodHandles.invoke(result, args);
+//        assertTrue(returnValue.length == pos+1 && returnValue[pos] instanceof Object[]);
+//        returnValue[pos] = Arrays.asList((Object[]) returnValue[pos]);
+//        collectedArgs[pos] = Arrays.asList((Object[]) collectedArgs[pos]);
+        assertArrayEquals(collectedArgs, returnValue);
     }
 
     @Test
@@ -770,6 +836,7 @@
     }
 
     void testInsertArguments(int nargs, int pos, int ins) {
+        countTest();
         MethodHandle target = ValueConversions.varargsArray(nargs + ins);
         Object[] args = randomArgs(target.type().parameterArray());
         List<Object> resList = Arrays.asList(args);
@@ -777,22 +844,24 @@
         List<Object> argsToInsert = argsToPass.subList(pos, pos + ins);
         MethodHandle target2 = MethodHandles.insertArguments(target, pos,
                 (Object[]) argsToInsert.toArray());
-        //System.out.println("insert: "+argsToInsert+" into "+target2);
+        if (verbosity >= 2)
+            System.out.println("insert: "+argsToInsert+" into "+target2);
         argsToInsert.clear();  // remove from argsToInsert
         Object res2 = MethodHandles.invoke(target2, argsToPass.toArray());
         Object res2List = Arrays.asList((Object[])res2);
-        //System.out.println("result: "+res2List);
+        if (verbosity >= 2)
+            System.out.println("result: "+res2List);
         //if (!resList.equals(res2List))
         //    System.out.println("*** fail at n/p/i = "+nargs+"/"+pos+"/"+ins+": "+resList+" => "+res2List);
         assertEquals(resList, res2List);
     }
 
-    @Test @Ignore("in progress")
+    @Test
     public void testFoldArguments() {
-        //if (CAN_SKIP_WORKING)  return;
+        if (CAN_SKIP_WORKING)  return;
         startTest("foldArguments");
         for (int nargs = 0; nargs <= 4; nargs++) {
-            for (int fold = 0; fold <= 4; fold++) {
+            for (int fold = 0; fold <= nargs; fold++) {
                 for (int pos = 0; pos <= nargs; pos++) {
                     testFoldArguments(nargs, pos, fold);
                 }
@@ -802,19 +871,23 @@
 
     void testFoldArguments(int nargs, int pos, int fold) {
         if (pos != 0)  return;  // can fold only at pos=0 for now
+        countTest();
         MethodHandle target = ValueConversions.varargsList(1 + nargs);
         MethodHandle combine = ValueConversions.varargsList(fold);
-        List<Object> argsToPass = Arrays.asList(randomArgs(fold + nargs, Object.class));
-        System.out.println("fold "+target+" with "+combine);
-        MethodHandle target2 = MethodHandles.foldArguments(target, combine, fold);
+        List<Object> argsToPass = Arrays.asList(randomArgs(nargs, Object.class));
+        if (verbosity >= 2)
+            System.out.println("fold "+target+" with "+combine);
+        MethodHandle target2 = MethodHandles.foldArguments(target, combine);
         // Simulate expected effect of combiner on arglist:
         List<Object> expected = new ArrayList<Object>(argsToPass);
         List<Object> argsToFold = expected.subList(pos, pos + fold);
-        System.out.println("fold: "+argsToFold+" into "+target2);
+        if (verbosity >= 2)
+            System.out.println("fold: "+argsToFold+" into "+target2);
         Object foldedArgs = MethodHandles.invoke(combine, argsToFold.toArray());
-        argsToFold.clear(); argsToFold.add(foldedArgs);
+        argsToFold.add(0, foldedArgs);
         Object result = MethodHandles.invoke(target2, argsToPass.toArray());
-        System.out.println("result: "+result);
+        if (verbosity >= 2)
+            System.out.println("result: "+result);
         if (!expected.equals(result))
             System.out.println("*** fail at n/p/f = "+nargs+"/"+pos+"/"+fold+": "+argsToPass+" => "+result);
         assertEquals(expected, result);
@@ -834,6 +907,7 @@
     }
 
     void testDropArguments(int nargs, int pos, int drop) {
+        countTest();
         MethodHandle target = ValueConversions.varargsArray(nargs);
         Object[] args = randomArgs(target.type().parameterArray());
         MethodHandle target2 = MethodHandles.dropArguments(target, pos,
@@ -893,6 +967,7 @@
         }
     }
     void testGuardWithTest(int nargs, Class<?> argClass) {
+        countTest();
         MethodHandle test = PRIVATE.findVirtual(Object.class, "equals", MethodType.make(boolean.class, Object.class));
         MethodHandle target = PRIVATE.findStatic(MethodHandlesTest.class, "targetIfEquals", MethodType.makeGeneric(nargs));
         MethodHandle fallback = PRIVATE.findStatic(MethodHandlesTest.class, "fallbackIfNotEquals", MethodType.makeGeneric(nargs));
@@ -950,6 +1025,7 @@
     }
 
     void testCatchException(Class<?> returnType, Throwable thrown, boolean throwIt, int nargs) {
+        countTest();
         Class<? extends Throwable> exType = thrown.getClass();
         MethodHandle throwOrReturn
                 = PRIVATE.findStatic(MethodHandlesTest.class, "throwOrReturn",
@@ -984,6 +1060,7 @@
     }
 
     void testThrowException(Class<?> returnType, Throwable thrown) {
+        countTest();
         Class<? extends Throwable> exType = thrown.getClass();
         MethodHandle target = MethodHandles.throwException(returnType, exType);
         //System.out.println("throwing with "+target+" : "+thrown);