src/java.base/share/classes/java/lang/invoke/MethodHandles.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File jdk Sdiff src/java.base/share/classes/java/lang/invoke

src/java.base/share/classes/java/lang/invoke/MethodHandles.java

Print this page
rev 10592 : 8050052: Small cleanups in java.lang.invoke code
Reviewed-by: ?
rev 10593 : 8050053: Improve caching of different invokers
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10594 : 8050166: Get rid of some package-private methods on arguments in j.l.i.MethodHandle
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10595 : 8050173: Add j.l.i.MethodHandle.copyWith(MethodType, LambdaForm)
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10596 : [mq]: 07.8050173.viewAsType.1
rev 10600 : imported patch 11.8050877.conv
rev 10601 : imported patch 12.8050884.identity
rev 10602 : imported patch 13.8050887.zero
rev 10603 : 8057654: Extract checks performed during MethodHandle construction into separate methods
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com


2491      * A[i] filter[i](V[i]);
2492      * T adapter(P... p, V[i]... v[i], B... b) {
2493      *   return target(p..., f[i](v[i])..., b...);
2494      * }
2495      * }</pre></blockquote>
2496      *
2497      * @param target the method handle to invoke after arguments are filtered
2498      * @param pos the position of the first argument to filter
2499      * @param filters method handles to call initially on filtered arguments
2500      * @return method handle which incorporates the specified argument filtering logic
2501      * @throws NullPointerException if the target is null
2502      *                              or if the {@code filters} array is null
2503      * @throws IllegalArgumentException if a non-null element of {@code filters}
2504      *          does not match a corresponding argument type of target as described above,
2505      *          or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
2506      *          or if the resulting method handle's type would have
2507      *          <a href="MethodHandle.html#maxarity">too many parameters</a>
2508      */
2509     public static
2510     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
2511         MethodType targetType = target.type();
2512         MethodHandle adapter = target;
2513         MethodType adapterType = null;
2514         assert((adapterType = targetType) != null);
2515         int maxPos = targetType.parameterCount();
2516         if (pos + filters.length > maxPos)
2517             throw newIllegalArgumentException("too many filters");
2518         int curPos = pos-1;  // pre-incremented
2519         for (MethodHandle filter : filters) {
2520             curPos += 1;
2521             if (filter == null)  continue;  // ignore null elements of filters
2522             adapter = filterArgument(adapter, curPos, filter);
2523             assert((adapterType = adapterType.changeParameterType(curPos, filter.type().parameterType(0))) != null);
2524         }
2525         assert(adapterType.equals(adapter.type()));
2526         return adapter;
2527     }
2528 
2529     /*non-public*/ static
2530     MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {












2531         MethodType targetType = target.type();
2532         MethodType filterType = filter.type();
2533         if (filterType.parameterCount() != 1
2534             || filterType.returnType() != targetType.parameterType(pos))
2535             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
2536         return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
2537     }
2538 
2539     /**
2540      * Adapts a target method handle by pre-processing
2541      * a sub-sequence of its arguments with a filter (another method handle).
2542      * The pre-processed arguments are replaced by the result (if any) of the
2543      * filter function.
2544      * The target is then called on the modified (usually shortened) argument list.
2545      * <p>
2546      * If the filter returns a value, the target must accept that value as
2547      * its argument in position {@code pos}, preceded and/or followed by
2548      * any arguments not passed to the filter.
2549      * If the filter returns void, the target must accept all arguments
2550      * not passed to the filter.
2551      * No arguments are reordered, and a result returned from the filter
2552      * replaces (in order) the whole subsequence of arguments originally
2553      * passed to the adapter.
2554      * <p>
2555      * The argument types (if any) of the filter
2556      * replace zero or one argument types of the target, at position {@code pos},


2696      * }
2697      * // and if the filter has a void return:
2698      * V target3(A...);
2699      * void filter3(V);
2700      * void adapter3(A... a) {
2701      *   V v = target3(a...);
2702      *   filter3(v);
2703      * }
2704      * }</pre></blockquote>
2705      * @param target the method handle to invoke before filtering the return value
2706      * @param filter method handle to call on the return value
2707      * @return method handle which incorporates the specified return value filtering logic
2708      * @throws NullPointerException if either argument is null
2709      * @throws IllegalArgumentException if the argument list of {@code filter}
2710      *          does not match the return type of target as described above
2711      */
2712     public static
2713     MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
2714         MethodType targetType = target.type();
2715         MethodType filterType = filter.type();





