< prev index next >
src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java
Print this page
rev 52749 : Bootstrap method consolidation
* clean up and simplify JDK support code for BSM invocation
* simplify JVM bootstrap handshake: use BootstrapCallInfo only
* remove unused JVM paths and data fields
* move bootstrap argument processing from MethodHandleNatives to ConstantPool
* remove ConstantGroup; merge argument access into BootstrapCallInfo
* adjust BSM argument access: remove copyArguments, add argumentRef API
* add metadata-free BSM modes, including symbolic arguments from CP
@@ -24,11 +24,17 @@
*/
package java.lang.invoke;
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;
/**
* Bootstrap methods for dynamically-computed constants.
*
@@ -38,38 +44,10 @@
* {@code null} value.
*
* @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}.
*
* @param lookup unused
@@ -216,16 +194,16 @@
return getStaticFinal(lookup, name, type, declaring);
}
/**
- * 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.
* <p>
* 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
* @param type the desired type of the value to be returned, which must be
* compatible with the return type of the method handle
@@ -245,18 +223,166 @@
MethodHandle handle, Object... args) throws Throwable {
requireNonNull(type);
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.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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 <T> the type of the value to be returned
+ * @return desc
+ * @see DynamicConstantDesc#ofSymbolic
+ */
+ public static <T extends ConstantDesc<?>> 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.
+ * <p>
+ * @apiNote
+ * This method behaves like the following:
+ * <blockquote><pre>{@code
+ String name = bsci.invocationName();
+ switch (name) {
+ case "invoke": return invoke(lookup, bsci);
+ case "symbolic": return symbolic(lookup, bsci);
+ }
+ * }</pre></blockquote>
+ * <p>
+ *
+ * @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);
}
/**
* Finds a {@link VarHandle} for an instance field.
*
< prev index next >