< prev index next >

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

Print this page




1175          * The type of the method handle will be that of the method,
1176          * without any insertion of an additional receiver parameter.
1177          * The given receiver will be bound into the method handle,
1178          * so that every call to the method handle will invoke the
1179          * requested method on the given receiver.
1180          * <p>
1181          * The returned method handle will have
1182          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
1183          * the method's variable arity modifier bit ({@code 0x0080}) is set
1184          * <em>and</em> the trailing array argument is not the only argument.
1185          * (If the trailing array argument is the only argument,
1186          * the given receiver value will be bound to it.)
1187          * <p>
1188          * This is equivalent to the following code:
1189          * <blockquote><pre>{@code
1190 import static java.lang.invoke.MethodHandles.*;
1191 import static java.lang.invoke.MethodType.*;
1192 ...
1193 MethodHandle mh0 = lookup().findVirtual(defc, name, type);
1194 MethodHandle mh1 = mh0.bindTo(receiver);
1195 MethodType mt1 = mh1.type();
1196 if (mh0.isVarargsCollector())
1197   mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
1198 return mh1;
1199          * }</pre></blockquote>
1200          * where {@code defc} is either {@code receiver.getClass()} or a super
1201          * type of that class, in which the requested method is accessible
1202          * to the lookup class.
1203          * (Note that {@code bindTo} does not preserve variable arity.)
1204          * @param receiver the object from which the method is accessed
1205          * @param name the name of the method
1206          * @param type the type of the method, with the receiver argument omitted
1207          * @return the desired method handle
1208          * @throws NoSuchMethodException if the method does not exist
1209          * @throws IllegalAccessException if access checking fails
1210          *                                or if the method's variable arity modifier bit
1211          *                                is set and {@code asVarargsCollector} fails
1212          * @exception SecurityException if a security manager is present and it
1213          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
1214          * @throws NullPointerException if any argument is null
1215          * @see MethodHandle#bindTo
1216          * @see #findVirtual
1217          */


2368      * Produces a method handle which returns its sole argument when invoked.
2369      * @param type the type of the sole parameter and return value of the desired method handle
2370      * @return a unary method handle which accepts and returns the given type
2371      * @throws NullPointerException if the argument is null
2372      * @throws IllegalArgumentException if the given type is {@code void.class}
2373      */
2374     public static
2375     MethodHandle identity(Class<?> type) {
2376         Wrapper btw = (type.isPrimitive() ? Wrapper.forPrimitiveType(type) : Wrapper.OBJECT);
2377         int pos = btw.ordinal();
2378         MethodHandle ident = IDENTITY_MHS[pos];
2379         if (ident == null) {
2380             ident = setCachedMethodHandle(IDENTITY_MHS, pos, makeIdentity(btw.primitiveType()));
2381         }
2382         if (ident.type().returnType() == type)
2383             return ident;
2384         // something like identity(Foo.class); do not bother to intern these
2385         assert(btw == Wrapper.OBJECT);
2386         return makeIdentity(type);
2387     }












































2388     private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length];
2389     private static MethodHandle makeIdentity(Class<?> ptype) {
2390         MethodType mtype = MethodType.methodType(ptype, ptype);
2391         LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
2392         return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
2393     }
2394 
2395     private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
2396         int pos = btw.ordinal();
2397         MethodHandle zero = ZERO_MHS[pos];
2398         if (zero == null) {
2399             zero = setCachedMethodHandle(ZERO_MHS, pos, makeZero(btw.primitiveType()));
2400         }
2401         if (zero.type().returnType() == rtype)
2402             return zero;
2403         assert(btw == Wrapper.OBJECT);
2404         return makeZero(rtype);
2405     }
2406     private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.values().length];
2407     private static MethodHandle makeZero(Class<?> rtype) {


2599      * <blockquote><pre>
2600      * {@link #dropArguments(MethodHandle,int,List) dropArguments}{@code (target, pos, Arrays.asList(valueTypes))}
2601      * </pre></blockquote>
2602      * @param target the method handle to invoke after the arguments are dropped
2603      * @param valueTypes the type(s) of the argument(s) to drop
2604      * @param pos position of first argument to drop (zero for the leftmost)
2605      * @return a method handle which drops arguments of the given types,
2606      *         before calling the original method handle
2607      * @throws NullPointerException if the target is null,
2608      *                              or if the {@code valueTypes} array or any of its elements is null
2609      * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
2610      *                  or if {@code pos} is negative or greater than the arity of the target,
2611      *                  or if the new method handle's type would have
2612      *                  <a href="MethodHandle.html#maxarity">too many parameters</a>
2613      */
2614     public static
2615     MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
2616         return dropArguments(target, pos, Arrays.asList(valueTypes));
2617     }
2618 






























































































2619     /**
2620      * Adapts a target method handle by pre-processing
2621      * one or more of its arguments, each with its own unary filter function,
2622      * and then calling the target with each pre-processed argument
2623      * replaced by the result of its corresponding filter function.
2624      * <p>
2625      * The pre-processing is performed by one or more method handles,
2626      * specified in the elements of the {@code filters} array.
2627      * The first element of the filter array corresponds to the {@code pos}
2628      * argument of the target, and so on in sequence.
2629      * <p>
2630      * Null arguments in the array are treated as identity functions,
2631      * and the corresponding arguments left unchanged.
2632      * (If there are no non-null elements in the array, the original target is returned.)
2633      * Each filter is applied to the corresponding argument of the adapter.
2634      * <p>
2635      * If a filter {@code F} applies to the {@code N}th argument of
2636      * the target, then {@code F} must be a method handle which
2637      * takes exactly one argument.  The type of {@code F}'s sole argument
2638      * replaces the corresponding argument type of the target


3110      * @param target method handle to call if test passes
3111      * @param fallback method handle to call if test fails
3112      * @return method handle which incorporates the specified if/then/else logic
3113      * @throws NullPointerException if any argument is null
3114      * @throws IllegalArgumentException if {@code test} does not return boolean,
3115      *          or if all three method types do not match (with the return
3116      *          type of {@code test} changed to match that of the target).
3117      */
3118     public static
3119     MethodHandle guardWithTest(MethodHandle test,
3120                                MethodHandle target,
3121                                MethodHandle fallback) {
3122         MethodType gtype = test.type();
3123         MethodType ttype = target.type();
3124         MethodType ftype = fallback.type();
3125         if (!ttype.equals(ftype))
3126             throw misMatchedTypes("target and fallback types", ttype, ftype);
3127         if (gtype.returnType() != boolean.class)
3128             throw newIllegalArgumentException("guard type is not a predicate "+gtype);
3129         List<Class<?>> targs = ttype.parameterList();
3130         List<Class<?>> gargs = gtype.parameterList();
3131         if (!targs.equals(gargs)) {
3132             int gpc = gargs.size(), tpc = targs.size();
3133             if (gpc >= tpc || !targs.subList(0, gpc).equals(gargs))
3134                 throw misMatchedTypes("target and test types", ttype, gtype);
3135             test = dropArguments(test, gpc, targs.subList(gpc, tpc));
3136             gtype = test.type();
3137         }
3138         return MethodHandleImpl.makeGuardWithTest(test, target, fallback);
3139     }
3140 
3141     static <T> RuntimeException misMatchedTypes(String what, T t1, T t2) {
3142         return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2);
3143     }
3144 
3145     /**
3146      * Makes a method handle which adapts a target method handle,
3147      * by running it inside an exception handler.
3148      * If the target returns normally, the adapter returns that value.
3149      * If an exception matching the specified type is thrown, the fallback
3150      * handle is called instead on the exception, plus the original arguments.
3151      * <p>
3152      * The target and handler must have the same corresponding
3153      * argument and return types, except that handler may omit trailing arguments
3154      * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
3155      * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
3156      * <p>


3188      * @throws NullPointerException if any argument is null
3189      * @throws IllegalArgumentException if {@code handler} does not accept
3190      *          the given exception type, or if the method handle types do
3191      *          not match in their return types and their
3192      *          corresponding parameters
3193      * @see MethodHandles#tryFinally(MethodHandle, MethodHandle)
3194      */
3195     public static
3196     MethodHandle catchException(MethodHandle target,
3197                                 Class<? extends Throwable> exType,
3198                                 MethodHandle handler) {
3199         MethodType ttype = target.type();
3200         MethodType htype = handler.type();
3201         if (!Throwable.class.isAssignableFrom(exType))
3202             throw new ClassCastException(exType.getName());
3203         if (htype.parameterCount() < 1 ||
3204             !htype.parameterType(0).isAssignableFrom(exType))
3205             throw newIllegalArgumentException("handler does not accept exception type "+exType);
3206         if (htype.returnType() != ttype.returnType())
3207             throw misMatchedTypes("target and handler return types", ttype, htype);
3208         List<Class<?>> targs = ttype.parameterList();
3209         List<Class<?>> hargs = htype.parameterList();
3210         hargs = hargs.subList(1, hargs.size());  // omit leading parameter from handler
3211         if (!targs.equals(hargs)) {
3212             int hpc = hargs.size(), tpc = targs.size();
3213             if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs))
3214                 throw misMatchedTypes("target and handler types", ttype, htype);
3215             handler = dropArguments(handler, 1+hpc, targs.subList(hpc, tpc));
3216             htype = handler.type();
3217         }
3218         return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
3219     }
3220 
3221     /**
3222      * Produces a method handle which will throw exceptions of the given {@code exType}.
3223      * The method handle will accept a single argument of {@code exType},
3224      * and immediately throw it as an exception.
3225      * The method type will nominally specify a return of {@code returnType}.
3226      * The return type may be anything convenient:  It doesn't matter to the
3227      * method handle's behavior, since it will never return normally.
3228      * @param returnType the return type of the desired method handle
3229      * @param exType the parameter type of the desired method handle
3230      * @return method handle which can throw the given exceptions
3231      * @throws NullPointerException if either argument is null
3232      */
3233     public static
3234     MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
3235         if (!Throwable.class.isAssignableFrom(exType))
3236             throw new ClassCastException(exType.getName());


