--- old/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java 2018-09-28 11:54:27.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java 2018-09-28 11:54:26.000000000 -0700 @@ -26,7 +26,13 @@ import sun.invoke.util.Wrapper; +import java.lang.constant.ConstantDesc; +import java.util.Arrays; + +import static java.lang.invoke.AbstractBootstrapCallInfo.maybeShareArguments; +import static java.lang.invoke.BootstrapMethodInvoker.invokeCommon; import static java.lang.invoke.MethodHandleNatives.mapLookupExceptionToError; +import static java.lang.invoke.MethodHandles.Lookup; import static java.util.Objects.requireNonNull; /** @@ -40,34 +46,6 @@ * @since 11 */ public final class ConstantBootstraps { - // implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant: - /*non-public*/ - static Object makeConstant(MethodHandle bootstrapMethod, - // Callee information: - String name, Class type, - // Extra arguments for BSM, if any: - Object info, - // Caller information: - Class callerClass) { - // Restrict bootstrap methods to those whose first parameter is Lookup - // The motivation here is, in the future, to possibly support BSMs - // that do not accept the meta-data of lookup/name/type, thereby - // allowing the co-opting of existing methods to be used as BSMs as - // long as the static arguments can be passed as method arguments - MethodType mt = bootstrapMethod.type(); - if (mt.parameterCount() < 2 || - !MethodHandles.Lookup.class.isAssignableFrom(mt.parameterType(0))) { - throw new BootstrapMethodError( - "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod); - } - - // BSMI.invoke handles all type checking and exception translation. - // If type is not a reference type, the JVM is expecting a boxed - // version, and will manage unboxing on the other side. - return BootstrapMethodInvoker.invoke( - type, bootstrapMethod, name, type, info, callerClass); - } - /** * Returns a {@code null} object reference for the reference type specified * by {@code type}. @@ -218,12 +196,12 @@ /** - * Returns the result of invoking a method handle with the provided - * arguments. + * Returns the result of invoking a bootstrap method handle on static + * arguments, but without metadata. *

* This method behaves as if the method handle to be invoked is the result * of adapting the given method handle, via {@link MethodHandle#asType}, to - * adjust the return type to the desired type. + * adjust the return type to {@code invocationType} of the bootstrap call. * * @param lookup unused * @param name unused @@ -247,14 +225,162 @@ requireNonNull(handle); requireNonNull(args); - if (type != handle.type().returnType()) { - // Adjust the return type of the handle to be invoked while - // preserving variable arity if present - handle = handle.asType(handle.type().changeReturnType(type)). - withVarargs(handle.isVarargsCollector()); + Object result = invokeCommon(handle, null, null, null, args, null); + return BootstrapCallInfo.convertResult(type, handle.type().returnType(), result); + } + + /** + * Returns the result of invoking a bootstrap method handle on static + * arguments, but without metadata. + *

+ * This method behaves as if the method handle to be invoked is the result + * of adapting the given method handle, via {@link MethodHandle#asType}, to + * adjust the return type to {@code invocationType} of the bootstrap call. + * + * @param lookup unused + * @param bsci the container of the bootstrap method + * @return the result of invoking the method handle + * @throws WrongMethodTypeException if the handle's method type cannot be + * adjusted to take the given number of arguments, or if the handle's return + * type cannot be adjusted to the desired type + * @throws ClassCastException if an argument or the result produced by + * invoking the handle cannot be converted by reference casting + * @throws Throwable anything thrown by the method handle invocation + */ + // not public until BootstrapCallInfo is public + static Object invoke(MethodHandles.Lookup lookup, BootstrapCallInfo bsci) throws Throwable { + MethodHandle bsm = bsci.bootstrapMethod(); + Object result = invokeCommon(bsm, + null, null, null, + maybeShareArguments(bsci), + bsci.argumentList()); + return BootstrapCallInfo.convertResult((Class) bsci.invocationType(), bsm.type().returnType(), result); + } + + /** + * Returns the result of invoking a bootstrap method handle on static + * arguments, but without metadata. In addition, any arguments of type + * {@code Object} or of any type assignable to {@code ConstantDesc} will + * be provided symbolic references, rather than resolved values, for + * the corresponding static arguments. + *

+ * Finally, any single argument of type {@code Lookup} will be passed the + * lookup object directly, rather than either a symbolic reference or + * resolved argument value. + *

+ * This method behaves as if the method handle to be invoked is the result + * of adapting the given method handle, via {@link MethodHandle#asType}, to + * adjust the return type to {@code invocationType} of the bootstrap call. + * + * @param lookup unused + * @param bsci the container of the bootstrap method + * @return the result of invoking the method handle + * @throws WrongMethodTypeException if the handle's method type cannot be + * adjusted to take the given number of arguments, or if the handle's return + * type cannot be adjusted to the desired type + * @throws ClassCastException if an argument or the result produced by + * invoking the handle cannot be converted by reference casting + * @throws Throwable anything thrown by the method handle invocation + */ + // not public until BootstrapCallInfo is public + static Object symbolic(MethodHandles.Lookup lookup, BootstrapCallInfo bsci) throws Throwable { + MethodHandle bsm = bsci.bootstrapMethod(); + MethodType bsmType = bsm.type(); + boolean passLookup = bsmType.parameterList().contains(Lookup.class); + Object[] argv = new Object[bsci.argumentCount() + (passLookup ? 1 : 0)]; + int pos = 0; + int maxPos = bsmType.parameterCount() - (bsm.isVarargsCollector() ? 1 : 0); + int bargPos = 0; + for (Class ptype : bsmType.parameterList()) { + if (pos == maxPos) break; + if (ptype == Lookup.class && passLookup) { + argv[pos++] = lookup; + passLookup = false; + } else if (isSymbolicArgType(ptype)) { + argv[pos++] = bsci.argumentDesc(bargPos++); + } else { + argv[pos++] = bsci.argument(bargPos++); + } + } + Class ptype = bsmType.lastParameterType().componentType(); + while (pos < argv.length) { + assert(ptype != null); + if (isSymbolicArgType(ptype)) { + argv[pos++] = bsci.argumentDesc(bargPos++); + } else { + argv[pos++] = bsci.argument(bargPos++); + } + } + Object result = invokeCommon(bsm, + null, null, null, + argv, null); + return BootstrapCallInfo.convertResult((Class)bsci.invocationType(), bsmType.returnType(), result); + } + + private static boolean isSymbolicArgType(Class ptype) { + return (ptype == Object.class || ConstantDesc.class.isAssignableFrom(ptype)); + } + + /** + * Trivial method which returns its sole argument, which must be a + * ConstantDesc of some sort. This method is useful as an + * expression-mode bootstrap method with the operation "symbolic". + * + * @param desc the value to be returned + * @param the type of the value to be returned + * @return desc + * @see DynamicConstantDesc#ofSymbolic + */ + public static > T constantDesc(T desc) { + return desc; + } + + /** + * Returns the result of invoking a bootstrap method handle in + * expression mode. The exact behavior of this mode depends on + * the {@code name} string. If the name is {@code "invoke"}, + * then the bootstrap method is applied directly to the arguments, + * as if it were the leading static argument to {@link #invoke}. + * If the name is {@code "symbolic"} then bootstrap arguments + * are extracted as unresolved symbolic references from the + * constant pool and returned. + * Other {@code name} strings are reserved for future use. + *

+ * @apiNote + * This method behaves like the following: + *

{@code
+    String name = bsci.invocationName();
+    switch (name) {
+    case "invoke":          return invoke(lookup, bsci);
+    case "symbolic":        return symbolic(lookup, bsci);
+    }
+     * }
+ *

+ * + * @param lookup must be non-null, otherwise presently unused + * @param bsci bootstrap call information + * @return the result of invoking the bootstrap method handle on appropriate arguments + * @throws WrongMethodTypeException if the handle's method type cannot be + * adjusted to take the given number of arguments, or if the handle's return + * type cannot be adjusted to the desired type + * @throws ClassCastException if an argument or the result produced by + * invoking the handle cannot be converted by reference casting + * @throws IllegalArgumentException if the {@code name} is invalid + * @throws Throwable anything thrown by an action selected by {@code name} + */ + // not public until BootstrapCallInfo is public + static Object linkExpression(MethodHandles.Lookup lookup, + BootstrapCallInfo bsci) throws Throwable { + requireNonNull(lookup); + requireNonNull(bsci); + + String name = bsci.invocationName(); + switch (name) { + case "invoke": return invoke(lookup, bsci); + case "symbolic": return symbolic(lookup, bsci); } - return handle.invokeWithArguments(args); + throw new IllegalArgumentException("invalid name for expression-mode constant: "+bsci); } /**