static MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) { filterArgumentChecks(target, pos, filter); MethodType targetType = target.type(); MethodType filterType = filter.type(); BoundMethodHandle result = target.rebind(); Class<?> newParamType = filterType.parameterType(0); LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType)); MethodType newType = targetType.changeParameterType(pos, newParamType); result = result.copyWithExtendL(newType, lform, filter); return result; }
private static MethodHandle dropArguments0(MethodHandle target, int pos, List<Class<?>> valueTypes) { MethodType oldType = target.type(); // get NPE int dropped = dropArgumentChecks(oldType, pos, valueTypes); MethodType newType = oldType.insertParameterTypes(pos, valueTypes); if (dropped == 0) return target; BoundMethodHandle result = target.rebind(); LambdaForm lform = result.form; int insertFormArg = 1 + pos; for (Class<?> ptype : valueTypes) { lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype)); } result = result.copyWith(newType, lform); return result; }
private static MethodHandle makeIdentity(Class<?> ptype) { MethodType mtype = MethodType.methodType(ptype, ptype); LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype)); return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY); }
private static MethodHandle makeZero(Class<?> rtype) { MethodType mtype = MethodType.methodType(rtype); LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype)); return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO); }
/** * Produces a method handle which will discard some dummy arguments * before calling some other specified <i>target</i> method handle. * The type of the new method handle will be the same as the target's type, * except it will also include the dummy argument types, * at some given position. * <p> * The {@code pos} argument may range between zero and <i>N</i>, * where <i>N</i> is the arity of the target. * If {@code pos} is zero, the dummy arguments will precede * the target's real arguments; if {@code pos} is <i>N</i> * they will come after. * <p> * <b>Example:</b> * <blockquote><pre>{@code import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); assertEquals("xy", (String) cat.invokeExact("x", "y")); MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class); MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2)); assertEquals(bigType, d0.type()); assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z")); * }</pre></blockquote> * <p> * This method is also equivalent to the following code: * <blockquote><pre> * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}{@code (target, pos, valueTypes.toArray(new Class[0]))} * </pre></blockquote> * @param target the method handle to invoke after the arguments are dropped * @param valueTypes the type(s) of the argument(s) to drop * @param pos position of first argument to drop (zero for the leftmost) * @return a method handle which drops arguments of the given types, * before calling the original method handle * @throws NullPointerException if the target is null, * or if the {@code valueTypes} list or any of its elements is null * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class}, * or if {@code pos} is negative or greater than the arity of the target, * or if the new method handle's type would have too many parameters */ public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) { MethodType oldType = target.type(); // get NPE int dropped = dropArgumentChecks(oldType, pos, valueTypes); MethodType newType = oldType.insertParameterTypes(pos, valueTypes); if (dropped == 0) return target; BoundMethodHandle result = target.rebind(); LambdaForm lform = result.form; int insertFormArg = 1 + pos; for (Class<?> ptype : valueTypes) { lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype)); } result = result.copyWith(newType, lform); return result; }
/** * Produces a method handle which will discard some dummy arguments * before calling some other specified <i>target</i> method handle. * The type of the new method handle will be the same as the target's type, * except it will also include the dummy argument types, * at some given position. * <p> * The {@code pos} argument may range between zero and <i>N</i>, * where <i>N</i> is the arity of the target. * If {@code pos} is zero, the dummy arguments will precede * the target's real arguments; if {@code pos} is <i>N</i> * they will come after. * <p> * <b>Example:</b> * <blockquote><pre>{@code import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); assertEquals("xy", (String) cat.invokeExact("x", "y")); MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class); MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2)); assertEquals(bigType, d0.type()); assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z")); * }</pre></blockquote> * <p> * This method is also equivalent to the following code: * <blockquote><pre> * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}{@code (target, pos, valueTypes.toArray(new Class[0]))} * </pre></blockquote> * @param target the method handle to invoke after the arguments are dropped * @param valueTypes the type(s) of the argument(s) to drop * @param pos position of first argument to drop (zero for the leftmost) * @return a method handle which drops arguments of the given types, * before calling the original method handle * @throws NullPointerException if the target is null, * or if the {@code valueTypes} list or any of its elements is null * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class}, * or if {@code pos} is negative or greater than the arity of the target, * or if the new method handle's type would have too many parameters */ public static MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) { valueTypes = copyTypes(valueTypes); MethodType oldType = target.type(); // get NPE int dropped = dropArgumentChecks(oldType, pos, valueTypes); MethodType newType = oldType.insertParameterTypes(pos, valueTypes); if (dropped == 0) return target; BoundMethodHandle result = target.rebind(); LambdaForm lform = result.form; int insertFormArg = 1 + pos; for (Class<?> ptype : valueTypes) { lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype)); } result = result.copyWith(newType, lform); return result; }
private static MethodHandle makeIdentity(Class<?> ptype) { MethodType mtype = methodType(ptype, ptype); LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype)); return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY); }
private static MethodHandle makeZero(Class<?> rtype) { MethodType mtype = methodType(rtype); LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype)); return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO); }
/** * Adapts a target method handle by post-processing * its return value (if any) with a filter (another method handle). * The result of the filter is returned from the adapter. * <p> * If the target returns a value, the filter must accept that value as * its only argument. * If the target returns void, the filter must accept no arguments. * <p> * The return type of the filter * replaces the return type of the target * in the resulting adapted method handle. * The argument type of the filter (if any) must be identical to the * return type of the target. * <p><b>Example:</b> * <blockquote><pre>{@code import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodHandle length = lookup().findVirtual(String.class, "length", methodType(int.class)); System.out.println((String) cat.invokeExact("x", "y")); // xy MethodHandle f0 = filterReturnValue(cat, length); System.out.println((int) f0.invokeExact("x", "y")); // 2 * }</pre></blockquote> * <p> Here is pseudocode for the resulting adapter: * <blockquote><pre>{@code * V target(A...); * T filter(V); * T adapter(A... a) { * V v = target(a...); * return filter(v); * } * // and if the target has a void return: * void target2(A...); * T filter2(); * T adapter2(A... a) { * target2(a...); * return filter2(); * } * // and if the filter has a void return: * V target3(A...); * void filter3(V); * void adapter3(A... a) { * V v = target3(a...); * filter3(v); * } * }</pre></blockquote> * @param target the method handle to invoke before filtering the return value * @param filter method handle to call on the return value * @return method handle which incorporates the specified return value filtering logic * @throws NullPointerException if either argument is null * @throws IllegalArgumentException if the argument list of {@code filter} * does not match the return type of target as described above */ public static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) { MethodType targetType = target.type(); MethodType filterType = filter.type(); filterReturnValueChecks(targetType, filterType); BoundMethodHandle result = target.rebind(); BasicType rtype = BasicType.basicType(filterType.returnType()); LambdaForm lform = result.editor().filterReturnForm(rtype, false); MethodType newType = targetType.changeReturnType(filterType.returnType()); result = result.copyWithExtendL(newType, lform, filter); return result; }
/** * Adapts a target method handle by post-processing * its return value (if any) with a filter (another method handle). * The result of the filter is returned from the adapter. * <p> * If the target returns a value, the filter must accept that value as * its only argument. * If the target returns void, the filter must accept no arguments. * <p> * The return type of the filter * replaces the return type of the target * in the resulting adapted method handle. * The argument type of the filter (if any) must be identical to the * return type of the target. * <p><b>Example:</b> * <blockquote><pre>{@code import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; ... MethodHandle cat = lookup().findVirtual(String.class, "concat", methodType(String.class, String.class)); MethodHandle length = lookup().findVirtual(String.class, "length", methodType(int.class)); System.out.println((String) cat.invokeExact("x", "y")); // xy MethodHandle f0 = filterReturnValue(cat, length); System.out.println((int) f0.invokeExact("x", "y")); // 2 * }</pre></blockquote> * <p>Here is pseudocode for the resulting adapter. In the code, * {@code T}/{@code t} represent the result type and value of the * {@code target}; {@code V}, the result type of the {@code filter}; and * {@code A}/{@code a}, the types and values of the parameters and arguments * of the {@code target} as well as the resulting adapter. * <blockquote><pre>{@code * T target(A...); * V filter(T); * V adapter(A... a) { * T t = target(a...); * return filter(t); * } * // and if the target has a void return: * void target2(A...); * V filter2(); * V adapter2(A... a) { * target2(a...); * return filter2(); * } * // and if the filter has a void return: * T target3(A...); * void filter3(V); * void adapter3(A... a) { * T t = target3(a...); * filter3(t); * } * }</pre></blockquote> * <p> * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector * variable-arity method handle}, even if the original target method handle was. * @param target the method handle to invoke before filtering the return value * @param filter method handle to call on the return value * @return method handle which incorporates the specified return value filtering logic * @throws NullPointerException if either argument is null * @throws IllegalArgumentException if the argument list of {@code filter} * does not match the return type of target as described above */ public static MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) { MethodType targetType = target.type(); MethodType filterType = filter.type(); filterReturnValueChecks(targetType, filterType); BoundMethodHandle result = target.rebind(); BasicType rtype = BasicType.basicType(filterType.returnType()); LambdaForm lform = result.editor().filterReturnForm(rtype, false); MethodType newType = targetType.changeReturnType(filterType.returnType()); result = result.copyWithExtendL(newType, lform, filter); return result; }