--- old/src/java.base/share/classes/java/lang/invoke/BootstrapCallInfo.java 2018-09-28 11:54:20.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/invoke/BootstrapCallInfo.java 2018-09-28 11:54:20.000000000 -0700 @@ -25,14 +25,22 @@ package java.lang.invoke; +import java.lang.constant.Constable; +import java.lang.constant.ConstantDesc; +import java.lang.invoke.AbstractBootstrapCallInfo.*; import java.lang.invoke.MethodHandles.Lookup; +import java.util.List; +import java.util.Objects; +import sun.invoke.util.Wrapper; + +import static java.lang.invoke.BootstrapMethodInvoker.invokeCommon; /** * An interface providing full static information about a particular * call to a * bootstrap method of an * dynamic call site or dynamic constant. - * This information includes the method itself, the associated + * This information includes the bootstrap method itself, the associated * name and type, and any associated static arguments. *

* If a bootstrap method declares exactly two arguments, and is @@ -72,40 +80,21 @@ args.add(lookup); args.add(bsci.invocationName()); args.add(bsci.invocationType()); - MethodHandle bsm = (MethodHandle) bsci.get(0); - List restOfArgs = bsci.asList().subList(1, bsci.size(); + MethodHandle bsm = (MethodHandle) bsci.argument(0); + List restOfArgs = bsci.argumentList().subList(1, bsci.argumentCount()); // the next line eagerly resolves all remaining static arguments: args.addAll(restOfArgs); return bsm.invokeWithArguments(args); } * } * - *

- * In the other direction, here is a combinator which pops - * a pull-mode bootstrap method from the beginning of a list of - * static argument values (already resolved), reformats all of - * the arguments into a pair of a lookup and a {@code BootstrapCallInfo}, - * and invokes the popped method. Again the callee has no way of - * telling it was not called directly by the JVM, except that - * all of the constant values will appear as resolved. - * Put another way, if any constant fails to resolve, the - * callee will not be able to catch the resulting error, - * since the error will be thrown by the JVM before the - * bootstrap method is entered. - *

{@code
-static Object genericBSM(Lookup lookup, String name, Object type,
-                         MethodHandle bsm, Object... args)
-    throws Throwable {
-  ConstantGroup cons = ConstantGroup.makeConstantGroup(Arrays.asList(args));
-  BootstrapCallInfo bsci = makeBootstrapCallInfo(bsm, name, type, cons);
-  return bsm.invoke(lookup, bsci);
-}
- * }
+ * @param  the type {@code MethodType} or {@code Class}
  *
- * @since 1.10
+ * @since 12
  */
 // public