2716         Class<?> rtype = targetType.returnType();
2717         int filterValues = filterType.parameterCount();
2718         if (filterValues == 0
2719                 ? (rtype != void.class)
2720                 : (rtype != filterType.parameterType(0)))
2721             throw newIllegalArgumentException("target and filter types do not match", target, filter);
2722         // result = fold( lambda(retval, arg...) { filter(retval) },
2723         //                lambda(        arg...) { target(arg...) } )
2724         return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
2725     }
2726 
2727     /**
2728      * Adapts a target method handle by pre-processing
2729      * some of its arguments, and then calling the target with
2730      * the result of the pre-processing, inserted into the original
2731      * sequence of arguments.
2732      * <p>
2733      * The pre-processing is performed by {@code combiner}, a second method handle.
2734      * Of the arguments passed to the adapter, the first {@code N} arguments
2735      * are copied to the combiner, which is then called.
2736      * (Here, {@code N} is defined as the parameter count of the combiner.)
2737      * After this, control passes to the target, with any result
2738      * from the combiner inserted before the original {@code N} incoming
2739      * arguments.
2740      * <p>
2741      * If the combiner returns a value, the first parameter type of the target
2742      * must be identical with the return type of the combiner, and the next
2743      * {@code N} parameter types of the target must exactly match the parameters
2744      * of the combiner.


2785      * T target2(A[N]..., B...);
2786      * void combiner2(A...);
2787      * T adapter2(A... a, B... b) {
2788      *   combiner2(a...);
2789      *   return target2(a..., b...);
2790      * }
2791      * }</pre></blockquote>
2792      * @param target the method handle to invoke after arguments are combined
2793      * @param combiner method handle to call initially on the incoming arguments
2794      * @return method handle which incorporates the specified argument folding logic
2795      * @throws NullPointerException if either argument is null
2796      * @throws IllegalArgumentException if {@code combiner}'s return type
2797      *          is non-void and not the same as the first argument type of
2798      *          the target, or if the initial {@code N} argument types
2799      *          of the target
2800      *          (skipping one matching the {@code combiner}'s return type)
2801      *          are not identical with the argument types of {@code combiner}
2802      */
2803     public static
2804     MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
2805         int pos = 0;
2806         MethodType targetType = target.type();
2807         MethodType combinerType = combiner.type();
2808         int foldPos = pos;




2809         int foldArgs = combinerType.parameterCount();
2810         int foldVals = combinerType.returnType() == void.class ? 0 : 1;