3454 
3455         // Step 1B: determine loop parameters.
3456         final List<Class<?>> commonSuffix = buildCommonSuffix(init, step, pred, fini, commonPrefix.size());
3457         checkLoop1b(init, commonSuffix);
3458 
3459         // Step 1C: determine loop return type.
3460         // Step 1D: check other types.
3461         final Class<?> loopReturnType = fini.stream().filter(Objects::nonNull).map(MethodHandle::type).
3462                 map(MethodType::returnType).findFirst().orElse(void.class);
3463         checkLoop1cd(pred, fini, loopReturnType);
3464 
3465         // Step 2: determine parameter lists.
3466         final List<Class<?>> commonParameterSequence = new ArrayList<>(commonPrefix);
3467         commonParameterSequence.addAll(commonSuffix);
3468         checkLoop2(step, pred, fini, commonParameterSequence);
3469 
3470         // Step 3: fill in omitted functions.
3471         for (int i = 0; i < nclauses; ++i) {
3472             Class<?> t = iterationVariableTypes.get(i);
3473             if (init.get(i) == null) {
3474                 init.set(i, zeroHandle(t));
3475             }
3476             if (step.get(i) == null) {
3477                 step.set(i, dropArguments(t == void.class ? zeroHandle(t) : identity(t), 0, commonPrefix.subList(0, i)));
3478             }
3479             if (pred.get(i) == null) {
3480                 pred.set(i, constant(boolean.class, true));
3481             }
3482             if (fini.get(i) == null) {
3483                 fini.set(i, zeroHandle(t));
3484             }
3485         }
3486 
3487         // Step 4: fill in missing parameter types.
3488         List<MethodHandle> finit = fillParameterTypes(init, commonSuffix);
3489         List<MethodHandle> fstep = fillParameterTypes(step, commonParameterSequence);
3490         List<MethodHandle> fpred = fillParameterTypes(pred, commonParameterSequence);
3491         List<MethodHandle> ffini = fillParameterTypes(fini, commonParameterSequence);
3492 
3493         assert finit.stream().map(MethodHandle::type).map(MethodType::parameterList).
3494                 allMatch(pl -> pl.equals(commonSuffix));
3495         assert Stream.of(fstep, fpred, ffini).flatMap(List::stream).map(MethodHandle::type).map(MethodType::parameterList).
3496                 allMatch(pl -> pl.equals(commonParameterSequence));
3497 
3498         return MethodHandleImpl.makeLoop(loopReturnType, commonSuffix, commonPrefix, finit, fstep, fpred, ffini);
3499     }
3500 
3501     private static List<MethodHandle> fillParameterTypes(List<MethodHandle> hs, final List<Class<?>> targetParams) {
3502         return hs.stream().map(h -> {
3503             int pc = h.type().parameterCount();


3557      *     MethodHandle[]
3558      *         checkExit = {null, null, pred, identity(init.type().returnType())},
3559      *         varBody = {init, body};
3560      *     return loop(checkExit, varBody);
3561      * }
3562      * }</pre></blockquote>
3563      *
3564      * @param init initializer: it should provide the initial value of the loop variable. This controls the loop's
3565      *             result type. Passing {@code null} or a {@code void} init function will make the loop's result type
3566      *             {@code void}.
3567      * @param pred condition for the loop, which may not be {@code null}.
3568      * @param body body of the loop, which may not be {@code null}.
3569      *
3570      * @return the value of the loop variable as the loop terminates.
3571      * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
3572      *
3573      * @see MethodHandles#loop(MethodHandle[][])
3574      * @since 9
3575      */
3576     public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
3577         MethodHandle fin = init == null ? zeroHandle(void.class) : identity(init.type().returnType());
3578         MethodHandle[] checkExit = {null, null, pred, fin};
3579         MethodHandle[] varBody = {init, body};
3580         return loop(checkExit, varBody);
3581     }
3582 
3583     /**
3584      * Constructs a {@code do-while} loop from an initializer, a body, and a predicate. This is a convenience wrapper
3585      * for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
3586      * <p>
3587      * The loop handle's result type is the same as the sole loop variable's, i.e., the result type of {@code init}.
3588      * The parameter type list of {@code init} also determines that of the resulting handle. The {@code pred} handle
3589      * must have an additional leading parameter of the same type as {@code init}'s result, and so must the {@code
3590      * body}. These constraints follow directly from those described for the {@linkplain MethodHandles#loop(MethodHandle[][])
3591      * generic loop combinator}.
3592      * <p>
3593      * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
3594      * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
3595      * passed to the loop.
3596      * <blockquote><pre>{@code
3597      * V init(A);


3623      * MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
3624      *     MethodHandle[] clause = { init, body, pred, identity(init.type().returnType()) };
3625      *     return loop(clause);
3626      * }
3627      * }</pre></blockquote>
3628      *
3629      *
3630      * @param init initializer: it should provide the initial value of the loop variable. This controls the loop's
3631      *             result type. Passing {@code null} or a {@code void} init function will make the loop's result type
3632      *             {@code void}.
3633      * @param pred condition for the loop, which may not be {@code null}.
3634      * @param body body of the loop, which may not be {@code null}.
3635      *
3636      * @return the value of the loop variable as the loop terminates.
3637      * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
3638      *
3639      * @see MethodHandles#loop(MethodHandle[][])
3640      * @since 9
3641      */
3642     public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
3643         MethodHandle fin = init == null ? zeroHandle(void.class) : identity(init.type().returnType());
3644         MethodHandle[] clause = {init, body, pred, fin};
3645         return loop(clause);
3646     }
3647 
3648     /**
3649      * Constructs a loop that runs a given number of iterations. The loop counter is an {@code int} initialized from the
3650      * {@code iterations} handle evaluation result. The counter is passed to the {@code body} function, so that must
3651      * accept an initial {@code int} argument. The result of the loop execution is the final value of the additional
3652      * local state. This is a convenience wrapper for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop
3653      * combinator}.
3654      * <p>
3655      * The result type and parameter type list of {@code init} determine those of the resulting handle. The {@code
3656      * iterations} handle must accept the same parameter types as {@code init} but return an {@code int}. The {@code
3657      * body} handle must accept the same parameter types as well, preceded by an {@code int} parameter for the counter,
3658      * and a parameter of the same type as {@code init}'s result. These constraints follow directly from those described
3659      * for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
3660      * <p>
3661      * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
3662      * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
3663      * passed to the loop.


3758      *     return loop(indexVar, loopLimit, bodyClause);
3759      * }
3760      * }</pre></blockquote>
3761      *
3762      * @param start a handle to return the start value of the loop counter.
3763      *              If it is {@code null}, a constant zero is assumed.
3764      * @param end a non-{@code null} handle to return the end value of the loop counter (the loop will run to {@code end-1}).
3765      * @param init initializer for additional loop state. This determines the loop's result type.
3766      *             Passing {@code null} or a {@code void} init function will make the loop's result type
3767      *             {@code void}.
3768      * @param body the body of the loop, which must not be {@code null}.
3769      *             It must accept an initial {@code int} parameter (for the counter), and then any
3770      *             additional loop-local variable plus loop parameters.
3771      *
3772      * @return a method handle representing the loop.
3773      * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
3774      *
3775      * @since 9
3776      */
3777     public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
3778         MethodHandle returnVar = dropArguments(init == null ? zeroHandle(void.class) : identity(init.type().returnType()),
3779                 0, int.class, int.class);
3780         MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)};
3781         MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar};
3782         MethodHandle[] bodyClause = {init, dropArguments(body, 1, int.class)};
3783         return loop(indexVar, loopLimit, bodyClause);
3784     }
3785 
3786     /**
3787      * Constructs a loop that ranges over the elements produced by an {@code Iterator<T>}.
3788      * The iterator will be produced by the evaluation of the {@code iterator} handle.
3789      * If this handle is passed as {@code null} the method {@link Iterable#iterator} will be used instead,
3790      * and will be applied to a leading argument of the loop handle.
3791      * Each value produced by the iterator is passed to the {@code body}, which must accept an initial {@code T} parameter.
3792      * The result of the loop execution is the final value of the additional local state
3793      * obtained by running {@code init}.
3794      * <p>
3795      * This is a convenience wrapper for the
3796      * {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}, and the constraints imposed on the {@code body}
3797      * handle follow directly from those described for the latter.
3798      * <p>


3859      * @param body the body of the loop, which must not be {@code null}.
3860      *             It must accept an initial {@code T} parameter (for the iterated values), and then any
3861      *             additional loop-local variable plus loop parameters.
3862      *
3863      * @return a method handle embodying the iteration loop functionality.
3864      * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
3865      *
3866      * @since 9
3867      */
3868     public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
3869         checkIteratedLoop(body);
3870 
3871         MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator);
3872         MethodHandle initIterator = iterator == null ?
3873                 initit.asType(initit.type().changeParameterType(0, body.type().parameterType(init == null ? 1 : 2))) :
3874                 iterator;
3875         Class<?> itype = initIterator.type().returnType();
3876         Class<?> ttype = body.type().parameterType(0);
3877 
3878         MethodHandle returnVar =
3879                 dropArguments(init == null ? zeroHandle(void.class) : identity(init.type().returnType()), 0, itype);
3880         MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext);
3881         MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype));
3882 
3883         MethodHandle[] iterVar = {initIterator, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred), returnVar};
3884         MethodHandle[] bodyClause = {init, filterArgument(body, 0, nextVal)};
3885 
3886         return loop(iterVar, bodyClause);
3887     }
3888 
3889     /**
3890      * Makes a method handle that adapts a {@code target} method handle by wrapping it in a {@code try-finally} block.
3891      * Another method handle, {@code cleanup}, represents the functionality of the {@code finally} block. Any exception
3892      * thrown during the execution of the {@code target} handle will be passed to the {@code cleanup} handle. The
3893      * exception will be rethrown, unless {@code cleanup} handle throws an exception first.  The
3894      * value returned from the {@code cleanup} handle's execution will be the result of the execution of the
3895      * {@code try-finally} handle.
3896      * <p>
3897      * The {@code cleanup} handle will be passed one or two additional leading arguments.
3898      * The first is the exception thrown during the
3899      * execution of the {@code target} handle, or {@code null} if no exception was thrown.


3953      * @param cleanup the handle that is invoked in the finally block.
3954      *
3955      * @return a method handle embodying the {@code try-finally} block composed of the two arguments.
3956      * @throws NullPointerException if any argument is null
3957      * @throws IllegalArgumentException if {@code cleanup} does not accept
3958      *          the required leading arguments, or if the method handle types do
3959      *          not match in their return types and their
3960      *          corresponding trailing parameters
3961      *
3962      * @see MethodHandles#catchException(MethodHandle, Class, MethodHandle)
3963      * @since 9
3964      */
3965     public static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup) {
3966         List<Class<?>> targetParamTypes = target.type().parameterList();
3967         List<Class<?>> cleanupParamTypes = cleanup.type().parameterList();
3968         Class<?> rtype = target.type().returnType();
3969 
3970         checkTryFinally(target, cleanup);
3971 
3972         // Match parameter lists: if the cleanup has a shorter parameter list than the target, add ignored arguments.
3973         int tpSize = targetParamTypes.size();
3974         int cpPrefixLength = rtype == void.class ? 1 : 2;
3975         int cpSize = cleanupParamTypes.size();
3976         MethodHandle aCleanup = cpSize - cpPrefixLength < tpSize ?
3977                 dropArguments(cleanup, cpSize, targetParamTypes.subList(tpSize - (cpSize - cpPrefixLength), tpSize)) :
3978                 cleanup;
3979 
3980         MethodHandle aTarget = target.asSpreader(Object[].class, target.type().parameterCount());
3981         aCleanup = aCleanup.asSpreader(Object[].class, tpSize);
3982 
3983         return MethodHandleImpl.makeTryFinally(aTarget, aCleanup, rtype, targetParamTypes);
3984     }
3985 
3986     /**
3987      * Adapts a target method handle by pre-processing some of its arguments, starting at a given position, and then
3988      * calling the target with the result of the pre-processing, inserted into the original sequence of arguments just
3989      * before the folded arguments.
3990      * <p>
3991      * This method is closely related to {@link #foldArguments(MethodHandle, MethodHandle)}, but allows to control the
3992      * position in the parameter list at which folding takes place. The argument controlling this, {@code pos}, is a
3993      * zero-based index. The aforementioned method {@link #foldArguments(MethodHandle, MethodHandle)} assumes position
3994      * 0.
3995      * <p>
3996      * @apiNote Example:
3997      * <blockquote><pre>{@code
3998     import static java.lang.invoke.MethodHandles.*;
3999     import static java.lang.invoke.MethodType.*;
4000     ...
4001     MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,


4052      *          are not identical with the argument types of {@code combiner}
4053      *
4054      * @see #foldArguments(MethodHandle, MethodHandle)
4055      * @since 9
4056      */
4057     public static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner) {
4058         MethodType targetType = target.type();
4059         MethodType combinerType = combiner.type();
4060         Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType);
4061         BoundMethodHandle result = target.rebind();
4062         boolean dropResult = rtype == void.class;
4063         LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType());
4064         MethodType newType = targetType;
4065         if (!dropResult) {
4066             newType = newType.dropParameterTypes(pos, pos + 1);
4067         }
4068         result = result.copyWithExtendL(newType, lform, combiner);
4069         return result;
4070     }
4071 
4072     /**
4073      * Wrap creation of a proper zero handle for a given type.
4074      *
4075      * @param type the type.
4076      *
4077      * @return a zero value for the given type.
4078      */
4079     static MethodHandle zeroHandle(Class<?> type) {
4080         return type.isPrimitive() ?  zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
4081     }
4082 
4083     private static void checkLoop0(MethodHandle[][] clauses) {
4084         if (clauses == null || clauses.length == 0) {
4085             throw newIllegalArgumentException("null or no clauses passed");
4086         }
4087         if (Stream.of(clauses).anyMatch(Objects::isNull)) {
4088             throw newIllegalArgumentException("null clauses are not allowed");
4089         }
4090         if (Stream.of(clauses).anyMatch(c -> c.length > 4)) {
4091             throw newIllegalArgumentException("All loop clauses must be represented as MethodHandle arrays with at most 4 elements.");
4092         }
4093     }
4094 
4095     private static void checkLoop1a(int i, MethodHandle in, MethodHandle st) {
4096         if (in.type().returnType() != st.type().returnType()) {
4097             throw misMatchedTypes("clause " + i + ": init and step return types", in.type().returnType(),
4098                     st.type().returnType());
4099         }
4100     }
4101 




