src/java.base/share/classes/java/lang/invoke/MethodHandles.java
changeset 52226 b4b932c6001f
parent 52086 fc52ccf451cd
child 52427 3c6aa484536c
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Tue Oct 23 10:55:59 2018 +0200
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Tue Oct 23 11:03:51 2018 +0200
@@ -4316,28 +4316,6 @@
         return result;
     }
 
-    /**
-     * As {@see foldArguments(MethodHandle, int, MethodHandle)}, but with the
-     * added capability of selecting the arguments from the targets parameters
-     * to call the combiner with. This allows us to avoid some simple cases of
-     * permutations and padding the combiner with dropArguments to select the
-     * right argument, which may ultimately produce fewer intermediaries.
-     */
-    static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner, int ... argPositions) {
-        MethodType targetType = target.type();
-        MethodType combinerType = combiner.type();
-        Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType, argPositions);
-        BoundMethodHandle result = target.rebind();
-        boolean dropResult = rtype == void.class;
-        LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType(), argPositions);
-        MethodType newType = targetType;
-        if (!dropResult) {
-            newType = newType.dropParameterTypes(pos, pos + 1);
-        }
-        result = result.copyWithExtendL(newType, lform, combiner);
-        return result;
-    }
-
     private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
         int foldArgs   = combinerType.parameterCount();
         Class<?> rtype = combinerType.returnType();
@@ -4359,15 +4337,78 @@
         return rtype;
     }
 
-    private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType, int ... argPos) {
-        int foldArgs = combinerType.parameterCount();
-        if (argPos.length != foldArgs) {
+    /**
+     * Adapts a target method handle by pre-processing some of its arguments, then calling the target with the result
+     * of the pre-processing replacing the argument at the given position.
+     *
+     * @param target the method handle to invoke after arguments are combined
+     * @param position the position at which to start folding and at which to insert the folding result; if this is {@code
+     *            0}, the effect is the same as for {@link #foldArguments(MethodHandle, MethodHandle)}.
+     * @param combiner method handle to call initially on the incoming arguments
+     * @param argPositions indexes of the target to pick arguments sent to the combiner from
+     * @return method handle which incorporates the specified argument folding logic
+     * @throws NullPointerException if either argument is null
+     * @throws IllegalArgumentException if either of the following two conditions holds:
+     *          (1) {@code combiner}'s return type is not the same as the argument type at position
+     *              {@code pos} of the target signature;
+     *          (2) the {@code N} argument types at positions {@code argPositions[1...N]} of the target signature are
+     *              not identical with the argument types of {@code combiner}.
+     */
+    /*non-public*/ static MethodHandle filterArgumentsWithCombiner(MethodHandle target, int position, MethodHandle combiner, int ... argPositions) {
+        return argumentsWithCombiner(true, target, position, combiner, argPositions);
+    }
+
+    /**
+     * Adapts a target method handle by pre-processing some of its arguments, calling the target with the result of
+     * the pre-processing inserted into the original sequence of arguments at the given position.
+     *
+     * @param target the method handle to invoke after arguments are combined
+     * @param position the position at which to start folding and at which to insert the folding result; if this is {@code
+     *            0}, the effect is the same as for {@link #foldArguments(MethodHandle, MethodHandle)}.
+     * @param combiner method handle to call initially on the incoming arguments
+     * @param argPositions indexes of the target to pick arguments sent to the combiner from
+     * @return method handle which incorporates the specified argument folding logic
+     * @throws NullPointerException if either argument is null
+     * @throws IllegalArgumentException if either of the following two conditions holds:
+     *          (1) {@code combiner}'s return type is non-{@code void} and not the same as the argument type at position
+     *              {@code pos} of the target signature;
+     *          (2) the {@code N} argument types at positions {@code argPositions[1...N]} of the target signature
+     *              (skipping {@code position} where the {@code combiner}'s return will be folded in) are not identical
+     *              with the argument types of {@code combiner}.
+     */
+    /*non-public*/ static MethodHandle foldArgumentsWithCombiner(MethodHandle target, int position, MethodHandle combiner, int ... argPositions) {
+        return argumentsWithCombiner(false, target, position, combiner, argPositions);
+    }
+
+    private static MethodHandle argumentsWithCombiner(boolean filter, MethodHandle target, int position, MethodHandle combiner, int ... argPositions) {
+        MethodType targetType = target.type();
+        MethodType combinerType = combiner.type();
+        Class<?> rtype = argumentsWithCombinerChecks(position, filter, targetType, combinerType, argPositions);
+        BoundMethodHandle result = target.rebind();
+
+        MethodType newType = targetType;
+        LambdaForm lform;
+        if (filter) {
+            lform = result.editor().filterArgumentsForm(1 + position, combinerType.basicType(), argPositions);
+        } else {
+            boolean dropResult = rtype == void.class;
+            lform = result.editor().foldArgumentsForm(1 + position, dropResult, combinerType.basicType(), argPositions);
+            if (!dropResult) {
+                newType = newType.dropParameterTypes(position, position + 1);
+            }
+        }
+        result = result.copyWithExtendL(newType, lform, combiner);
+        return result;
+    }
+
+    private static Class<?> argumentsWithCombinerChecks(int position, boolean filter, MethodType targetType, MethodType combinerType, int ... argPos) {
+        int combinerArgs = combinerType.parameterCount();
+        if (argPos.length != combinerArgs) {
             throw newIllegalArgumentException("combiner and argument map must be equal size", combinerType, argPos.length);
         }
         Class<?> rtype = combinerType.returnType();
-        int foldVals = rtype == void.class ? 0 : 1;
-        boolean ok = true;
-        for (int i = 0; i < foldArgs; i++) {
+
+        for (int i = 0; i < combinerArgs; i++) {
             int arg = argPos[i];
             if (arg < 0 || arg > targetType.parameterCount()) {
                 throw newIllegalArgumentException("arg outside of target parameterRange", targetType, arg);
@@ -4378,11 +4419,9 @@
                         + " -> " + combinerType + ", map: " + Arrays.toString(argPos));
             }
         }
-        if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(foldPos)) {
-            ok = false;
+        if (filter && combinerType.returnType() != targetType.parameterType(position)) {
+            throw misMatchedTypes("target and combiner types", targetType, combinerType);
         }
-        if (!ok)
-            throw misMatchedTypes("target and combiner types", targetType, combinerType);
         return rtype;
     }