8057654: Extract checks performed during MethodHandle construction into separate methods
authorvlivanov
Wed, 10 Sep 2014 19:19:51 +0400
changeset 26477 e095a2b8a1f8
parent 26476 2b814465aaa3
child 26478 285691ed55e4
8057654: Extract checks performed during MethodHandle construction into separate methods Reviewed-by: vlivanov, psandoz Contributed-by: john.r.rose@oracle.com
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Wed Sep 10 19:19:51 2014 +0400
@@ -869,29 +869,34 @@
         return MethodHandleImpl.makeSpreadArguments(this, arrayType, spreadArgPos, arrayLength);
     }
 
-    private void asSpreaderChecks(Class<?> arrayType, int arrayLength) {
+    /**
+     * See if {@code asSpreader} can be validly called with the given arguments.
+     * Return the type of the method handle call after spreading but before conversions.
+     */
+    private MethodType asSpreaderChecks(Class<?> arrayType, int arrayLength) {
         spreadArrayChecks(arrayType, arrayLength);
         int nargs = type().parameterCount();
         if (nargs < arrayLength || arrayLength < 0)
             throw newIllegalArgumentException("bad spread array length");
-        if (arrayType != Object[].class && arrayLength != 0) {
-            boolean sawProblem = false;
-            Class<?> arrayElement = arrayType.getComponentType();
-            for (int i = nargs - arrayLength; i < nargs; i++) {
-                if (!MethodType.canConvert(arrayElement, type().parameterType(i))) {
-                    sawProblem = true;
+        Class<?> arrayElement = arrayType.getComponentType();
+        MethodType mtype = type();
+        boolean match = true, fail = false;
+        for (int i = nargs - arrayLength; i < nargs; i++) {
+            Class<?> ptype = mtype.parameterType(i);
+            if (ptype != arrayElement) {
+                match = false;
+                if (!MethodType.canConvert(arrayElement, ptype)) {
+                    fail = true;
                     break;
                 }
             }
-            if (sawProblem) {
-                ArrayList<Class<?>> ptypes = new ArrayList<>(type().parameterList());
-                for (int i = nargs - arrayLength; i < nargs; i++) {
-                    ptypes.set(i, arrayElement);
-                }
-                // elicit an error:
-                this.asType(MethodType.methodType(type().returnType(), ptypes));
-            }
         }
+        if (match)  return mtype;
+        MethodType needType = mtype.asSpreaderType(arrayType, arrayLength);
+        if (!fail)  return needType;
+        // elicit an error:
+        this.asType(needType);
+        throw newInternalError("should not return", null);
     }
 
     private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Sep 10 19:19:51 2014 +0400
@@ -2508,32 +2508,36 @@
      */
     public static
     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
-        MethodType targetType = target.type();
+        filterArgumentsCheckArity(target, pos, filters);
         MethodHandle adapter = target;
-        MethodType adapterType = null;
-        assert((adapterType = targetType) != null);
-        int maxPos = targetType.parameterCount();
-        if (pos + filters.length > maxPos)
-            throw newIllegalArgumentException("too many filters");
         int curPos = pos-1;  // pre-incremented
         for (MethodHandle filter : filters) {
             curPos += 1;
             if (filter == null)  continue;  // ignore null elements of filters
             adapter = filterArgument(adapter, curPos, filter);
-            assert((adapterType = adapterType.changeParameterType(curPos, filter.type().parameterType(0))) != null);
         }
-        assert(adapterType.equals(adapter.type()));
         return adapter;
     }
 
     /*non-public*/ static
     MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
+        filterArgumentChecks(target, pos, filter);
+        return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
+    }
+
+    private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
+        MethodType targetType = target.type();
+        int maxPos = targetType.parameterCount();
+        if (pos + filters.length > maxPos)
+            throw newIllegalArgumentException("too many filters");
+    }
+
+    private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
         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.makeCollectArguments(target, filter, pos, false);
     }
 
     /**
@@ -2713,15 +2717,17 @@
     MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
         MethodType targetType = target.type();
         MethodType filterType = filter.type();
+        filterReturnValueChecks(targetType, filterType);
+        return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
+    }
+
+    private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
         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...) } )
-        return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
+            throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
     }
 
     /**
@@ -2802,24 +2808,28 @@
      */
     public static
     MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
-        int pos = 0;
+        int foldPos = 0;
         MethodType targetType = target.type();
         MethodType combinerType = combiner.type();
-        int foldPos = pos;
-        int foldArgs = combinerType.parameterCount();
-        int foldVals = combinerType.returnType() == void.class ? 0 : 1;
+        Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
+        return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
+    }
+
+    private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
+        int foldArgs   = combinerType.parameterCount();
+        Class<?> rtype = combinerType.returnType();
+        int foldVals = rtype == 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 && foldVals != 0 && !combinerType.returnType().equals(targetType.parameterType(0)))
+        if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
             ok = false;
         if (!ok)
             throw misMatchedTypes("target and combiner types", targetType, combinerType);
-        MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos);
-        return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
+        return rtype;
     }
 
     /**