JDK-8190871 : Minimal set of bootstrap methods for dynamic constants
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Priority: P2
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 11
  • Submitted: 2017-11-07
  • Updated: 2017-12-21
  • Resolved: 2017-12-21
Related Reports
CSR :  
Description
Summary
-------

Issue [JDK-8186046](https://bugs.openjdk.java.net/browse/JDK-8186046) adds support for dynamic constants to the Java platform. A minimal set of bootstrap methods should be defined for use with the ldc instruction and static arguments to dynamic constants and invokedynamic instructions.


Problem
-------

The Java platform does not provide a useful and minimal set of bootstrap methods for use with dynamic constants.


Solution
--------

Define a set of useful and minimal set of bootstrap methods for use with dynamic constants.

Note that the specification takes the rather unorthodox approach of stating that some of the first three method parameters may be unused. Bootstrap method invocation stacks up the lookup, name, and type arguments, followed by zero or more static arguments. For certain Bootstrap methods not all the first three parameters are required to produce the dynamic constant but the contract requires those parameters be part of the method signature (note that it is not required that the parameters be of the exact type, they could be a super type such as Object since method invocation is performed as if by MethodHandle.invoke).

It is intended to follow up in a separate issue with non-normative text giving rational and guidance to developers who want to use such bootstrap methods.  

Specification
-------------

A new public final class, ConstantBootstraps, is added in the java.lang.invoke package with public static methods that can be used as bootstrap methods producing constant values:
 

    /**
     * Bootstrap methods for dynamically-computed constants.
     *
     * <p>The bootstrap methods in this class will throw a
     * {@code NullPointerException} for any reference argument that is {@code null},
     * unless the argument is specified to be unused or specified to accept a
     * {@code null} value.
     *
     * @since 10
     */
    public final class ConstantBootstraps {
    ...

    /**
     * Returns a {@code null} object reference for the reference type specified
     * by {@code type}.
     *
     * @param lookup unused
     * @param name unused
     * @param type a reference type
     * @return a {@code null} value
     * @throws IllegalArgumentException if {@code type} is not a reference type
     */
    public static Object nullConstant(MethodHandles.Lookup lookup, String name, Class<?> type)

    /**
     * Returns a {@link Class} mirror for the primitive type whose type
     * descriptor is specified by {@code name}.
     *
     * @param lookup unused
     * @param name the descriptor (JVMS 4.3) of the desired primitive type
     * @param type the required result type (must be {@code Class.class})
     * @return the {@link Class} mirror
     * @throws IllegalArgumentException if the name is not a descriptor for a
     * primitive type or the type is not {@code Class.class}
     */
    public static Class<?> primitiveClass(MethodHandles.Lookup lookup, 
            String name, Class<?> type)

    /**
     * Returns an {@code enum} constant of the type specified by {@code type}
     * with the name specified by {@code name}.
     *
     * @param lookup the lookup context describing the class performing the
     * operation (normally stacked by the JVM)
     * @param type the {@code Class} object describing the enum type for which
     * a constant is to be returned
     * @param name the name of the constant to return, which must exactly match
     * an enum constant in the specified type.
     * @param <E> The enum type for which a constant value is to be returned
     * @return the enum constant of the specified enum type with the
     * specified name
     * @throws IllegalAccessError if the declaring class or the field is not
     * accessible to the class performing the operation
     * @throws IllegalArgumentException if the specified enum type has
     * no constant with the specified name, or the specified
     * class object does not represent an enum type
     * @see Enum#valueOf(Class, String)
     */
    public static <E extends Enum<E>> E enumConstant(MethodHandles.Lookup lookup, 
            String name, Class<E> type) 

    /**
     * Returns the value of a static final field.
     *
     * @param lookup the lookup context describing the class performing the
     * operation (normally stacked by the JVM)
     * @param name the name of the field
     * @param type the type of the field
     * @param declaringClass the class in which the field is declared
     * @return the value of the field
     * @throws IllegalAccessError if the declaring class or the field is not
     * accessible to the class performing the operation
     * @throws NoSuchFieldError if the specified field does not exist
     * @throws IncompatibleClassChangeError if the specified field is not
     * {@code final}
     */
    public static Object getStaticFinal(MethodHandles.Lookup lookup, 
            String name, Class<?> type,
            Class<?> declaringClass)

    /**
     * Returns the value of a static final field declared in the class which
     * is the same as the field's type (or, for primitive-valued fields,
     * declared in the wrapper class.)  This is a simplified form of
     * {@link #getStaticFinal(MethodHandles.Lookup, String, Class, Class)}
     * for the case where a class declares distinguished constant instances of
     * itself.
     *
     * @param lookup the lookup context describing the class performing the
     * operation (normally stacked by the JVM)
     * @param name the name of the field
     * @param type the type of the field
     * @return the value of the field
     * @throws IllegalAccessError if the declaring class or the field is not
     * accessible to the class performing the operation
     * @throws NoSuchFieldError if the specified field does not exist
     * @throws IncompatibleClassChangeError if the specified field is not
     * {@code final}
     * @see #getStaticFinal(MethodHandles.Lookup, String, Class, Class)
     */
    public static Object getStaticFinal(MethodHandles.Lookup lookup, 
            String name, Class<?> type)

    /**
     * Returns the result of invoking a method handle with the provided
     * arguments.
     *
     * @param lookup the lookup context describing the class performing the
     * operation (normally stacked by the JVM)
     * @param name unused
     * @param type the type of the value to be returned, which must be
     * compatible with the return type of the method handle
     * @param handle the method handle to be invoked
     * @param args the arguments to pass to the method handle, as if with
     * {@link MethodHandle#invokeWithArguments}.  Each argument may be
     * {@code null}.
     * @return the result of invoking the method handle
     * @throws WrongMethodTypeException if the handle's return type cannot be
     * adjusted to the desired type
     * @throws ClassCastException if an argument cannot be converted by
     * reference casting
     * @throws NullPointerException if {@code args} is {@code null}
     * (each argument of {@code args} may be {@code null}).
     * @throws Throwable anything thrown by the method handle invocation
     */
    public static Object invoke(MethodHandles.Lookup lookup, 
            String name, Class<?> type,
            MethodHandle handle, Object... args) throws Throwable

    /**
     * Finds a {@link VarHandle} for an instance field.
     *
     * @param lookup the lookup context describing the class performing the
     * operation (normally stacked by the JVM)
     * @param name the name of the field
     * @param type the required result type (must be {@code Class<VarHandle>})
     * @param declaringClass the class in which the field is declared
     * @param fieldType the type of the field
     * @return the {@link VarHandle}
     * @throws IllegalAccessError if the declaring class or the field is not
     * accessible to the class performing the operation
     * @throws NoSuchFieldError if the specified field does not exist
     * @throws IllegalArgumentException if the type is not {@code VarHandle}
     */
    public static VarHandle fieldVarHandle(MethodHandles.Lookup lookup, 
            String name, Class<VarHandle> type, 
            Class<?> declaringClass, Class<?> fieldType)

    /**
     * Finds a {@link VarHandle} for a static field.
     *
     * @param lookup the lookup context describing the class performing the
     * operation (normally stacked by the JVM)
     * @param name the name of the field
     * @param type the required result type (must be {@code Class<VarHandle>})
     * @param declaringClass the class in which the field is declared
     * @param fieldType the type of the field
     * @return the {@link VarHandle}
     * @throws IllegalAccessError if the declaring class or the field is not
     * accessible to the class performing the operation
     * @throws NoSuchFieldError if the specified field does not exist
     * @throws IllegalArgumentException if the type is not {@code VarHandle}
     */
    public static VarHandle staticFieldVarHandle(MethodHandles.Lookup lookup,
            String name, Class<VarHandle> type, 
            Class<?> declaringClass, Class<?> fieldType)

    /**
     * Finds a {@link VarHandle} for an array type.
     *
     * @param lookup the lookup context describing the class performing the
     * operation (normally stacked by the JVM)
     * @param name unused
     * @param type the required result type (must be {@code Class<VarHandle>})
     * @param arrayClass the type of the array
     * @return the {@link VarHandle}
     * @throws IllegalAccessError if the component type of the array is not
     * accessible to the class performing the operation
     * @throws IllegalArgumentException if the type is not {@code VarHandle}
     */
    public static VarHandle arrayVarHandle(MethodHandles.Lookup lookup, 
            String name, Class<VarHandle> type, 
            Class<?> arrayClass)


Comments
A bootstrap method is currently required to have three arguments (lookup, name, and type) followed by zero or more static arguments.
21-12-2017

While this is a lower-level API, perhaps the unused argument should not be exposed at the API surface even if the unused arguments are present at the VM level. Voting to approve with the current iteration of the API.
21-12-2017

The ideal plan would be to integrate as soon as possible after 11 development opens up. In that respect it wold be good, if time permits, to completes reviews before 11 starts.
29-11-2017

Currently prioritizing the review of CSRs targeting JDK 10 since the JDK 11 line of development doesn't exist yet.
29-11-2017

We decided to push dynamic constants out to 11, since there is risk integrating this late in the 10 schedule, and integrating early on in the 11 schedule better aligns with the new release process. In this respect the reviews should not change and the time-frame, if we integrate early in 11, is pushed out by just a few weeks.
20-11-2017

The fixVersion is set to 11; is this change intended for 10?
20-11-2017

I added some rational to the Solution section.
17-11-2017

For reviewing the new API, it would be helpful for the Solution section to briefly discuss the atypical design of the API. For example, usually methods do not have so many method parameters which can be ignored, so I assume there is desire for an overriding consistency of parameters across methods, but that rationale for that consistency is not clear to me solely from the API. Thanks.
17-11-2017