2811         int afterInsertPos = foldPos + foldVals;
2812         boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
2813         if (ok && !(combinerType.parameterList()
2814                     .equals(targetType.parameterList().subList(afterInsertPos,
2815                                                                afterInsertPos + foldArgs))))
2816             ok = false;
2817         if (ok && foldVals != 0 && !combinerType.returnType().equals(targetType.parameterType(0)))
2818             ok = false;
2819         if (!ok)
2820             throw misMatchedTypes("target and combiner types", targetType, combinerType);
2821         MethodType newType = targetType.dropParameterTypes(foldPos, afterInsertPos);
2822         return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
2823     }
2824 
2825     /**
2826      * Makes a method handle which adapts a target method handle,
2827      * by guarding it with a test, a boolean-valued method handle.
2828      * If the guard fails, a fallback handle is called instead.
2829      * All three method handles must have the same corresponding
2830      * argument and return types, except that the return type
2831      * of the test must be boolean, and the test is allowed
2832      * to have fewer arguments than the other two method handles.
2833      * <p> Here is pseudocode for the resulting adapter:
2834      * <blockquote><pre>{@code
2835      * boolean test(A...);
2836      * T target(A...,B...);
2837      * T fallback(A...,B...);
2838      * T adapter(A... a,B... b) {
2839      *   if (test(a...))
2840      *     return target(a..., b...);
2841      *   else
2842      *     return fallback(a..., b...);




2491      * A[i] filter[i](V[i]);
2492      * T adapter(P... p, V[i]... v[i], B... b) {
2493      *   return target(p..., f[i](v[i])..., b...);
2494      * }
2495      * }</pre></blockquote>
2496      *
2497      * @param target the method handle to invoke after arguments are filtered
2498      * @param pos the position of the first argument to filter
2499      * @param filters method handles to call initially on filtered arguments
2500      * @return method handle which incorporates the specified argument filtering logic
2501      * @throws NullPointerException if the target is null
2502      *                              or if the {@code filters} array is null
2503      * @throws IllegalArgumentException if a non-null element of {@code filters}
2504      *          does not match a corresponding argument type of target as described above,
2505      *          or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
2506      *          or if the resulting method handle's type would have
2507      *          <a href="MethodHandle.html#maxarity">too many parameters</a>
2508      */
2509     public static
2510     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
2511         filterArgumentsCheckArity(target, pos, filters);
2512         MethodHandle adapter = target;





2513         int curPos = pos-1;  // pre-incremented
2514         for (MethodHandle filter : filters) {
2515             curPos += 1;
2516             if (filter == null)  continue;  // ignore null elements of filters
2517             adapter = filterArgument(adapter, curPos, filter);

2518         }

2519         return adapter;
2520     }
2521 
2522     /*non-public*/ static
2523     MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
2524         filterArgumentChecks(target, pos, filter);
2525         return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
2526     }
2527 
2528     private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
2529         MethodType targetType = target.type();
2530         int maxPos = targetType.parameterCount();
2531         if (pos + filters.length > maxPos)
2532             throw newIllegalArgumentException("too many filters");
2533     }
2534 
2535     private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
2536         MethodType targetType = target.type();
2537         MethodType filterType = filter.type();
2538         if (filterType.parameterCount() != 1
2539             || filterType.returnType() != targetType.parameterType(pos))
2540             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);

2541     }
2542 
2543     /**
2544      * Adapts a target method handle by pre-processing
2545      * a sub-sequence of its arguments with a filter (another method handle).
2546      * The pre-processed arguments are replaced by the result (if any) of the
2547      * filter function.
2548      * The target is then called on the modified (usually shortened) argument list.
2549      * <p>
2550      * If the filter returns a value, the target must accept that value as
2551      * its argument in position {@code pos}, preceded and/or followed by
2552      * any arguments not passed to the filter.
2553      * If the filter returns void, the target must accept all arguments
2554      * not passed to the filter.
2555      * No arguments are reordered, and a result returned from the filter
2556      * replaces (in order) the whole subsequence of arguments originally
2557      * passed to the adapter.
2558      * <p>
2559      * The argument types (if any) of the filter
2560      * replace zero or one argument types of the target, at position {@code pos},


2700      * }
2701      * // and if the filter has a void return:
2702      * V target3(A...);
2703      * void filter3(V);
2704      * void adapter3(A... a) {
2705      *   V v = target3(a...);
2706      *   filter3(v);
2707      * }
2708      * }</pre></blockquote>
2709      * @param target the method handle to invoke before filtering the return value
2710      * @param filter method handle to call on the return value
2711      * @return method handle which incorporates the specified return value filtering logic
2712      * @throws NullPointerException if either argument is null
2713      * @throws IllegalArgumentException if the argument list of {@code filter}
2714      *          does not match the return type of target as described above
2715      */
2716     public static
2717     MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
2718         MethodType targetType = target.type();
2719         MethodType filterType = filter.type();
2720         filterReturnValueChecks(targetType, filterType);
2721         return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
2722     }
2723 
2724     private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
2725         Class<?> rtype = targetType.returnType();
2726         int filterValues = filterType.parameterCount();
2727         if (filterValues == 0
2728                 ? (rtype != void.class)
2729                 : (rtype != filterType.parameterType(0)))
2730             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);



