< 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,34 ****
--- 24,40 ----
*/
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,75 ****
* {@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
--- 44,53 ----
*** 216,231 ****
return getStaticFinal(lookup, name, type, declaring);
}
/**
! * Returns the result of invoking a method handle with the provided
! * arguments.
* <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.
*
* @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
--- 194,209 ----
return getStaticFinal(lookup, name, type, declaring);
}
/**
! * 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 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,262 ****
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());
}
! return handle.invokeWithArguments(args);
}
/**
* Finds a {@link VarHandle} for an instance field.
*
--- 223,388 ----
MethodHandle handle, Object... args) throws Throwable {
requireNonNull(type);
requireNonNull(handle);
requireNonNull(args);
! 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);
}
! throw new IllegalArgumentException("invalid name for expression-mode constant: "+bsci);
}
/**
* Finds a {@link VarHandle} for an instance field.
*
< prev index next >