1175          * The type of the method handle will be that of the method,
1176          * without any insertion of an additional receiver parameter.
1177          * The given receiver will be bound into the method handle,
1178          * so that every call to the method handle will invoke the
1179          * requested method on the given receiver.
1180          * <p>
1181          * The returned method handle will have
1182          * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
1183          * the method's variable arity modifier bit ({@code 0x0080}) is set
1184          * <em>and</em> the trailing array argument is not the only argument.
1185          * (If the trailing array argument is the only argument,
1186          * the given receiver value will be bound to it.)
1187          * <p>
1188          * This is equivalent to the following code:
1189          * <blockquote><pre>{@code
1190 import static java.lang.invoke.MethodHandles.*;
1191 import static java.lang.invoke.MethodType.*;
1192 ...
1193 MethodHandle mh0 = lookup().findVirtual(defc, name, type);
1194 MethodHandle mh1 = mh0.bindTo(receiver);
1195 mh1 = mh1.withVarargs(mh0.isVarargsCollector());


1196 return mh1;
1197          * }</pre></blockquote>
1198          * where {@code defc} is either {@code receiver.getClass()} or a super
1199          * type of that class, in which the requested method is accessible
1200          * to the lookup class.
1201          * (Note that {@code bindTo} does not preserve variable arity.)
1202          * @param receiver the object from which the method is accessed
1203          * @param name the name of the method
1204          * @param type the type of the method, with the receiver argument omitted
1205          * @return the desired method handle
1206          * @throws NoSuchMethodException if the method does not exist
1207          * @throws IllegalAccessException if access checking fails
1208          *                                or if the method's variable arity modifier bit
1209          *                                is set and {@code asVarargsCollector} fails
1210          * @exception SecurityException if a security manager is present and it
1211          *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
1212          * @throws NullPointerException if any argument is null
1213          * @see MethodHandle#bindTo
1214          * @see #findVirtual
1215          */