2731     }
2732 
2733     /**
2734      * Adapts a target method handle by pre-processing
2735      * some of its arguments, and then calling the target with
2736      * the result of the pre-processing, inserted into the original
2737      * sequence of arguments.
2738      * <p>
2739      * The pre-processing is performed by {@code combiner}, a second method handle.
2740      * Of the arguments passed to the adapter, the first {@code N} arguments
2741      * are copied to the combiner, which is then called.
2742      * (Here, {@code N} is defined as the parameter count of the combiner.)
2743      * After this, control passes to the target, with any result
2744      * from the combiner inserted before the original {@code N} incoming
2745      * arguments.
2746      * <p>
2747      * If the combiner returns a value, the first parameter type of the target
2748      * must be identical with the return type of the combiner, and the next
2749      * {@code N} parameter types of the target must exactly match the parameters
2750      * of the combiner.


2791      * T target2(A[N]..., B...);
2792      * void combiner2(A...);
2793      * T adapter2(A... a, B... b) {
2794      *   combiner2(a...);
2795      *   return target2(a..., b...);
2796      * }
2797      * }</pre></blockquote>
2798      * @param target the method handle to invoke after arguments are combined
2799      * @param combiner method handle to call initially on the incoming arguments
2800      * @return method handle which incorporates the specified argument folding logic
2801      * @throws NullPointerException if either argument is null
2802      * @throws IllegalArgumentException if {@code combiner}'s return type
2803      *          is non-void and not the same as the first argument type of
2804      *          the target, or if the initial {@code N} argument types
2805      *          of the target
2806      *          (skipping one matching the {@code combiner}'s return type)
2807      *          are not identical with the argument types of {@code combiner}
2808      */
2809     public static
2810     MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
2811         int foldPos = 0;
2812         MethodType targetType = target.type();
2813         MethodType combinerType = combiner.type();
2814         Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
2815         return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
2816     }
2817 
2818     private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
2819         int foldArgs   = combinerType.parameterCount();
2820         Class<?> rtype = combinerType.returnType();
2821         int foldVals = rtype == void.class ? 0 : 1;
2822         int afterInsertPos = foldPos + foldVals;
2823         boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
2824         if (ok && !(combinerType.parameterList()
2825                     .equals(targetType.parameterList().subList(afterInsertPos,
2826                                                                afterInsertPos + foldArgs))))
2827             ok = false;
2828         if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
2829             ok = false;
2830         if (!ok)
2831             throw misMatchedTypes("target and combiner types", targetType, combinerType);
2832         return rtype;

2833     }
2834 
2835     /**
2836      * Makes a method handle which adapts a target method handle,
2837      * by guarding it with a test, a boolean-valued method handle.
2838      * If the guard fails, a fallback handle is called instead.
2839      * All three method handles must have the same corresponding
2840      * argument and return types, except that the return type
2841      * of the test must be boolean, and the test is allowed
2842      * to have fewer arguments than the other two method handles.
2843      * <p> Here is pseudocode for the resulting adapter:
2844      * <blockquote><pre>{@code
2845      * boolean test(A...);
2846      * T target(A...,B...);
2847      * T fallback(A...,B...);
2848      * T adapter(A... a,B... b) {
2849      *   if (test(a...))
2850      *     return target(a..., b...);
2851      *   else
2852      *     return fallback(a..., b...);


src/java.base/share/classes/java/lang/invoke/MethodHandles.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File