< prev index next >

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

Print this page

        

@@ -24,10 +24,12 @@
  */
 
 package java.lang.invoke;
 
 import java.lang.invoke.MethodHandles.Lookup;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * An interface providing full static information about a particular
  * call to a
  * <a href="package-summary.html#bsm">bootstrap method</a> of an

@@ -71,11 +73,11 @@
   ArrayList<Object> args = new ArrayList<>();
   args.add(lookup);
   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);
 }
  * }</pre></blockquote>

@@ -94,20 +96,152 @@
  * bootstrap method is entered.
  * <blockquote><pre>{@code
 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>
  *
- * @since 1.10
+ * @since 11
  */
-// public
+public
 interface BootstrapCallInfo<T> extends ConstantGroup {
+
+    /// Access
+
+    /**
+     * Returns the number of static arguments.
+     * @return the number of static arguments
+     */
+    int size();
+
+    /**
+     * Returns the selected static argument, resolving it if necessary.
+     * Throws a linkage error if resolution proves impossible.
+     * @param index which static argument to select
+     * @return the selected static argument
+     * @throws LinkageError if the selected static argument needs resolution
+     * and cannot be resolved
+     */
+    Object get(int index) throws LinkageError;
+
+    /**
+     * Returns the selected static argument,
+     * or the given sentinel value if there is none available.
+     * If the static argument cannot be resolved, the sentinel will be returned.
+     * If the static argument can (perhaps) be resolved, but has not yet been resolved,
+     * then the sentinel <em>may</em> be returned, at the implementation's discretion.
+     * To force resolution (and a possible exception), call {@link #get(int)}.
+     * @param index the selected constant
+     * @param ifNotPresent the sentinel value to return if the static argument is not present
+     * @return the selected static argument, if available, else the sentinel value
+     */
+    Object get(int index, Object ifNotPresent);
+
+    /**
+     * Returns an indication of whether a static argument may be available.
+     * If it returns {@code true}, it will always return true in the future,
+     * and a call to {@link #get(int)} will never throw an exception.
+     * <p>
+     * After a normal return from {@link #get(int)} or a present
+     * value is reported from {@link #get(int,Object)}, this method
+     * must always return true.
+     * <p>
+     * If this method returns {@code false}, nothing in particular
+     * can be inferred, since the query only concerns the internal
+     * logic of the {@code BootstrapCallInfo} object which ensures that a
+     * successful query to a constant will always remain successful.
+     * The only way to force a permanent decision about whether
+     * a static argument is available is to call {@link #get(int)} and
+     * be ready for an exception if the constant is unavailable.
+     * @param index the selected constant
+     * @return {@code true} if the selected static argument is known by
+     *     this object to be present, {@code false} if it is known
+     *     not to be present or
+     */
+    boolean isPresent(int index);
+
+
+    /// Views
+
+    /**
+     * Create a view on the static arguments as a {@link List} view.
+     * Any request for a static argument through this view will
+     * force resolution.
+     * @return a {@code List} view on the static arguments which will force resolution
+     */
+    default List<Object> asList() {
+        return new AbstractConstantGroup.AsList(this, 0, size());
+    }
+
+    /**
+     * Create a view on the static argument as a {@link List} view.
+     * Any request for a static argument through this view will
+     * return the given sentinel value, if the corresponding
+     * call to {@link #get(int,Object)} would do so.
+     * @param ifNotPresent the sentinel value to return if a static argument is not present
+     * @return a {@code List} view on the static arguments which will not force resolution
+     */
+    default List<Object> asList(Object ifNotPresent) {
+        return new AbstractConstantGroup.AsList(this, 0, size(), ifNotPresent);
+    }
+
+
+    /// Bulk operations
+
+    /**
+     * Copy a sequence of static arguments into a given buffer.
+     * This is equivalent to {@code end-offset} separate calls to {@code get},
+     * for each index in the range from {@code offset} up to but not including {@code end}.
+     * For the first static argument that cannot be resolved,
+     * a {@code LinkageError} is thrown, but only after
+     * preceding static arguments have been stored.
+     * @param start index of first static argument to retrieve
+     * @param end limiting index of static arguments to retrieve
+     * @param buf array to receive the requested static arguments
+     * @param pos position in the array to offset storing the static arguments
+     * @return the limiting index, {@code end}
+     * @throws LinkageError if a static argument cannot be resolved
+     */
+    default int copyArguments(int start, int end,
+                              Object[] buf, int pos)
+            throws LinkageError
+    {
+        int bufBase = pos - start;  // buf[bufBase + i] = get(i)
+        for (int i = start; i < end; i++) {
+            buf[bufBase + i] = get(i);
+        }
+        return end;
+    }
+
+    /**
+     * Copy a sequence of static arguments into a given buffer.
+     * This is equivalent to {@code end-offset} separate calls to {@code get},
+     * for each index in the range from {@code offset} up to but not including {@code end}.
+     * Any static arguments that cannot be resolved are replaced by the
+     * given sentinel value.
+     * @param start index of first static argument to retrieve
+     * @param end limiting index of static arguments to retrieve
+     * @param buf array to receive the requested values
+     * @param pos position in the array to offset storing the static arguments
+     * @param ifNotPresent sentinel value to store if a static argument is not available
+     * @return the limiting index, {@code end}
+     * @throws LinkageError if {@code resolve} is true and a static argument cannot be resolved
+     */
+    default int copyConstants(int start, int end,
+                              Object[] buf, int pos,
+                              Object ifNotPresent) {
+        int bufBase = pos - start;  // buf[bufBase + i] = get(i)
+        for (int i = start; i < end; i++) {
+            buf[bufBase + i] = get(i, ifNotPresent);
+        }
+        return end;
+    }
+
+
     /** Returns the bootstrap method for this call.
      * @return the bootstrap method
      */
     MethodHandle bootstrapMethod();
 

@@ -124,19 +258,128 @@
     /**
      * 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 args 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,
-                                                          ConstantGroup constants) {
-        AbstractConstantGroup.BSCIWithCache<T> bsci = new AbstractConstantGroup.BSCIWithCache<>(bsm, name, type, constants.size());
+                                                          Object... args) {
+        AbstractConstantGroup.BSCIWithCache<T> bsci = new AbstractConstantGroup.BSCIWithCache<>(bsm, name, type, args.length);
         final Object NP = AbstractConstantGroup.BSCIWithCache.NOT_PRESENT;
-        bsci.initializeCache(constants.asList(NP), NP);
+        bsci.initializeCache(Arrays.asList(args), 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.copyArguments(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.copyArguments(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
< prev index next >