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 10938 : [mq]: remove.use_lf_editor


2086 assert(twice.type().equals(intfn1));
2087 assert((int)twice.invokeExact(21) == 42);
2088      * }</pre></blockquote>
2089      * @param target the method handle to invoke after arguments are reordered
2090      * @param newType the expected type of the new method handle
2091      * @param reorder an index array which controls the reordering
2092      * @return a method handle which delegates to the target after it
2093      *           drops unused arguments and moves and/or duplicates the other arguments
2094      * @throws NullPointerException if any argument is null
2095      * @throws IllegalArgumentException if the index array length is not equal to
2096      *                  the arity of the target, or if any index array element
2097      *                  not a valid index for a parameter of {@code newType},
2098      *                  or if two corresponding parameter types in
2099      *                  {@code target.type()} and {@code newType} are not identical,
2100      */
2101     public static
2102     MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
2103         reorder = reorder.clone();  // get a private copy
2104         MethodType oldType = target.type();
2105         permuteArgumentChecks(reorder, newType, oldType);
2106         if (USE_LAMBDA_FORM_EDITOR) {
2107             // first detect dropped arguments and handle them separately
2108             int[] originalReorder = reorder;
2109             BoundMethodHandle result = target.rebind();
2110             LambdaForm form = result.form;
2111             int newArity = newType.parameterCount();
2112             // Normalize the reordering into a real permutation,
2113             // by removing duplicates and adding dropped elements.
2114             // This somewhat improves lambda form caching, as well
2115             // as simplifying the transform by breaking it up into steps.
2116             for (int ddIdx; (ddIdx = findFirstDupOrDrop(reorder, newArity)) != 0; ) {
2117                 if (ddIdx > 0) {
2118                     // We found a duplicated entry at reorder[ddIdx].
2119                     // Example:  (x,y,z)->asList(x,y,z)
2120                     // permuted by [1*,0,1] => (a0,a1)=>asList(a1,a0,a1)
2121                     // permuted by [0,1,0*] => (a0,a1)=>asList(a0,a1,a0)
2122                     // The starred element corresponds to the argument
2123                     // deleted by the dupArgumentForm transform.
2124                     int srcPos = ddIdx, dstPos = srcPos, dupVal = reorder[srcPos];
2125                     boolean killFirst = false;
2126                     for (int val; (val = reorder[--dstPos]) != dupVal; ) {


2146                         // This is where we will insert the dropVal.
2147                         insPos += 1;
2148                     }
2149                     Class<?> ptype = newType.parameterType(dropVal);
2150                     form = form.editor().addArgumentForm(1 + insPos, BasicType.basicType(ptype));
2151                     oldType = oldType.insertParameterTypes(insPos, ptype);
2152                     // expand the reordering by inserting an element at insPos
2153                     int tailPos = insPos + 1;
2154                     reorder = Arrays.copyOf(reorder, reorder.length + 1);
2155                     System.arraycopy(reorder, insPos, reorder, tailPos, reorder.length - tailPos);
2156                     reorder[insPos] = dropVal;
2157                 }
2158                 assert (permuteArgumentChecks(reorder, newType, oldType));
2159             }
2160             assert (reorder.length == newArity);  // a perfect permutation
2161             // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
2162             form = form.editor().permuteArgumentsForm(1, reorder);
2163             if (newType == result.type() && form == result.internalForm())
2164                 return result;
2165             return result.copyWith(newType, form);
2166         } else {
2167             // first detect dropped arguments and handle them separately
2168             MethodHandle originalTarget = target;
2169             int newArity = newType.parameterCount();
2170             for (int dropIdx; (dropIdx = findFirstDrop(reorder, newArity)) >= 0; ) {
2171                 // dropIdx is missing from reorder; add it in at the end
2172                 int oldArity = reorder.length;
2173                 target = dropArguments(target, oldArity, newType.parameterType(dropIdx));
2174                 reorder = Arrays.copyOf(reorder, oldArity + 1);
2175                 reorder[oldArity] = dropIdx;
2176             }
2177             assert(target == originalTarget || permuteArgumentChecks(reorder, newType, target.type()));
2178             // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
2179             BoundMethodHandle result = target.rebind();
2180             LambdaForm form = result.form.permuteArguments(1, reorder, basicTypes(newType.parameterList()));
2181             return result.copyWith(newType, form);
2182         }
2183     }
2184 
2185     /** Return the first value in [0..newArity-1] that is not present in reorder. */
2186     private static int findFirstDrop(int[] reorder, int newArity) {
2187         final int BIT_LIMIT = 63;  // max number of bits in bit mask
2188         if (newArity < BIT_LIMIT) {
2189             long mask = 0;
2190             for (int arg : reorder) {
2191                 assert(arg < newArity);
2192                 mask |= (1L << arg);
2193             }
2194             if (mask == (1L << newArity) - 1) {
2195                 assert(Long.numberOfTrailingZeros(Long.lowestOneBit(~mask)) == newArity);
2196                 return -1;
2197             }
2198             // find first zero
2199             long zeroBit = Long.lowestOneBit(~mask);
2200             int zeroPos = Long.numberOfTrailingZeros(zeroBit);
2201             assert(zeroPos < newArity);
2202             return zeroPos;
2203         } else {
2204             BitSet mask = new BitSet(newArity);
2205             for (int arg : reorder) {
2206                 assert (arg < newArity);
2207                 mask.set(arg);
2208             }
2209             int zeroPos = mask.nextClearBit(0);
2210             assert(zeroPos <= newArity);
2211             if (zeroPos == newArity)
2212                 return -1;
2213             return zeroPos;
2214         }
2215     }
2216 
2217     /**
2218      * Return an indication of any duplicate or omission in reorder.
2219      * If the reorder contains a duplicate entry, return the index of the second occurrence.
2220      * Otherwise, return ~(n), for the first n in [0..newArity-1] that is not present in reorder.
2221      * Otherwise, return zero.
2222      * If an element not in [0..newArity-1] is encountered, return reorder.length.
2223      */
2224     private static int findFirstDupOrDrop(int[] reorder, int newArity) {
2225         final int BIT_LIMIT = 63;  // max number of bits in bit mask
2226         if (newArity < BIT_LIMIT) {
2227             long mask = 0;
2228             for (int i = 0; i < reorder.length; i++) {
2229                 int arg = reorder[i];
2230                 if (arg >= newArity) {
2231                     return reorder.length;
2232                 }
2233                 long bit = 1L << arg;
2234                 if ((mask & bit) != 0) {


2485      * </pre></blockquote>
2486      * @param target the method handle to invoke after the arguments are dropped
2487      * @param valueTypes the type(s) of the argument(s) to drop
2488      * @param pos position of first argument to drop (zero for the leftmost)
2489      * @return a method handle which drops arguments of the given types,
2490      *         before calling the original method handle
2491      * @throws NullPointerException if the target is null,
2492      *                              or if the {@code valueTypes} list or any of its elements is null
2493      * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
2494      *                  or if {@code pos} is negative or greater than the arity of the target,
2495      *                  or if the new method handle's type would have too many parameters
2496      */
2497     public static
2498     MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
2499         MethodType oldType = target.type();  // get NPE
2500         int dropped = dropArgumentChecks(oldType, pos, valueTypes);
2501         MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
2502         if (dropped == 0)  return target;
2503         BoundMethodHandle result = target.rebind();
2504         LambdaForm lform = result.form;
2505         if (USE_LAMBDA_FORM_EDITOR) {
2506             int insertFormArg = 1 + pos;
2507             for (Class<?> ptype : valueTypes) {
2508                 lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
2509             }
2510         } else {
2511             lform = lform.addArguments(pos, valueTypes);
2512         }
2513         result = result.copyWith(newType, lform);
2514         return result;
2515     }
2516 
2517     private static int dropArgumentChecks(MethodType oldType, int pos, List<Class<?>> valueTypes) {
2518         int dropped = valueTypes.size();
2519         MethodType.checkSlotCount(dropped);
2520         int outargs = oldType.parameterCount();
2521         int inargs  = outargs + dropped;
2522         if (pos < 0 || pos > outargs)
2523             throw newIllegalArgumentException("no argument type to remove"
2524                     + Arrays.asList(oldType, pos, valueTypes, inargs, outargs)
2525                     );
2526         return dropped;
2527     }
2528 
2529     /**
2530      * Produces a method handle which will discard some dummy arguments
2531      * before calling some other specified <i>target</i> method handle.
2532      * The type of the new method handle will be the same as the target's type,


2642      *          or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
2643      *          or if the resulting method handle's type would have
2644      *          <a href="MethodHandle.html#maxarity">too many parameters</a>
2645      */
2646     public static
2647     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
2648         filterArgumentsCheckArity(target, pos, filters);
2649         MethodHandle adapter = target;
2650         int curPos = pos-1;  // pre-incremented
2651         for (MethodHandle filter : filters) {
2652             curPos += 1;
2653             if (filter == null)  continue;  // ignore null elements of filters
2654             adapter = filterArgument(adapter, curPos, filter);
2655         }
2656         return adapter;
2657     }
2658 
2659     /*non-public*/ static
2660     MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
2661         filterArgumentChecks(target, pos, filter);
2662         if (USE_LAMBDA_FORM_EDITOR) {
2663             MethodType targetType = target.type();
2664             MethodType filterType = filter.type();
2665             BoundMethodHandle result = target.rebind();
2666             Class<?> newParamType = filterType.parameterType(0);
2667             LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
2668             MethodType newType = targetType.changeParameterType(pos, newParamType);
2669             result = result.copyWithExtendL(newType, lform, filter);
2670             return result;
2671         } else {
2672             return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
2673         }
2674     }
2675 
2676     private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
2677         MethodType targetType = target.type();
2678         int maxPos = targetType.parameterCount();
2679         if (pos + filters.length > maxPos)
2680             throw newIllegalArgumentException("too many filters");
2681     }
2682 
2683     private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
2684         MethodType targetType = target.type();
2685         MethodType filterType = filter.type();
2686         if (filterType.parameterCount() != 1
2687             || filterType.returnType() != targetType.parameterType(pos))
2688             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
2689     }
2690 
2691     /**
2692      * Adapts a target method handle by pre-processing
2693      * a sub-sequence of its arguments with a filter (another method handle).


2780      * Other equivalences are possible but would require argument permutation.
2781      *
2782      * @param target the method handle to invoke after filtering the subsequence of arguments
2783      * @param pos the position of the first adapter argument to pass to the filter,
2784      *            and/or the target argument which receives the result of the filter
2785      * @param filter method handle to call on the subsequence of arguments
2786      * @return method handle which incorporates the specified argument subsequence filtering logic
2787      * @throws NullPointerException if either argument is null
2788      * @throws IllegalArgumentException if the return type of {@code filter}
2789      *          is non-void and is not the same as the {@code pos} argument of the target,
2790      *          or if {@code pos} is not between 0 and the target's arity, inclusive,
2791      *          or if the resulting method handle's type would have
2792      *          <a href="MethodHandle.html#maxarity">too many parameters</a>
2793      * @see MethodHandles#foldArguments
2794      * @see MethodHandles#filterArguments
2795      * @see MethodHandles#filterReturnValue
2796      */
2797     public static
2798     MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
2799         MethodType newType = collectArgumentsChecks(target, pos, filter);
2800         if (USE_LAMBDA_FORM_EDITOR) {
2801             MethodType collectorType = filter.type();
2802             BoundMethodHandle result = target.rebind();
2803             LambdaForm lform;
2804             if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) {
2805                 lform = result.editor().collectArgumentArrayForm(1 + pos, filter);
2806                 if (lform != null) {
2807                     return result.copyWith(newType, lform);
2808                 }
2809             }
2810             lform = result.editor().collectArgumentsForm(1 + pos, collectorType.basicType());
2811             return result.copyWithExtendL(newType, lform, filter);
2812         } else {
2813             return MethodHandleImpl.makeCollectArguments(target, filter, pos, false);
2814         }
2815     }
2816 
2817     private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
2818         MethodType targetType = target.type();
2819         MethodType filterType = filter.type();
2820         Class<?> rtype = filterType.returnType();
2821         List<Class<?>> filterArgs = filterType.parameterList();
2822         if (rtype == void.class) {
2823             return targetType.insertParameterTypes(pos, filterArgs);
2824         }
2825         if (rtype != targetType.parameterType(pos)) {
2826             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
2827         }
2828         return targetType.dropParameterTypes(pos, pos+1).insertParameterTypes(pos, filterArgs);
2829     }
2830 
2831     /**
2832      * Adapts a target method handle by post-processing
2833      * its return value (if any) with a filter (another method handle).
2834      * The result of the filter is returned from the adapter.


2873      * // and if the filter has a void return:
2874      * V target3(A...);
2875      * void filter3(V);
2876      * void adapter3(A... a) {
2877      *   V v = target3(a...);
2878      *   filter3(v);
2879      * }
2880      * }</pre></blockquote>
2881      * @param target the method handle to invoke before filtering the return value
2882      * @param filter method handle to call on the return value
2883      * @return method handle which incorporates the specified return value filtering logic
2884      * @throws NullPointerException if either argument is null
2885      * @throws IllegalArgumentException if the argument list of {@code filter}
2886      *          does not match the return type of target as described above
2887      */
2888     public static
2889     MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
2890         MethodType targetType = target.type();
2891         MethodType filterType = filter.type();
2892         filterReturnValueChecks(targetType, filterType);
2893         if (USE_LAMBDA_FORM_EDITOR) {
2894             BoundMethodHandle result = target.rebind();
2895             BasicType rtype = BasicType.basicType(filterType.returnType());
2896             LambdaForm lform = result.editor().filterReturnForm(rtype, false);
2897             MethodType newType = targetType.changeReturnType(filterType.returnType());
2898             result = result.copyWithExtendL(newType, lform, filter);
2899             return result;
2900         } else {
2901             return MethodHandleImpl.makeCollectArguments(filter, target, 0, false);
2902         }
2903     }
2904 
2905     private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
2906         Class<?> rtype = targetType.returnType();
2907         int filterValues = filterType.parameterCount();
2908         if (filterValues == 0
2909                 ? (rtype != void.class)
2910                 : (rtype != filterType.parameterType(0)))
2911             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
2912     }
2913 
2914     /**
2915      * Adapts a target method handle by pre-processing
2916      * some of its arguments, and then calling the target with
2917      * the result of the pre-processing, inserted into the original
2918      * sequence of arguments.
2919      * <p>
2920      * The pre-processing is performed by {@code combiner}, a second method handle.
2921      * Of the arguments passed to the adapter, the first {@code N} arguments
2922      * are copied to the combiner, which is then called.


2976      *   return target2(a..., b...);
2977      * }
2978      * }</pre></blockquote>
2979      * @param target the method handle to invoke after arguments are combined
2980      * @param combiner method handle to call initially on the incoming arguments
2981      * @return method handle which incorporates the specified argument folding logic
2982      * @throws NullPointerException if either argument is null
2983      * @throws IllegalArgumentException if {@code combiner}'s return type
2984      *          is non-void and not the same as the first argument type of
2985      *          the target, or if the initial {@code N} argument types
2986      *          of the target
2987      *          (skipping one matching the {@code combiner}'s return type)
2988      *          are not identical with the argument types of {@code combiner}
2989      */
2990     public static
2991     MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
2992         int foldPos = 0;
2993         MethodType targetType = target.type();
2994         MethodType combinerType = combiner.type();
2995         Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
2996         if (USE_LAMBDA_FORM_EDITOR) {
2997             BoundMethodHandle result = target.rebind();
2998             boolean dropResult = (rtype == void.class);
2999             // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
3000             LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType());
3001             MethodType newType = targetType;
3002             if (!dropResult)
3003                 newType = newType.dropParameterTypes(foldPos, foldPos + 1);
3004             result = result.copyWithExtendL(newType, lform, combiner);
3005             return result;
3006         } else {
3007             return MethodHandleImpl.makeCollectArguments(target, combiner, foldPos, true);
3008         }
3009     }
3010 
3011     private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
3012         int foldArgs   = combinerType.parameterCount();
3013         Class<?> rtype = combinerType.returnType();
3014         int foldVals = rtype == void.class ? 0 : 1;
3015         int afterInsertPos = foldPos + foldVals;
3016         boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
3017         if (ok && !(combinerType.parameterList()
3018                     .equals(targetType.parameterList().subList(afterInsertPos,
3019                                                                afterInsertPos + foldArgs))))
3020             ok = false;
3021         if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
3022             ok = false;
3023         if (!ok)
3024             throw misMatchedTypes("target and combiner types", targetType, combinerType);
3025         return rtype;
3026     }
3027 
3028     /**




2086 assert(twice.type().equals(intfn1));
2087 assert((int)twice.invokeExact(21) == 42);
2088      * }</pre></blockquote>
2089      * @param target the method handle to invoke after arguments are reordered
2090      * @param newType the expected type of the new method handle
2091      * @param reorder an index array which controls the reordering
2092      * @return a method handle which delegates to the target after it
2093      *           drops unused arguments and moves and/or duplicates the other arguments
2094      * @throws NullPointerException if any argument is null
2095      * @throws IllegalArgumentException if the index array length is not equal to
2096      *                  the arity of the target, or if any index array element
2097      *                  not a valid index for a parameter of {@code newType},
2098      *                  or if two corresponding parameter types in
2099      *                  {@code target.type()} and {@code newType} are not identical,
2100      */
2101     public static
2102     MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
2103         reorder = reorder.clone();  // get a private copy
2104         MethodType oldType = target.type();
2105         permuteArgumentChecks(reorder, newType, oldType);

