jdk/src/share/classes/java/lang/invoke/MethodHandles.java
changeset 9646 5ebbe5ab084f
parent 9645 dabb5e4edc4c
child 9730 e4b334d47f4b
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Thu May 12 19:27:33 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Thu May 12 19:27:49 2011 -0700
@@ -1080,7 +1080,7 @@
             MethodType rawType = mh.type();
             if (rawType.parameterType(0) == caller)  return mh;
             MethodType narrowType = rawType.changeParameterType(0, caller);
-            MethodHandle narrowMH = MethodHandleImpl.convertArguments(mh, narrowType, rawType, null);
+            MethodHandle narrowMH = MethodHandleImpl.convertArguments(mh, narrowType, rawType, 0);
             return fixVarargs(narrowMH, mh);
         }
 
@@ -1377,18 +1377,7 @@
      */
     public static
     MethodHandle convertArguments(MethodHandle target, MethodType newType) {
-        MethodType oldType = target.type();
-        if (oldType.equals(newType))
-            return target;
-        MethodHandle res = null;
-        try {
-            res = MethodHandleImpl.convertArguments(target,
-                                                    newType, oldType, null);
-        } catch (IllegalArgumentException ex) {
-        }
-        if (res == null)
-            throw new WrongMethodTypeException("cannot convert to "+newType+": "+target);
-        return res;
+        return MethodHandleImpl.convertArguments(target, newType, 1);
     }
 
     /**
@@ -1431,7 +1420,7 @@
      */
     public static
     MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