-interface BootstrapCallInfo extends ConstantGroup {
+interface BootstrapCallInfo> {
+
     /** Returns the bootstrap method for this call.
      * @return the bootstrap method
      */
@@ -121,22 +110,342 @@
      */
     T invocationType();
 
+    /** Returns a ConstantDesc for the method type or constant type for this call.
+     * Does not (by itself) trigger resolution of this type.
+     * @return the method type or constant type
+     */
+    ConstantDesc invocationTypeDesc();
+
+    /**
+     * Returns the number of static arguments.
+     * @return the number of static arguments
+     */
+    int argumentCount();
+
+    /**
+     * 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 argument(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 may be returned, at the implementation's discretion.
+     * To force resolution (and a possible exception), call {@link #argument(int)}.
+     * @param index which static argument to select
+     * @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
+     */
+    default Object argument(int index, Object ifNotPresent) {
+        if (argumentIsPresent(index))  return argument(index);
+        return ifNotPresent;
+    }
+
+    /**
+     * Returns a symbolic reference underlying the selected static argument,
+     * if it is available.
+     * @param index which static argument to select
+     * @return a symbolic reference underlying the selected static argument
+     * @throws IllegalArgumentException if the original symbolic reference is not available,
+     * and a substitute cannot be created on the fly by {@link ConstantDesc}.
+     */
+    ConstantDesc argumentDesc(int index);
+
+    /**
+     * 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 #argument(int)} will never throw an exception.
+     * 

+ * After a normal return from {@link #argument(int)} or a present + * value is reported from {@link #argument(int,Object)}, this method + * must always return true. + *

+ * 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 #argument(int)} and + * be ready for an exception if the constant is unavailable. + * @param index which constant to select + * @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 argumentIsPresent(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, and may therefore cause a {@code LinkageError}. + * @return a {@code List} view on the static arguments which will force resolution + */ + default List argumentList() { + return new ArgList(this, 0, argumentCount()); + } + + /** + * Create a view on the static arguments 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 #argument(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 argumentList(Object ifNotPresent) { + return new ArgList(this, 0, argumentCount(), ifNotPresent); + } + + /** + * Create a view on the symbolic references of the static arguments as a {@link List} view. + * @return a {@code List} view on this group's symbolic references + */ + default List> argumentDescList() { + List syms = new ArgList(this, true, 0, argumentCount()); + @SuppressWarnings({"unchecked", "rawtypes"}) + List> result = (List) syms; + return result; + } + + /// Factories and helper methods + + /** + * 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}. + *

+ * @apiNote + * This method behaves like the following but may be more optimal: + *

{@code
+     *   ArrayList args = new ArrayList<>();
+     *   args.add(lookup);
+     *   args.add(name);
+     *   args.add(type);
+     *   args.addAll(staticArgs);
+     *   return handle.invokeWithArguments(args);
+     * }
+     *
+     * @param handle the bootstrap method handle to be invoked on the static arguments
+     * @param lookup the lookup
+     * @param name the name associated with the constant or call site being linked
+     * @param type the type associated with the constant or call site being linked
+     * @param staticArgs the static argument list
+     * @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
+     */
+    static Object invokeWithMetadata(MethodHandle handle,
+                                     MethodHandles.Lookup lookup,
+                                     String name,
+                                     TypeDescriptor type,
+                                     List staticArgs)
+            throws Throwable {
+        Objects.requireNonNull(lookup);
+        return invokeCommon(handle, lookup, name, type, null, staticArgs);
+    }
+
     /**
-     * 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  the type of the invocation type, either {@link MethodHandle} or {@link Class}
-     * @return a new bootstrap call descriptor with the given components
-     */
-    static  BootstrapCallInfo makeBootstrapCallInfo(MethodHandle bsm,
-                                                          String name,
-                                                          T type,
-                                                          ConstantGroup constants) {
-        AbstractConstantGroup.BSCIWithCache bsci = new AbstractConstantGroup.BSCIWithCache<>(bsm, name, type, constants.size());
-        final Object NP = AbstractConstantGroup.BSCIWithCache.NOT_PRESENT;
-        bsci.initializeCache(constants.asList(NP), 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}.
+     * 

+ * @apiNote + * This method behaves like the following but may be more optimal: + *

{@code
+     *   ArrayList args = new ArrayList<>();
+     *   args.add(lookup);
+     *   args.add(name);
+     *   args.add(type);
+     *   args.addAll(Arrays.asList(staticArgs));
+     *   return handle.invokeWithArguments(args);
+     * }
+     *
+     * @param handle the bootstrap method handle to be invoked on the static arguments
+     * @param lookup the lookup
+     * @param name the name associated with the constant or call site being linked
+     * @param type the type associated with the constant or call site being linked
+     * @param staticArgs the static argument list
+     * @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
+     */
+    static Object invokeWithMetadata(MethodHandle handle,
+                                     MethodHandles.Lookup lookup,
+                                     String name,
+                                     TypeDescriptor type,
+                                     Object... staticArgs)
+            throws Throwable {
+        Objects.requireNonNull(lookup);
+        Objects.requireNonNull(staticArgs);
+        return invokeCommon(handle, lookup, name, type, staticArgs, null);
+    }
+
+    /**
+     * 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}.
+     * 

+ * @apiNote + * This method behaves like the following but may be more optimal: + *

{@code
+     *   ArrayList args = new ArrayList<>();
+     *   args.add(lookup);
+     *   args.add(bci.invocationName());
+     *   args.add(bci.invocationType());
+     *   args.addAll(bci.argumentList());
+     *   return handle.invokeWithArguments(args);
+     * }
+     *
+     * @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
+     */
+    static Object invokeWithMetadata(MethodHandle handle,
+                                     MethodHandles.Lookup lookup,
+                                     BootstrapCallInfo bsci)
+            throws Throwable {
+        Objects.requireNonNull(lookup);
+        return invokeCommon(handle, lookup, bsci.invocationName(), bsci.invocationType(), AbstractBootstrapCallInfo.maybeShareArguments(bsci), bsci.argumentList());
+    }
+
+    /**
+     * Convert the result returned by a bootstrap method to the class
+     * required by the bootstrap method's {@code invocationType}.
+     *
+     * @param bsci the bootstrap call descriptor
+     * @param result the result to be converted
+     * @param  the type {@code MethodType} or {@code Class}
+     * @return the converted result
+     * @throws ClassCastException if a value conversion error occurs during conversion
+     * @throws WrongMethodTypeException if a method type mismatch is detected occurs during conversion
+     */
+    static
+    >
+    Object convertResult(BootstrapCallInfo bsci, Object result) {
+        // FIXME:  If invocationType cannot be resolved, some results are still valid.
+        return convertResult(bsci.invocationType(), bsci.bootstrapMethod().type().returnType(), result);
+    }
+
+    /**
+     * Convert the result returned by a bootstrap method to the class
+     * required by the bootstrap method's {@code invocationType}.
+     *
+     * @param type the method type or constant type to be obtained
+     * @param resultType the type of the result (return type of the BSM that returned the result)
+     * @param result the result to be converted
+     * @param  the type {@code MethodType} or {@code Class}
+     * @return the converted result
+     * @throws ClassCastException if a value conversion error occurs during conversion
+     * @throws WrongMethodTypeException if a method type mismatch is detected occurs during conversion
+     */
+    static
+    >
+    Object convertResult(T type, Class resultType, Object result) {
+        Class resultClass;
+        boolean isFieldType;
+        if (type instanceof Class) {
+            isFieldType = true;
+            resultClass = (Class) type;
+        } else {
+            isFieldType = false;
+            resultClass = null;
+        }
+        if (isFieldType && resultClass.isPrimitive()) {
+            Class wrapperClass = Wrapper.asWrapperType(resultClass);
+            if (result.getClass() == wrapperClass) {
+                return result;  // fast path
+            }
+            // Non-reference conversions are more than just plain casts.
+            // By pushing the value through a funnel of the form (R x)->x,
+            // the boxed result can be widened as needed.  See MH::asType.
+            MethodHandle funnel = MethodHandles.identity(resultClass);
+            if (!MethodType.canConvert(resultType, resultClass)) {
+                // Example:  Result type is Integer and resultClass is short.
+                funnel = funnel.asType(MethodType.methodType(resultClass, resultType));
+                assert(false);  // should have thrown WMTE
+            }
+            try {
+                result = funnel.invoke(result);
+            } catch (ClassCastException | WrongMethodTypeException ex) {
+                throw ex;
+            } catch (Throwable ex) {
+                throw new InternalError(ex);
+            }
+            // Now it is the wrapper type for resultType.
+            assert(result.getClass() == Wrapper.asWrapperType(resultClass));
+            return result;
+        } else if (isFieldType) {
+            // A reference type.
+            return resultClass.cast(result);
+        } else {
+            // Check or convert the method-like result.
+            MethodType mt = (MethodType) type;  // must be either Class or MethodType
+            if (result instanceof CallSite) {
+                CallSite cs = (CallSite) result;
+                if (!cs.type().equals(mt))
+                    throw CallSite.wrongTargetType(cs, mt);
+                return cs;  // no conversion, just checking
+            }
+            if (result instanceof MethodHandle) {
+                // Method handles can be converted on the fly:
+                MethodHandle mh = (MethodHandle) result;
+                return mh.asType(mt);
+            }
+            throw new ClassCastException("CallSite bootstrap method failed to produce an instance of CallSite");
+        }
+    }
+
+    /**
+     * Produce a string that briefly reports the BSM, name, type,
+     * and argument list.  For arguments, use a non-resolving list view,
+     * with unresolved elements being presented as asterisks.
+     * @param bsci the object to produce a string for
+     * @return {@code this.asList("*").toString()}
+     */
+    public static String toString(BootstrapCallInfo bsci) {
+        MethodHandle bsm = bsci.bootstrapMethod();
+        MemberName mem = bsm.internalMemberName();
+        Object bsmStr = bsm;
+        if (mem != null)  bsmStr = mem;
+        //bsmStr = bsm.describeConstable()
+        Object typeStr = null;
+        try {
+            typeStr = bsci.invocationType();
+        } catch (LinkageError ex) {
+            typeStr = bsci.invocationTypeDesc();
+        }
+        return (bsmStr
+                + "/" + bsci.invocationName()
+                + ":" + typeStr
+                + bsci.argumentList("*"));
     }
 }