OpenJDK / amber / amber
changeset 49299:8bb5ff495383 condy-folding
Expose adapter methods for adapting calls between bootstream method
handles accepting a sequence of arguments and a bootstrap call
descriptor or vice-versa.
author | psandoz |
---|---|
date | Tue, 20 Feb 2018 17:56:39 -0800 |
parents | 2543b2c202b9 |
children | b3678924a994 |
files | src/java.base/share/classes/java/lang/invoke/BootstrapCallInfo.java src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java |
diffstat | 2 files changed, 136 insertions(+), 68 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/invoke/BootstrapCallInfo.java Fri Feb 16 16:31:21 2018 -0500 +++ b/src/java.base/share/classes/java/lang/invoke/BootstrapCallInfo.java Tue Feb 20 17:56:39 2018 -0800 @@ -26,6 +26,7 @@ package java.lang.invoke; import java.lang.invoke.MethodHandles.Lookup; +import java.util.Arrays; /** * An interface providing full static information about a particular @@ -73,7 +74,7 @@ args.add(bsci.invocationName()); args.add(bsci.invocationType()); MethodHandle bsm = (MethodHandle) bsci.get(0); - List<Object> restOfArgs = bsci.asList().subList(1, bsci.size(); + List<Object> restOfArgs = bsci.asList().subList(1, bsci.size()); // the next line eagerly resolves all remaining static arguments: args.addAll(restOfArgs); return bsm.invokeWithArguments(args); @@ -96,8 +97,7 @@ static Object genericBSM(Lookup lookup, String name, Object type, MethodHandle bsm, Object... args) throws Throwable { - ConstantGroup cons = ConstantGroup.makeConstantGroup(Arrays.asList(args)); - BootstrapCallInfo<Object> bsci = makeBootstrapCallInfo(bsm, name, type, cons); + BootstrapCallInfo<Object> bsci = makeBootstrapCallInfo(bsm, name, type, args); return bsm.invoke(lookup, bsci); } * }</pre></blockquote> @@ -139,4 +139,132 @@ bsci.initializeCache(constants.asList(NP), NP); return bsci; } -} + + /** + * Make a new bootstrap call descriptor with the given components. + * @param bsm bootstrap method + * @param name invocation name + * @param type invocation type + * @param constants the additional static arguments for the bootstrap method + * @param <T> the type of the invocation type, either {@link MethodHandle} or {@link Class} + * @return a new bootstrap call descriptor with the given components + */ + static <T> BootstrapCallInfo<T> makeBootstrapCallInfo(MethodHandle bsm, + String name, + T type, + Object... constants) { + AbstractConstantGroup.BSCIWithCache<T> bsci = new AbstractConstantGroup.BSCIWithCache<>(bsm, name, type, constants.length); + final Object NP = AbstractConstantGroup.BSCIWithCache.NOT_PRESENT; + bsci.initializeCache(Arrays.asList(constants), NP); + return bsci; + } + + /** + * Invoke a bootstrap method handle with arguments obtained by resolving + * the sequence of constants supplied by a given bootstrap call descriptor, + * {@code bci}. + * The first argument to the method will be {@code lookup}. + * The second argument will be the invocation name of {@code bci}. + * The third argument will be the invocation type of {@code bci}. + * The fourth and subsequent arguments (if any) will be the resolved + * constants, in order, supplied by {@code bci}. + * <p> + * @apiNote + * This method behaves like the following but may be more optimal: + * <blockquote><pre>{@code + * ArrayList<Object> args = new ArrayList<>(); + * args.add(lookup); + * args.add(bsci.invocationName()); + * args.add(bsci.invocationType()); + * List<Object> constantArgs = bsci.asList(); + * args.addAll(constantArgs); + * return handle.invokeWithArguments(args); + * }</pre></blockquote> + * + * @param handle the bootstrap method handle to be invoked with resolved + * constants supplied by {@code bci} + * @param lookup the lookup + * @param bsci the bootstrap call descriptor + * @return the result of invocation + * @throws Throwable if an error occurs when resolving the constants from + * the bootstrap call descriptor or invoking the method handle + */ + // @@@ More stuff to add as api note + // This method is static so that it's possible to look it up and bind + // to a method handle, thereby viewing that method handle as if accepts + // a BootstrapCallInfo + static Object invokeFromCallInfoToArguments(MethodHandle handle, + MethodHandles.Lookup lookup, + BootstrapCallInfo<?> bsci) throws Throwable { + int argc = bsci.size(); + switch (argc) { + case 0: + return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType()); + case 1: + return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(), + bsci.get(0)); + case 2: + return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(), + bsci.get(0), bsci.get(1)); + case 3: + return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(), + bsci.get(0), bsci.get(1), bsci.get(2)); + case 4: + return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(), + bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3)); + case 5: + return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(), + bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4)); + case 6: + return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(), + bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4), bsci.get(5)); + default: + final int NON_SPREAD_ARG_COUNT = 3; // (lookup, name, type) + final int MAX_SAFE_SIZE = MethodType.MAX_MH_ARITY / 2 - NON_SPREAD_ARG_COUNT; + if (argc >= MAX_SAFE_SIZE) { + // to be on the safe side, use invokeWithArguments which handles jumbo lists + Object[] newargv = new Object[NON_SPREAD_ARG_COUNT + argc]; + newargv[0] = lookup; + newargv[1] = bsci.invocationName(); + newargv[2] = bsci.invocationType(); + bsci.copyConstants(0, argc, newargv, NON_SPREAD_ARG_COUNT); + return handle.invokeWithArguments(newargv); + } + MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argc); + MethodHandle typedBSM = handle.asType(invocationType); + MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT); + Object[] argv = new Object[argc]; + bsci.copyConstants(0, argc, argv, 0); + return spreader.invokeExact(typedBSM, (Object) lookup, (Object) bsci.invocationName(), bsci.invocationType(), argv); + } + } + + /** + * Invoke a bootstrap method handle with a bootstrap call descriptor + * argument composed from a given sequence of arguments. + * <p> + * @apiNote + * This method behaves like the following but may be more optimal: + * <blockquote><pre>{@code + * BootstrapCallInfo<Object> bsci = makeBootstrapCallInfo(handle, name, type, args); + * return handle.invoke(lookup, bsci); + * }</pre></blockquote> + * + * @param handle the bootstrap method handle to be invoked with a bootstrap + * call descriptor composed from the sequence of arguments + * @param lookup the lookup + * @param name the method name or constant name + * @param type the method type or constant type + * @param args the sequence of arguments + * @return the result of invocation + * @throws Throwable if an error occurs when invoking the method handle + */ + static Object invokeFromArgumentsToCallInfo(MethodHandle handle, + MethodHandles.Lookup lookup, + String name, + Object type, + Object... args) throws Throwable { + BootstrapCallInfo<?> bsci = makeBootstrapCallInfo(handle, name, type, args); + return handle.invoke(lookup, bsci); + } +} \ No newline at end of file
--- a/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java Fri Feb 16 16:31:21 2018 -0500 +++ b/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java Tue Feb 20 17:56:39 2018 -0800 @@ -304,23 +304,12 @@ /*non-public*/ static final class PushAdapter { - // skeleton for push-mode BSM which wraps a pull-mode BSM: - static Object pushToBootstrapMethod(MethodHandle pullModeBSM, - MethodHandles.Lookup lookup, String name, Object type, - Object... arguments) throws Throwable { - ConstantGroup cons = makeConstantGroup(Arrays.asList(arguments)); - BootstrapCallInfo<?> bsci = makeBootstrapCallInfo(pullModeBSM, name, type, cons); - if (TRACE_METHOD_LINKAGE) - System.out.println("pull-mode BSM gets pushed arguments from fake BSCI"); - return pullModeBSM.invoke(lookup, bsci); - } + static final MethodHandle MH_pushToBootstrapMethod; - static final MethodHandle MH_pushToBootstrapMethod; static { - final Class<?> THIS_CLASS = PushAdapter.class; try { MH_pushToBootstrapMethod = IMPL_LOOKUP - .findStatic(THIS_CLASS, "pushToBootstrapMethod", + .findStatic(BootstrapCallInfo.class, "invokeFromArgumentsToCallInfo", MethodType.methodType(Object.class, MethodHandle.class, Lookup.class, String.class, Object.class, Object[].class)); } catch (Throwable ex) { @@ -331,63 +320,14 @@ /*non-public*/ static final class PullAdapter { - // skeleton for pull-mode BSM which wraps a push-mode BSM: - static Object pullFromBootstrapMethod(MethodHandle pushModeBSM, - MethodHandles.Lookup lookup, - BootstrapCallInfo<?> bsci) - throws Throwable { - int argc = bsci.size(); - switch (argc) { - case 0: - return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType()); - case 1: - return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), - bsci.get(0)); - case 2: - return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), - bsci.get(0), bsci.get(1)); - case 3: - return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), - bsci.get(0), bsci.get(1), bsci.get(2)); - case 4: - return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), - bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3)); - case 5: - return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), - bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4)); - case 6: - return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), - bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4), bsci.get(5)); - default: - final int NON_SPREAD_ARG_COUNT = 3; // (lookup, name, type) - final int MAX_SAFE_SIZE = MethodType.MAX_MH_ARITY / 2 - NON_SPREAD_ARG_COUNT; - if (argc >= MAX_SAFE_SIZE) { - // to be on the safe side, use invokeWithArguments which handles jumbo lists - Object[] newargv = new Object[NON_SPREAD_ARG_COUNT + argc]; - newargv[0] = lookup; - newargv[1] = bsci.invocationName(); - newargv[2] = bsci.invocationType(); - bsci.copyConstants(0, argc, newargv, NON_SPREAD_ARG_COUNT); - return pushModeBSM.invokeWithArguments(newargv); - } - MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argc); - MethodHandle typedBSM = pushModeBSM.asType(invocationType); - MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT); - Object[] argv = new Object[argc]; - bsci.copyConstants(0, argc, argv, 0); - return spreader.invokeExact(typedBSM, (Object) lookup, (Object) bsci.invocationName(), bsci.invocationType(), argv); - } - } - static final MethodHandle MH_pullFromBootstrapMethod; static { - final Class<?> THIS_CLASS = PullAdapter.class; try { MH_pullFromBootstrapMethod = IMPL_LOOKUP - .findStatic(THIS_CLASS, "pullFromBootstrapMethod", + .findStatic(BootstrapCallInfo.class, "invokeFromCallInfoToArguments", MethodType.methodType(Object.class, MethodHandle.class, - Lookup.class, BootstrapCallInfo.class)); + Lookup.class, BootstrapCallInfo.class)); } catch (Throwable ex) { throw new InternalError(ex); }