2366      * Produces a method handle which returns its sole argument when invoked.
2367      * @param type the type of the sole parameter and return value of the desired method handle
2368      * @return a unary method handle which accepts and returns the given type
2369      * @throws NullPointerException if the argument is null
2370      * @throws IllegalArgumentException if the given type is {@code void.class}
2371      */
2372     public static
2373     MethodHandle identity(Class<?> type) {
2374         Wrapper btw = (type.isPrimitive() ? Wrapper.forPrimitiveType(type) : Wrapper.OBJECT);
2375         int pos = btw.ordinal();
2376         MethodHandle ident = IDENTITY_MHS[pos];
2377         if (ident == null) {
2378             ident = setCachedMethodHandle(IDENTITY_MHS, pos, makeIdentity(btw.primitiveType()));
2379         }
2380         if (ident.type().returnType() == type)
2381             return ident;
2382         // something like identity(Foo.class); do not bother to intern these
2383         assert(btw == Wrapper.OBJECT);
2384         return makeIdentity(type);
2385     }
2386      
2387     /** Produces a constant method handle of the requested return type which
2388      * returns the default value for that type every time it is invoked.
2389      * The resulting constant method handle will have no side effects.
2390      * <p>The returned method handle is equivalent to {@code empty(methodType(type))}.
2391      * It is also equivalent to {@code explicitCastArguments(constant(Object.class, null), methodType(type))},
2392      * since {@code explicitCastArguments} converts {@code null} to default values.
2393      * @param type the expected return type of the desired method handle
2394      * @return a constant method handle that takes no arguments and returns the default value of the given type (or void, if the type is void)
2395      * @throws NullPointerException if the argument is null
2396      * @see MethodHandles#constant
2397      * @see MethodHandles#empty
2398      * @since 9
2399      */
2400     public static  MethodHandle zero(Class<?> type) {
2401         Objects.requireNonNull(type);
2402         return type.isPrimitive() ?  zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
2403     }
2404 
2405     private static MethodHandle identityOrVoid(Class<?> type) {
2406         return type == void.class ? zero(type) : identity(type);
2407     }
2408 
2409     /**
2410      * Produces a method handle of the requested type which ignores any arguments, does nothing,
2411      * and returns a suitable default depending on the return type.
2412      * That is, it returns a zero primitive value, a {@code null}, or {@code void}.
2413      * <p>The returned method handle is equivalent to
2414      * {@code dropArguments(zero(type.returnType()), 0, type.parameterList())}.
2415      * <p>
2416      * Example:  Given a predicate and target, a useful "if-then" construct can be constructed as
2417      * {@code guardWithTest(pred, target, empty(target.type())}.
2418      * @param type the type of the desired method handle
2419      * @return a constant method handle of the given type, which returns a default value of the given return type
2420      * @throws NullPointerException if the argument is null
2421      * @see MethodHandles#zero
2422      * @see MethodHandles#constant
2423      * @since 9
2424      */
2425     public static  MethodHandle empty(MethodType type) {
2426         Objects.requireNonNull(type);
2427         return dropArguments(zero(type.returnType()), 0, type.parameterList());
2428     }
2429 
2430     private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length];
2431     private static MethodHandle makeIdentity(Class<?> ptype) {
2432         MethodType mtype = MethodType.methodType(ptype, ptype);
2433         LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
2434         return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
2435     }
2436 
2437     private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
2438         int pos = btw.ordinal();
2439         MethodHandle zero = ZERO_MHS[pos];
2440         if (zero == null) {
2441             zero = setCachedMethodHandle(ZERO_MHS, pos, makeZero(btw.primitiveType()));
2442         }
2443         if (zero.type().returnType() == rtype)
2444             return zero;
2445         assert(btw == Wrapper.OBJECT);
2446         return makeZero(rtype);
2447     }
2448     private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.values().length];
2449     private static MethodHandle makeZero(Class<?> rtype) {


2641      * <blockquote><pre>
2642      * {@link #dropArguments(MethodHandle,int,List) dropArguments}{@code (target, pos, Arrays.asList(valueTypes))}
2643      * </pre></blockquote>
2644      * @param target the method handle to invoke after the arguments are dropped
2645      * @param valueTypes the type(s) of the argument(s) to drop
2646      * @param pos position of first argument to drop (zero for the leftmost)
2647      * @return a method handle which drops arguments of the given types,
2648      *         before calling the original method handle
2649      * @throws NullPointerException if the target is null,
2650      *                              or if the {@code valueTypes} array or any of its elements is null
2651      * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
2652      *                  or if {@code pos} is negative or greater than the arity of the target,
2653      *                  or if the new method handle's type would have
2654      *                  <a href="MethodHandle.html#maxarity">too many parameters</a>
2655      */
2656     public static
2657     MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
2658         return dropArguments(target, pos, Arrays.asList(valueTypes));
2659     }
2660 
2661     // private version which allows caller some freedom with error handling
2662     private static MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos,
2663                                       boolean nullOnFailure) {
2664         List<Class<?>> oldTypes = target.type().parameterList();
2665         int match = oldTypes.size();
2666         if (skip != 0) {
2667             if (skip < 0 || skip > match) {
2668                 throw newIllegalArgumentException("illegal skip", skip, target);
2669             }
2670             oldTypes = oldTypes.subList(skip, match);
2671             match -= skip;
2672         }
2673         List<Class<?>> addTypes = newTypes;
2674         int add = addTypes.size();
2675         if (pos != 0) {
2676             if (pos < 0 || pos > add) {
2677                 throw newIllegalArgumentException("illegal pos", pos, newTypes);
2678             }
2679             addTypes = addTypes.subList(pos, add);
2680             add -= pos; assert(addTypes.size() == add);
2681         }
2682         // Do not add types which already match the existing arguments.
2683         if (match > add || !oldTypes.equals(addTypes.subList(0, match))) {
2684             if (nullOnFailure) {
2685                 return null;
2686             } 
2687             throw newIllegalArgumentException("argument lists do not match", oldTypes, newTypes);
2688         }
2689         addTypes = addTypes.subList(match, add);
2690         add -= match; assert(addTypes.size() == add);
2691         // newTypes:     (   P*[pos], M*[match], A*[add] )
2692         // target: ( S*[skip],        M*[match]  )
2693         MethodHandle adapter = target;
2694         if (add > 0) {
2695             adapter = dropArguments(adapter, skip+ match, addTypes);
2696         }
2697         // adapter: (S*[skip],        M*[match], A*[add] )
2698         if (pos > 0) {
2699             adapter = dropArguments(adapter, skip, newTypes.subList(0, pos));
2700        }
2701         // adapter: (S*[skip], P*[pos], M*[match], A*[add] )
2702         return adapter;
2703     }
2704 
2705     /**
2706      * Adapts a target method handle to match the given parameter type list, if necessary, by adding dummy arguments.
2707      * Some leading parameters are first skipped; they will be left unchanged and are otherwise ignored.
2708      * The remaining types in the target's parameter type list must be contained as a sub-list of the given type list,
2709      * at the given position.
2710      * Any non-matching parameter types (before or after the matching sub-list) are inserted in corresponding
2711      * positions of the target method handle's parameters, as if by {@link #dropArguments}.
2712      * (More precisely, elements in the new list before {@code pos} are inserted into the target list at {@code skip},
2713      * while elements in the new list after the match beginning at {@code pos} are inserted at the end of the
2714      * target list.)
2715      * The target's return type will be unchanged.
2716      * <p>
2717      * <b>Example:</b>
2718      * Two method handles whose argument lists are "effectively identical" (i.e., identical
2719      * in a common prefix) may be mutually converted to a common type
2720      * by two calls to {@code dropArgumentsToMatch}, as follows:
2721      * <blockquote><pre>{@code
2722 import static java.lang.invoke.MethodHandles.*;
2723 import static java.lang.invoke.MethodType.*;
2724 ...
2725 ...
2726 MethodHandle h0= constant(boolean.class, true);
2727 MethodHandle h1 = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class));
2728 MethodType bigType = h1.type().insertParameterTypes(1, String.class, int.class);
2729 MethodHandle h2 = dropArguments(h1, 0, bigType.parameterList());
2730 if (h1.type().parameterCount() < h2.type().parameterCount())
2731     h1 = dropArgumentsToMatch(h1, 0, h2.type().parameterList(), 0);  // lengthen h1
2732 else
2733     h2 = dropArgumentsToMatch(h2, 0, h1.type().parameterList(), 0);    // lengthen h2
2734 MethodHandle h3 = guardWithTest(h0, h1, h2);
2735 assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));
2736      * }</pre></blockquote>
2737      * @param target the method handle to adapt
2738      * @param skip number of targets parameters to disregard (they will be unchanged)
2739      * @param newTypes the desired argument list of the method handle
2740      * @param pos place in {@code newTypes} where the non-skipped target parameters must occur
2741      * @return a possibly adapted method handle
2742      * @throws NullPointerException if either argument is null
2743      * @throws IllegalArgumentException
2744      *         if either index is out of range in its corresponding list, or
2745      *         if the non-skipped target parameter types match the new types at {@code pos}
2746      * @since 9
2747      */
2748     public static
2749     MethodHandle dropArgumentsToMatch(MethodHandle target, int skip, List<Class<?>> newTypes, int pos) {
2750         Objects.requireNonNull(target);
2751         Objects.requireNonNull(newTypes);
2752         return dropArgumentsToMatch(target, skip, newTypes, pos, false);
2753     }
2754 
2755     /**
2756      * Adapts a target method handle by pre-processing
2757      * one or more of its arguments, each with its own unary filter function,
2758      * and then calling the target with each pre-processed argument
2759      * replaced by the result of its corresponding filter function.
2760      * <p>
2761      * The pre-processing is performed by one or more method handles,
2762      * specified in the elements of the {@code filters} array.
2763      * The first element of the filter array corresponds to the {@code pos}
2764      * argument of the target, and so on in sequence.
2765      * <p>
2766      * Null arguments in the array are treated as identity functions,
2767      * and the corresponding arguments left unchanged.
2768      * (If there are no non-null elements in the array, the original target is returned.)
2769      * Each filter is applied to the corresponding argument of the adapter.
2770      * <p>
2771      * If a filter {@code F} applies to the {@code N}th argument of
2772      * the target, then {@code F} must be a method handle which
2773      * takes exactly one argument.  The type of {@code F}'s sole argument
2774      * replaces the corresponding argument type of the target


3246      * @param target method handle to call if test passes
3247      * @param fallback method handle to call if test fails
3248      * @return method handle which incorporates the specified if/then/else logic
3249      * @throws NullPointerException if any argument is null
3250      * @throws IllegalArgumentException if {@code test} does not return boolean,
3251      *          or if all three method types do not match (with the return
3252      *          type of {@code test} changed to match that of the target).
3253      */
3254     public static
3255     MethodHandle guardWithTest(MethodHandle test,
3256                                MethodHandle target,
3257                                MethodHandle fallback) {
3258         MethodType gtype = test.type();
3259         MethodType ttype = target.type();
3260         MethodType ftype = fallback.type();
3261         if (!ttype.equals(ftype))
3262             throw misMatchedTypes("target and fallback types", ttype, ftype);
3263         if (gtype.returnType() != boolean.class)
3264             throw newIllegalArgumentException("guard type is not a predicate "+gtype);
3265         List<Class<?>> targs = ttype.parameterList();
3266         test = dropArgumentsToMatch(test, 0, targs, 0, true);
3267         if (test == null) {


3268             throw misMatchedTypes("target and test types", ttype, gtype);


3269         }
3270         return MethodHandleImpl.makeGuardWithTest(test, target, fallback);
3271     }
3272 
3273     static <T> RuntimeException misMatchedTypes(String what, T t1, T t2) {
3274         return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2);
3275     }
3276 
3277     /**
3278      * Makes a method handle which adapts a target method handle,
3279      * by running it inside an exception handler.
3280      * If the target returns normally, the adapter returns that value.
3281      * If an exception matching the specified type is thrown, the fallback
3282      * handle is called instead on the exception, plus the original arguments.
3283      * <p>
3284      * The target and handler must have the same corresponding
3285      * argument and return types, except that handler may omit trailing arguments
3286      * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
3287      * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
3288      * <p>


3320      * @throws NullPointerException if any argument is null
3321      * @throws IllegalArgumentException if {@code handler} does not accept
3322      *          the given exception type, or if the method handle types do
3323      *          not match in their return types and their
3324      *          corresponding parameters
3325      * @see MethodHandles#tryFinally(MethodHandle, MethodHandle)
3326      */
3327     public static
3328     MethodHandle catchException(MethodHandle target,
3329                                 Class<? extends Throwable> exType,
3330                                 MethodHandle handler) {
3331         MethodType ttype = target.type();
3332         MethodType htype = handler.type();
3333         if (!Throwable.class.isAssignableFrom(exType))
3334             throw new ClassCastException(exType.getName());
3335         if (htype.parameterCount() < 1 ||
3336             !htype.parameterType(0).isAssignableFrom(exType))
3337             throw newIllegalArgumentException("handler does not accept exception type "+exType);
3338         if (htype.returnType() != ttype.returnType())
3339             throw misMatchedTypes("target and handler return types", ttype, htype);
3340         handler = dropArgumentsToMatch(handler, 1, ttype.parameterList(), 0, true);
3341         if (handler == null) {




3342             throw misMatchedTypes("target and handler types", ttype, htype);


3343         }
3344         return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
3345     }
3346 
3347     /**
3348      * Produces a method handle which will throw exceptions of the given {@code exType}.
3349      * The method handle will accept a single argument of {@code exType},
3350      * and immediately throw it as an exception.
3351      * The method type will nominally specify a return of {@code returnType}.
3352      * The return type may be anything convenient:  It doesn't matter to the
3353      * method handle's behavior, since it will never return normally.
3354      * @param returnType the return type of the desired method handle
3355      * @param exType the parameter type of the desired method handle
3356      * @return method handle which can throw the given exceptions
3357      * @throws NullPointerException if either argument is null
3358      */
3359     public static
3360     MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
3361         if (!Throwable.class.isAssignableFrom(exType))
3362             throw new ClassCastException(exType.getName());