2106         // first detect dropped arguments and handle them separately
2107         int[] originalReorder = reorder;
2108         BoundMethodHandle result = target.rebind();
2109         LambdaForm form = result.form;
2110         int newArity = newType.parameterCount();
2111         // Normalize the reordering into a real permutation,
2112         // by removing duplicates and adding dropped elements.
2113         // This somewhat improves lambda form caching, as well
2114         // as simplifying the transform by breaking it up into steps.
2115         for (int ddIdx; (ddIdx = findFirstDupOrDrop(reorder, newArity)) != 0; ) {
2116             if (ddIdx > 0) {
2117                 // We found a duplicated entry at reorder[ddIdx].
2118                 // Example:  (x,y,z)->asList(x,y,z)
2119                 // permuted by [1*,0,1] => (a0,a1)=>asList(a1,a0,a1)
2120                 // permuted by [0,1,0*] => (a0,a1)=>asList(a0,a1,a0)
2121                 // The starred element corresponds to the argument
2122                 // deleted by the dupArgumentForm transform.
2123                 int srcPos = ddIdx, dstPos = srcPos, dupVal = reorder[srcPos];
2124                 boolean killFirst = false;
2125                 for (int val; (val = reorder[--dstPos]) != dupVal; ) {


2145                     // This is where we will insert the dropVal.
2146                     insPos += 1;
2147                 }
2148                 Class<?> ptype = newType.parameterType(dropVal);
2149                 form = form.editor().addArgumentForm(1 + insPos, BasicType.basicType(ptype));
2150                 oldType = oldType.insertParameterTypes(insPos, ptype);
2151                 // expand the reordering by inserting an element at insPos
2152                 int tailPos = insPos + 1;
2153                 reorder = Arrays.copyOf(reorder, reorder.length + 1);
2154                 System.arraycopy(reorder, insPos, reorder, tailPos, reorder.length - tailPos);
2155                 reorder[insPos] = dropVal;
2156             }
2157             assert (permuteArgumentChecks(reorder, newType, oldType));
2158         }
2159         assert (reorder.length == newArity);  // a perfect permutation
2160         // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
2161         form = form.editor().permuteArgumentsForm(1, reorder);
2162         if (newType == result.type() && form == result.internalForm())
2163             return result;
2164         return result.copyWith(newType, form);

















































