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);
             }