3580 
3581         // Step 1B: determine loop parameters.
3582         final List<Class<?>> commonSuffix = buildCommonSuffix(init, step, pred, fini, commonPrefix.size());
3583         checkLoop1b(init, commonSuffix);
3584 
3585         // Step 1C: determine loop return type.
3586         // Step 1D: check other types.
3587         final Class<?> loopReturnType = fini.stream().filter(Objects::nonNull).map(MethodHandle::type).
3588                 map(MethodType::returnType).findFirst().orElse(void.class);
3589         checkLoop1cd(pred, fini, loopReturnType);
3590 
3591         // Step 2: determine parameter lists.
3592         final List<Class<?>> commonParameterSequence = new ArrayList<>(commonPrefix);
3593         commonParameterSequence.addAll(commonSuffix);
3594         checkLoop2(step, pred, fini, commonParameterSequence);
3595 
3596         // Step 3: fill in omitted functions.
3597         for (int i = 0; i < nclauses; ++i) {
3598             Class<?> t = iterationVariableTypes.get(i);
3599             if (init.get(i) == null) {
3600                 init.set(i, empty(MethodType.methodType(t, commonSuffix)));
3601             }
3602             if (step.get(i) == null) {
3603                 step.set(i, dropArgumentsToMatch(identityOrVoid(t), 0, commonParameterSequence, i));
3604             }
3605             if (pred.get(i) == null) {
3606                 pred.set(i, dropArguments(constant(boolean.class, true), 0, commonParameterSequence));
3607             }
3608             if (fini.get(i) == null) {
3609                 fini.set(i, empty(MethodType.methodType(t, commonParameterSequence)));
3610             }
3611         }
3612 
3613         // Step 4: fill in missing parameter types.
3614         List<MethodHandle> finit = fillParameterTypes(init, commonSuffix);
3615         List<MethodHandle> fstep = fillParameterTypes(step, commonParameterSequence);
3616         List<MethodHandle> fpred = fillParameterTypes(pred, commonParameterSequence);
3617         List<MethodHandle> ffini = fillParameterTypes(fini, commonParameterSequence);
3618 
3619         assert finit.stream().map(MethodHandle::type).map(MethodType::parameterList).
3620                 allMatch(pl -> pl.equals(commonSuffix));
3621         assert Stream.of(fstep, fpred, ffini).flatMap(List::stream).map(MethodHandle::type).map(MethodType::parameterList).
3622                 allMatch(pl -> pl.equals(commonParameterSequence));
3623 
3624         return MethodHandleImpl.makeLoop(loopReturnType, commonSuffix, commonPrefix, finit, fstep, fpred, ffini);
3625     }
3626 
3627     private static List<MethodHandle> fillParameterTypes(List<MethodHandle> hs, final List<Class<?>> targetParams) {
3628         return hs.stream().map(h -> {
3629             int pc = h.type().parameterCount();


3683      *     MethodHandle[]
3684      *         checkExit = {null, null, pred, identity(init.type().returnType())},
3685      *         varBody = {init, body};
3686      *     return loop(checkExit, varBody);
3687      * }
3688      * }</pre></blockquote>
3689      *
3690      * @param init initializer: it should provide the initial value of the loop variable. This controls the loop's
3691      *             result type. Passing {@code null} or a {@code void} init function will make the loop's result type
3692      *             {@code void}.
3693      * @param pred condition for the loop, which may not be {@code null}.
3694      * @param body body of the loop, which may not be {@code null}.
3695      *
3696      * @return the value of the loop variable as the loop terminates.
3697      * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
3698      *
3699      * @see MethodHandles#loop(MethodHandle[][])
3700      * @since 9
3701      */
3702     public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
3703         MethodHandle fin = init == null ? zero(void.class) : identity(init.type().returnType());
3704         MethodHandle[] checkExit = {null, null, pred, fin};
3705         MethodHandle[] varBody = {init, body};
3706         return loop(checkExit, varBody);
3707     }
3708 
3709     /**
3710      * Constructs a {@code do-while} loop from an initializer, a body, and a predicate. This is a convenience wrapper
3711      * for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
3712      * <p>
3713      * The loop handle's result type is the same as the sole loop variable's, i.e., the result type of {@code init}.
3714      * The parameter type list of {@code init} also determines that of the resulting handle. The {@code pred} handle
3715      * must have an additional leading parameter of the same type as {@code init}'s result, and so must the {@code
3716      * body}. These constraints follow directly from those described for the {@linkplain MethodHandles#loop(MethodHandle[][])
3717      * generic loop combinator}.
3718      * <p>
3719      * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
3720      * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
3721      * passed to the loop.
3722      * <blockquote><pre>{@code
3723      * V init(A);


3749      * MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
3750      *     MethodHandle[] clause = { init, body, pred, identity(init.type().returnType()) };
3751      *     return loop(clause);
3752      * }
3753      * }</pre></blockquote>
3754      *
3755      *
3756      * @param init initializer: it should provide the initial value of the loop variable. This controls the loop's
3757      *             result type. Passing {@code null} or a {@code void} init function will make the loop's result type
3758      *             {@code void}.
3759      * @param pred condition for the loop, which may not be {@code null}.
3760      * @param body body of the loop, which may not be {@code null}.
3761      *
3762      * @return the value of the loop variable as the loop terminates.
3763      * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
3764      *
3765      * @see MethodHandles#loop(MethodHandle[][])
3766      * @since 9
3767      */
3768     public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
3769         MethodHandle fin = init == null ? zero(void.class) : identity(init.type().returnType());
3770         MethodHandle[] clause = {init, body, pred, fin};
3771         return loop(clause);
3772     }
3773 
3774     /**
3775      * Constructs a loop that runs a given number of iterations. The loop counter is an {@code int} initialized from the
3776      * {@code iterations} handle evaluation result. The counter is passed to the {@code body} function, so that must
3777      * accept an initial {@code int} argument. The result of the loop execution is the final value of the additional
3778      * local state. This is a convenience wrapper for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop
3779      * combinator}.
3780      * <p>
3781      * The result type and parameter type list of {@code init} determine those of the resulting handle. The {@code
3782      * iterations} handle must accept the same parameter types as {@code init} but return an {@code int}. The {@code
3783      * body} handle must accept the same parameter types as well, preceded by an {@code int} parameter for the counter,
3784      * and a parameter of the same type as {@code init}'s result. These constraints follow directly from those described
3785      * for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
3786      * <p>
3787      * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
3788      * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
3789      * passed to the loop.


3884      *     return loop(indexVar, loopLimit, bodyClause);
3885      * }
3886      * }</pre></blockquote>
3887      *
3888      * @param start a handle to return the start value of the loop counter.
3889      *              If it is {@code null}, a constant zero is assumed.
3890      * @param end a non-{@code null} handle to return the end value of the loop counter (the loop will run to {@code end-1}).
3891      * @param init initializer for additional loop state. This determines the loop's result type.
3892      *             Passing {@code null} or a {@code void} init function will make the loop's result type
3893      *             {@code void}.
3894      * @param body the body of the loop, which must not be {@code null}.
3895      *             It must accept an initial {@code int} parameter (for the counter), and then any
3896      *             additional loop-local variable plus loop parameters.
3897      *
3898      * @return a method handle representing the loop.
3899      * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
3900      *
3901      * @since 9
3902      */
3903     public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
3904         MethodHandle returnVar = dropArguments(init == null ? zero(void.class) : identity(init.type().returnType()),
3905                 0, int.class, int.class);
3906         MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)};
3907         MethodHandle[] loopLimit = {end, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), returnVar};
3908         MethodHandle[] bodyClause = {init, dropArguments(body, 1, int.class)};
3909         return loop(indexVar, loopLimit, bodyClause);
3910     }
3911 
3912     /**
3913      * Constructs a loop that ranges over the elements produced by an {@code Iterator<T>}.
3914      * The iterator will be produced by the evaluation of the {@code iterator} handle.
3915      * If this handle is passed as {@code null} the method {@link Iterable#iterator} will be used instead,
3916      * and will be applied to a leading argument of the loop handle.
3917      * Each value produced by the iterator is passed to the {@code body}, which must accept an initial {@code T} parameter.
3918      * The result of the loop execution is the final value of the additional local state
3919      * obtained by running {@code init}.
3920      * <p>
3921      * This is a convenience wrapper for the
3922      * {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}, and the constraints imposed on the {@code body}
3923      * handle follow directly from those described for the latter.
3924      * <p>


3985      * @param body the body of the loop, which must not be {@code null}.
3986      *             It must accept an initial {@code T} parameter (for the iterated values), and then any
3987      *             additional loop-local variable plus loop parameters.
3988      *
3989      * @return a method handle embodying the iteration loop functionality.
3990      * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
3991      *
3992      * @since 9
3993      */
3994     public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
3995         checkIteratedLoop(body);
3996 
3997         MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator);
3998         MethodHandle initIterator = iterator == null ?
3999                 initit.asType(initit.type().changeParameterType(0, body.type().parameterType(init == null ? 1 : 2))) :
4000                 iterator;
4001         Class<?> itype = initIterator.type().returnType();
4002         Class<?> ttype = body.type().parameterType(0);
4003 
4004         MethodHandle returnVar =
4005                 dropArguments(init == null ? zero(void.class) : identity(init.type().returnType()), 0, itype);
4006         MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext);
4007         MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype));
4008 
4009         MethodHandle[] iterVar = {initIterator, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred), returnVar};
4010         MethodHandle[] bodyClause = {init, filterArgument(body, 0, nextVal)};
4011 
4012         return loop(iterVar, bodyClause);
4013     }
4014 
4015     /**
4016      * Makes a method handle that adapts a {@code target} method handle by wrapping it in a {@code try-finally} block.
4017      * Another method handle, {@code cleanup}, represents the functionality of the {@code finally} block. Any exception
4018      * thrown during the execution of the {@code target} handle will be passed to the {@code cleanup} handle. The
4019      * exception will be rethrown, unless {@code cleanup} handle throws an exception first.  The
4020      * value returned from the {@code cleanup} handle's execution will be the result of the execution of the
4021      * {@code try-finally} handle.
4022      * <p>
4023      * The {@code cleanup} handle will be passed one or two additional leading arguments.
4024      * The first is the exception thrown during the
4025      * execution of the {@code target} handle, or {@code null} if no exception was thrown.


4079      * @param cleanup the handle that is invoked in the finally block.
4080      *
4081      * @return a method handle embodying the {@code try-finally} block composed of the two arguments.
4082      * @throws NullPointerException if any argument is null
4083      * @throws IllegalArgumentException if {@code cleanup} does not accept
4084      *          the required leading arguments, or if the method handle types do
4085      *          not match in their return types and their
4086      *          corresponding trailing parameters
4087      *
4088      * @see MethodHandles#catchException(MethodHandle, Class, MethodHandle)
4089      * @since 9
4090      */
4091     public static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup) {
4092         List<Class<?>> targetParamTypes = target.type().parameterList();
4093         List<Class<?>> cleanupParamTypes = cleanup.type().parameterList();
4094         Class<?> rtype = target.type().returnType();
4095 
4096         checkTryFinally(target, cleanup);
4097 
4098         // Match parameter lists: if the cleanup has a shorter parameter list than the target, add ignored arguments.
4099         // The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
4100         // target parameter list.
4101         cleanup = dropArgumentsToMatch(cleanup, (rtype == void.class ? 1 : 2), targetParamTypes, 0);




4102         MethodHandle aTarget = target.asSpreader(Object[].class, target.type().parameterCount());
4103         MethodHandle aCleanup = cleanup.asSpreader(Object[].class, targetParamTypes.size());
4104 
4105         return MethodHandleImpl.makeTryFinally(aTarget, aCleanup, rtype, targetParamTypes);
4106     }
4107 
4108     /**
4109      * Adapts a target method handle by pre-processing some of its arguments, starting at a given position, and then
4110      * calling the target with the result of the pre-processing, inserted into the original sequence of arguments just
4111      * before the folded arguments.
4112      * <p>
4113      * This method is closely related to {@link #foldArguments(MethodHandle, MethodHandle)}, but allows to control the
4114      * position in the parameter list at which folding takes place. The argument controlling this, {@code pos}, is a
4115      * zero-based index. The aforementioned method {@link #foldArguments(MethodHandle, MethodHandle)} assumes position
4116      * 0.
4117      * <p>
4118      * @apiNote Example:
4119      * <blockquote><pre>{@code
4120     import static java.lang.invoke.MethodHandles.*;
4121     import static java.lang.invoke.MethodType.*;
4122     ...
4123     MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,


4174      *          are not identical with the argument types of {@code combiner}
4175      *
4176      * @see #foldArguments(MethodHandle, MethodHandle)
4177      * @since 9
4178      */
4179     public static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner) {
4180         MethodType targetType = target.type();
4181         MethodType combinerType = combiner.type();
4182         Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType);
4183         BoundMethodHandle result = target.rebind();
4184         boolean dropResult = rtype == void.class;
4185         LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType());
4186         MethodType newType = targetType;
4187         if (!dropResult) {
4188             newType = newType.dropParameterTypes(pos, pos + 1);
4189         }
4190         result = result.copyWithExtendL(newType, lform, combiner);
4191         return result;
4192     }
4193 










4194 
4195     private static void checkLoop0(MethodHandle[][] clauses) {
4196         if (clauses == null || clauses.length == 0) {
4197             throw newIllegalArgumentException("null or no clauses passed");
4198         }
4199         if (Stream.of(clauses).anyMatch(Objects::isNull)) {
4200             throw newIllegalArgumentException("null clauses are not allowed");
4201         }
4202         if (Stream.of(clauses).anyMatch(c -> c.length > 4)) {
4203             throw newIllegalArgumentException("All loop clauses must be represented as MethodHandle arrays with at most 4 elements.");
4204         }
4205     }
4206 
4207     private static void checkLoop1a(int i, MethodHandle in, MethodHandle st) {
4208         if (in.type().returnType() != st.type().returnType()) {
4209             throw misMatchedTypes("clause " + i + ": init and step return types", in.type().returnType(),
4210                     st.type().returnType());
4211         }
4212     }
4213 


< prev index next >