2165     }
2166 
2167     /**
2168      * Return an indication of any duplicate or omission in reorder.
2169      * If the reorder contains a duplicate entry, return the index of the second occurrence.
2170      * Otherwise, return ~(n), for the first n in [0..newArity-1] that is not present in reorder.
2171      * Otherwise, return zero.
2172      * If an element not in [0..newArity-1] is encountered, return reorder.length.
2173      */
2174     private static int findFirstDupOrDrop(int[] reorder, int newArity) {
2175         final int BIT_LIMIT = 63;  // max number of bits in bit mask
2176         if (newArity < BIT_LIMIT) {
2177             long mask = 0;
2178             for (int i = 0; i < reorder.length; i++) {
2179                 int arg = reorder[i];
2180                 if (arg >= newArity) {
2181                     return reorder.length;
2182                 }
2183                 long bit = 1L << arg;
2184                 if ((mask & bit) != 0) {


2435      * </pre></blockquote>
2436      * @param target the method handle to invoke after the arguments are dropped
2437      * @param valueTypes the type(s) of the argument(s) to drop
2438      * @param pos position of first argument to drop (zero for the leftmost)
2439      * @return a method handle which drops arguments of the given types,
2440      *         before calling the original method handle
2441      * @throws NullPointerException if the target is null,
2442      *                              or if the {@code valueTypes} list or any of its elements is null
2443      * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
2444      *                  or if {@code pos} is negative or greater than the arity of the target,
2445      *                  or if the new method handle's type would have too many parameters
2446      */
2447     public static
2448     MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
2449         MethodType oldType = target.type();  // get NPE
2450         int dropped = dropArgumentChecks(oldType, pos, valueTypes);
2451         MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
2452         if (dropped == 0)  return target;
2453         BoundMethodHandle result = target.rebind();
2454         LambdaForm lform = result.form;

2455         int insertFormArg = 1 + pos;
2456         for (Class<?> ptype : valueTypes) {
2457             lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
2458         }



2459         result = result.copyWith(newType, lform);
2460         return result;
2461     }
2462 
2463     private static int dropArgumentChecks(MethodType oldType, int pos, List<Class<?>> valueTypes) {
2464         int dropped = valueTypes.size();
2465         MethodType.checkSlotCount(dropped);
2466         int outargs = oldType.parameterCount();
2467         int inargs  = outargs + dropped;
2468         if (pos < 0 || pos > outargs)
2469             throw newIllegalArgumentException("no argument type to remove"
2470                     + Arrays.asList(oldType, pos, valueTypes, inargs, outargs)
2471                     );
2472         return dropped;
2473     }
2474 
2475     /**
2476      * Produces a method handle which will discard some dummy arguments
2477      * before calling some other specified <i>target</i> method handle.
2478      * The type of the new method handle will be the same as the target's type,


2588      *          or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
2589      *          or if the resulting method handle's type would have
2590      *          <a href="MethodHandle.html#maxarity">too many parameters</a>
2591      */
2592     public static
2593     MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
2594         filterArgumentsCheckArity(target, pos, filters);
2595         MethodHandle adapter = target;
2596         int curPos = pos-1;  // pre-incremented
2597         for (MethodHandle filter : filters) {
2598             curPos += 1;
2599             if (filter == null)  continue;  // ignore null elements of filters
2600             adapter = filterArgument(adapter, curPos, filter);
2601         }
2602         return adapter;
2603     }
2604 
2605     /*non-public*/ static
2606     MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
2607         filterArgumentChecks(target, pos, filter);

2608         MethodType targetType = target.type();
2609         MethodType filterType = filter.type();
2610         BoundMethodHandle result = target.rebind();
2611         Class<?> newParamType = filterType.parameterType(0);
2612         LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
2613         MethodType newType = targetType.changeParameterType(pos, newParamType);
2614         result = result.copyWithExtendL(newType, lform, filter);
2615         return result;



2616     }
2617 
2618     private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
2619         MethodType targetType = target.type();
2620         int maxPos = targetType.parameterCount();
2621         if (pos + filters.length > maxPos)
2622             throw newIllegalArgumentException("too many filters");
2623     }
2624 
2625     private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
2626         MethodType targetType = target.type();
2627         MethodType filterType = filter.type();
2628         if (filterType.parameterCount() != 1
2629             || filterType.returnType() != targetType.parameterType(pos))
2630             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
2631     }
2632 
2633     /**
2634      * Adapts a target method handle by pre-processing
2635      * a sub-sequence of its arguments with a filter (another method handle).


2722      * Other equivalences are possible but would require argument permutation.
2723      *
2724      * @param target the method handle to invoke after filtering the subsequence of arguments
2725      * @param pos the position of the first adapter argument to pass to the filter,
2726      *            and/or the target argument which receives the result of the filter
2727      * @param filter method handle to call on the subsequence of arguments
2728      * @return method handle which incorporates the specified argument subsequence filtering logic
2729      * @throws NullPointerException if either argument is null
2730      * @throws IllegalArgumentException if the return type of {@code filter}
2731      *          is non-void and is not the same as the {@code pos} argument of the target,
2732      *          or if {@code pos} is not between 0 and the target's arity, inclusive,
2733      *          or if the resulting method handle's type would have
2734      *          <a href="MethodHandle.html#maxarity">too many parameters</a>
2735      * @see MethodHandles#foldArguments
2736      * @see MethodHandles#filterArguments
2737      * @see MethodHandles#filterReturnValue
2738      */
2739     public static
2740     MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
2741         MethodType newType = collectArgumentsChecks(target, pos, filter);

