--- 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
+ * @apiNote
+ * This method behaves like the following:
+ *
+ *
+ * @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);
}
/**
+ * {@code
+ String name = bsci.invocationName();
+ switch (name) {
+ case "invoke": return invoke(lookup, bsci);
+ case "symbolic": return symbolic(lookup, bsci);
+ }
+ * }