< 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 >