2742         MethodType collectorType = filter.type();
2743         BoundMethodHandle result = target.rebind();
2744         LambdaForm lform;
2745         if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) {
2746             lform = result.editor().collectArgumentArrayForm(1 + pos, filter);
2747             if (lform != null) {
2748                 return result.copyWith(newType, lform);
2749             }
2750         }
2751         lform = result.editor().collectArgumentsForm(1 + pos, collectorType.basicType());
2752         return result.copyWithExtendL(newType, lform, filter);



2753     }
2754 
2755     private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
2756         MethodType targetType = target.type();
2757         MethodType filterType = filter.type();
2758         Class<?> rtype = filterType.returnType();
2759         List<Class<?>> filterArgs = filterType.parameterList();
2760         if (rtype == void.class) {
2761             return targetType.insertParameterTypes(pos, filterArgs);
2762         }
2763         if (rtype != targetType.parameterType(pos)) {
2764             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
2765         }
2766         return targetType.dropParameterTypes(pos, pos+1).insertParameterTypes(pos, filterArgs);
2767     }
2768 
2769     /**
2770      * Adapts a target method handle by post-processing
2771      * its return value (if any) with a filter (another method handle).
2772      * The result of the filter is returned from the adapter.


2811      * // and if the filter has a void return:
2812      * V target3(A...);
2813      * void filter3(V);
2814      * void adapter3(A... a) {
2815      *   V v = target3(a...);
2816      *   filter3(v);
2817      * }
2818      * }</pre></blockquote>
2819      * @param target the method handle to invoke before filtering the return value
2820      * @param filter method handle to call on the return value
2821      * @return method handle which incorporates the specified return value filtering logic
2822      * @throws NullPointerException if either argument is null
2823      * @throws IllegalArgumentException if the argument list of {@code filter}
2824      *          does not match the return type of target as described above
2825      */
2826     public static
2827     MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
2828         MethodType targetType = target.type();
2829         MethodType filterType = filter.type();
2830         filterReturnValueChecks(targetType, filterType);