-        return convertArguments(target, newType);  // FIXME!
+        return MethodHandleImpl.convertArguments(target, newType, 2);
     }
 
     /*
@@ -1526,23 +1515,32 @@
     MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
         MethodType oldType = target.type();
         checkReorder(reorder, newType, oldType);
-        return MethodHandleImpl.convertArguments(target,
+        return MethodHandleImpl.permuteArguments(target,
                                                  newType, oldType,
                                                  reorder);
     }
 
     private static void checkReorder(int[] reorder, MethodType newType, MethodType oldType) {
+        if (newType.returnType() != oldType.returnType())
+            throw newIllegalArgumentException("return types do not match",
+                    oldType, newType);
         if (reorder.length == oldType.parameterCount()) {
             int limit = newType.parameterCount();
             boolean bad = false;
-            for (int i : reorder) {
+            for (int j = 0; j < reorder.length; j++) {
+                int i = reorder[j];
                 if (i < 0 || i >= limit) {
                     bad = true; break;
                 }
+                Class<?> src = newType.parameterType(i);
+                Class<?> dst = oldType.parameterType(j);
+                if (src != dst)
+                    throw newIllegalArgumentException("parameter types do not match after reorder",
+                            oldType, newType);
             }
             if (!bad)  return;
         }
-        throw newIllegalArgumentException("bad reorder array");
+        throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder));
     }
 
     /**
@@ -1631,7 +1629,7 @@
             if (type == void.class)
                 throw newIllegalArgumentException("void type");
             Wrapper w = Wrapper.forPrimitiveType(type);
-            return identity(type).bindTo(w.convert(value, type));
+            return insertArguments(identity(type), 0, w.convert(value, type));
         } else {
             return identity(type).bindTo(type.cast(value));
         }
@@ -1866,7 +1864,8 @@
     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
         MethodType targetType = target.type();
         MethodHandle adapter = target;
-        MethodType adapterType = targetType;
+        MethodType adapterType = null;
+        assert((adapterType = targetType) != null);
         int maxPos = targetType.parameterCount();
         if (pos + filters.length > maxPos)
             throw newIllegalArgumentException("too many filters");
@@ -1874,19 +1873,23 @@
         for (MethodHandle filter : filters) {
             curPos += 1;
             if (filter == null)  continue;  // ignore null elements of filters
-            MethodType filterType = filter.type();
-            if (filterType.parameterCount() != 1
-                || filterType.returnType() != targetType.parameterType(curPos))
-                throw newIllegalArgumentException("target and filter types do not match");
-            adapterType = adapterType.changeParameterType(curPos, filterType.parameterType(0));
-            adapter = MethodHandleImpl.filterArgument(adapter, curPos, filter);
+            adapter = filterArgument(adapter, curPos, filter);
+            assert((adapterType = adapterType.changeParameterType(curPos, filter.type().parameterType(0))) != null);
         }
-        MethodType midType = adapter.type();
-        if (midType != adapterType)
-            adapter = MethodHandleImpl.convertArguments(adapter, adapterType, midType, null);
+        assert(adapterType.equals(adapter.type()));
         return adapter;
     }
 
+    /*non-public*/ static
+    MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
+        MethodType targetType = target.type();
+        MethodType filterType = filter.type();
+        if (filterType.parameterCount() != 1
+            || filterType.returnType() != targetType.parameterType(pos))
+            throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+        return MethodHandleImpl.filterArgument(target, pos, filter);
+    }
+
     /**
      * Adapts a target method handle {@code target} by post-processing
      * its return value with a unary filter function.
@@ -1922,14 +1925,26 @@
     MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
         MethodType targetType = target.type();
         MethodType filterType = filter.type();
-        if (filterType.parameterCount() != 1
-            || filterType.parameterType(0) != targetType.returnType())
-            throw newIllegalArgumentException("target and filter types do not match");
+        Class<?> rtype = targetType.returnType();
+        int filterValues = filterType.parameterCount();
+        if (filterValues == 0
+                ? (rtype != void.class)
+                : (rtype != filterType.parameterType(0)))
+            throw newIllegalArgumentException("target and filter types do not match", target, filter);
         // result = fold( lambda(retval, arg...) { filter(retval) },
         //                lambda(        arg...) { target(arg...) } )
+        MethodType newType = targetType.changeReturnType(filterType.returnType());
+        MethodHandle result = null;
+        if (AdapterMethodHandle.canCollectArguments(filterType, targetType, 0, false)) {
+            result = AdapterMethodHandle.makeCollectArguments(filter, target, 0, false);
+            if (result != null)  return result;
+        }
         // FIXME: Too many nodes here.
-        MethodHandle returner = dropArguments(filter, 1, targetType.parameterList());
-        return foldArguments(returner, target);
+        assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this class is deprecated
+        MethodHandle returner = dropArguments(filter, filterValues, targetType.parameterList());
+        result = foldArguments(returner, target);
+        assert(result.type().equals(newType));
+        return result;
     }
 
     /**
@@ -1981,16 +1996,23 @@
     MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
         MethodType targetType = target.type();
         MethodType combinerType = combiner.type();
+        int foldPos = 0;  // always at the head, at present
         int foldArgs = combinerType.parameterCount();
-        boolean ok = (targetType.parameterCount() >= 1 + foldArgs);
-        if (ok && !combinerType.parameterList().equals(targetType.parameterList().subList(1, foldArgs+1)))
+        int foldVals = combinerType.returnType() == void.class ? 0 : 1;
+        int afterInsertPos = foldPos + foldVals;
+        boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
+        if (ok && !(combinerType.parameterList()
+                    .equals(targetType.parameterList().subList(afterInsertPos,
+                                                               afterInsertPos + foldArgs))))
             ok = false;
-        if (ok && !combinerType.returnType().equals(targetType.parameterType(0)))
+        if (ok && foldVals != 0 && !combinerType.returnType().equals(targetType.parameterType(0)))
             ok = false;
         if (!ok)
             throw misMatchedTypes("target and combiner types", targetType, combinerType);
-        MethodType newType = targetType.dropParameterTypes(0, 1);
-        return MethodHandleImpl.foldArguments(target, newType, combiner);
+        MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos);
+        MethodHandle res = MethodHandleImpl.foldArguments(target, newType, foldPos, combiner);
+        if (res == null)  throw newIllegalArgumentException("cannot fold from "+newType+" to " +targetType);
+        return res;
     }
 
     /**