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
|