2831         BoundMethodHandle result = target.rebind();
2832         BasicType rtype = BasicType.basicType(filterType.returnType());
2833         LambdaForm lform = result.editor().filterReturnForm(rtype, false);
2834         MethodType newType = targetType.changeReturnType(filterType.returnType());
2835         result = result.copyWithExtendL(newType, lform, filter);
2836         return result;



2837     }
2838 
2839     private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
2840         Class<?> rtype = targetType.returnType();
2841         int filterValues = filterType.parameterCount();
2842         if (filterValues == 0
2843                 ? (rtype != void.class)
2844                 : (rtype != filterType.parameterType(0)))
2845             throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
2846     }
2847 
2848     /**
2849      * Adapts a target method handle by pre-processing
2850      * some of its arguments, and then calling the target with
2851      * the result of the pre-processing, inserted into the original
2852      * sequence of arguments.
2853      * <p>
2854      * The pre-processing is performed by {@code combiner}, a second method handle.
2855      * Of the arguments passed to the adapter, the first {@code N} arguments
2856      * are copied to the combiner, which is then called.


2910      *   return target2(a..., b...);
2911      * }
2912      * }</pre></blockquote>
2913      * @param target the method handle to invoke after arguments are combined
2914      * @param combiner method handle to call initially on the incoming arguments
2915      * @return method handle which incorporates the specified argument folding logic
2916      * @throws NullPointerException if either argument is null
2917      * @throws IllegalArgumentException if {@code combiner}'s return type
2918      *          is non-void and not the same as the first argument type of
2919      *          the target, or if the initial {@code N} argument types
2920      *          of the target
2921      *          (skipping one matching the {@code combiner}'s return type)
2922      *          are not identical with the argument types of {@code combiner}
2923      */
2924     public static
2925     MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
2926         int foldPos = 0;
2927         MethodType targetType = target.type();
2928         MethodType combinerType = combiner.type();
2929         Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);

2930         BoundMethodHandle result = target.rebind();
2931         boolean dropResult = (rtype == void.class);
2932         // Note:  This may cache too many distinct LFs. Consider backing off to varargs code.
2933         LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType());
2934         MethodType newType = targetType;
2935         if (!dropResult)
2936             newType = newType.dropParameterTypes(foldPos, foldPos + 1);
2937         result = result.copyWithExtendL(newType, lform, combiner);
2938         return result;



2939     }
2940 
2941     private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
2942         int foldArgs   = combinerType.parameterCount();
2943         Class<?> rtype = combinerType.returnType();
2944         int foldVals = rtype == void.class ? 0 : 1;
2945         int afterInsertPos = foldPos + foldVals;
2946         boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
2947         if (ok && !(combinerType.parameterList()
2948                     .equals(targetType.parameterList().subList(afterInsertPos,
2949                                                                afterInsertPos + foldArgs))))
2950             ok = false;
2951         if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
2952             ok = false;
2953         if (!ok)
2954             throw misMatchedTypes("target and combiner types", targetType, combinerType);
2955         return rtype;
2956     }
2957 
2958     /**


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