JDK-8202031 : JVM Constants API
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 12
  • Submitted: 2018-04-19
  • Updated: 2021-10-17
  • Resolved: 2018-12-08
Related Reports
CSR :  
Duplicate :  
Relates :  
Relates :  
Description
Summary
-------

Introduce an API to model nominal descriptions of key class-file and run-time artifacts, in particular constants that are loadable from the constant pool.

Problem
-------

Every Java class file has a constant pool, JVMLS 11 4.4, which stores the operands for bytecode instructions in the class. Broadly speaking, entries in the constant pool describe either run-time artifacts such as classes and methods, or simple values such as strings and integers. All these entries are known as _loadable constants_ because they may serve as operands for the `ldc` instruction, JVMLS 11 6.5. They may also appear in the static argument list of a bootstrap method for the `invokedynamic` instruction. Executing an `ldc` or `invokedynamic` instruction causes the loadable constant to be resolved into a “live” value of a standard Java type such as `Class`, `String`, or `int`.

Programs which manipulate `class` files need to model bytecode instructions, and in turn loadable constants. However, using the standard Java types to model loadable constants is inadequate. It may be acceptable for a loadable constant that describes a string (a `CONSTANT_String_info` entry), since producing a "live" `String` object is straightforward, but it is problematic for a loadable constant that describes a class (a `CONSTANT_Class_info` entry), because producing a "live" `Class` object relies on the correctness and consistency of class loading. Unfortunately, class loading has many environmental dependencies and failure modes: the desired class does not exist or may not be accessible to the requester; the result of class loading varies with context; loading classes has side-effects; and sometimes class loading may not be possible at all (such as when the classes being described do not yet exist or are otherwise not loadable, as in during compilation of those same classes, or during `jlink`-time transformation).

Consequently, programs which deal with loadable constants would be simpler if they could manipulate classes and methods, and less well-known artifacts such as method handles and dynamically-computed constants, in a purely nominal, symbolic form:

- Bytecode parsing and generation libraries must describe classes and method handles in symbolic form. Without a standard mechanism, they must resort to ad-hoc mechanisms, whether descriptor types such as ASM's `Handle`, or tuples of strings (method owner, method name, method descriptor), or ad-hoc (and error-prone) encodings of these into a single string.

- Bootstraps for `invokedynamic` that operate by spinning bytecode (such as `LambdaMetafactory`) would be simpler if they could work in a symbolic domain rather than with "live" classes and method handles.

- Compilers and offline transformers (such as `jlink` plugins) need to describe classes and members for classes that cannot be loaded into the running VM. Compiler plugins (such as annotation processors) similarly need to describe program elements in symbolic terms.

These kinds of libraries and tools would all benefit from having a single, standard way to describe loadable constants.

Solution
--------

We define a family of value-based symbolic reference (JVMS 5.1) types, in the new package `java.lang.invoke.constant`, capable of describing each kind of loadable constant. A symbolic reference describes a loadable constant in purely nominal form, separate from class loading or accessibility context. Some classes can act as their own symbolic references (e.g., `String`); for linkable constants we define a family of symbolic reference types (`ClassDesc`, `MethodTypeDesc`, `MethodHandleDesc`, and `DynamicConstantDesc`) that contain the nominal information to describe these constants.


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

    --- old/src/java.base/share/classes/java/lang/Class.java	2018-11-30 15:18:43.688082977 -0500
    +++ new/src/java.base/share/classes/java/lang/Class.java	2018-11-30 15:18:43.392082987 -0500
    @@ -154,7 +159,9 @@
     public final class Class<T> implements java.io.Serializable,
                                   GenericDeclaration,
                                   Type,
    -                              AnnotatedElement {
    +                              AnnotatedElement,
    +                              TypeDescriptor.OfField<Class<?>>,
    +                              Constable {
         private static final int ANNOTATION= 0x00002000;
         private static final int ENUM      = 0x00004000;
         private static final int SYNTHETIC = 0x00001000;
    @@ -4027,4 +4034,66 @@
             }
             return members;
         }
    +
    +    /**
    +     * Returns the type descriptor string for this class.
    +     * <p>
    +     * Note that this is not a strict inverse of {@link #forName};
    +     * distinct classes which share a common name but have different class loaders
    +     * will have identical descriptor strings.
    +     *
    +     * @return the type descriptor representation
    +     * @jvms 4.3.2 Field Descriptors
    +     * @since 12
    +     */
    +    @Override
    +    public String descriptorString() {
    +        if (isPrimitive())
    +            return Wrapper.forPrimitiveType(this).basicTypeString();
    +        else if (isArray()) {
    +            return "[" + componentType.descriptorString();
    +        }
    +        else {
    +            return "L" + getName().replace('.', '/') + ";";
    +        }
    +    }
    +
    +    /**
    +     * Returns the component type of this {@code Class}, if it describes
    +     * an array type, or {@code null} otherwise.  Equivalent to
    +     * {@link Class#getComponentType()}.
    +     *
    +     * @return a {@code Class} describing the component type, or {@code null}
    +     * if this {@code Class} does not describe an array type
    +     * @since 12
    +     */
    +    @Override
    +    public Class<?> componentType() {
    +        return isArray() ? componentType : null;
    +    }
    +
    +    /**
    +     * Returns a {@code Class} for an array type whose component type
    +     * is described by this {@linkplain Class}.
    +     *
    +     * @return a {@code Class} describing the array type
    +     * @since 12
    +     */
    +    @Override
    +    public Class<?> arrayType() {
    +        return Array.newInstance(this, 0).getClass();
    +    }
    +
    +    /**
    +     * Returns a nominal descriptor for this instance, if one can be
    +     * constructed, or an empty {@link Optional} if one cannot be.
    +     *
    +     * @return An {@link Optional} containing the resulting nominal descriptor,
    +     * or an empty {@link Optional} if one cannot be constructed.
    +     * @since 12
    +     */
    +    @Override
    +    public Optional<ClassDesc> describeConstable() {
    +        return Optional.of(ClassDesc.ofDescriptor(descriptorString()));
    +    }
    }
    --- old/src/java.base/share/classes/java/lang/Double.java   2018-11-26 12:36:05.833067418 -0500
    +++ new/src/java.base/share/classes/java/lang/Double.java   2018-11-26 12:36:05.545063990 -0500
    @@ -46,7 +51,8 @@
      * @author  Joseph D. Darcy
      * @since 1.0
      */
    -public final class Double extends Number implements Comparable<Double> {
    +public final class Double extends Number
    +        implements Comparable<Double>, ConstantDesc, Constable {
         /**
          * A constant holding the positive infinity of type
          * {@code double}. It is equal to the value returned by
    @@ -1070,6 +1076,31 @@
             return Math.min(a, b);
         }

    +    /**
    +     * Returns a nominal descriptor for this instance, which is the instance
    +     * itself.
    +     *
    +     * @return an {@link Optional} describing the {@linkplain Double} instance
    +     * @since 12
    +     */
    +    @Override
    +    public Optional<Double> describeConstable() {
    +        return Optional.of(this);
    +    }
    +
    +    /**
    +     * Resolves this instance as a {@link ConstantDesc}, the result of which is
    +     * the instance itself.
    +     *
    +     * @param lookup ignored
    +     * @return the {@linkplain Double} instance
    +     * @since 12
    +     */
    +    @Override
    +    public Double resolveConstantDesc(MethodHandles.Lookup lookup) {
    +        return this;
    +    }
    +
     /** use serialVersionUID from JDK 1.0.2 for interoperability */
     private static final long serialVersionUID = -9172774392245257468L;
    }
    --- old/src/java.base/share/classes/java/lang/Enum.java 2018-11-14 19:59:46.295610343 -0500
    +++ new/src/java.base/share/classes/java/lang/Enum.java 2018-11-14 19:59:46.011602128 -0500
    @@ -56,7 +64,7 @@
     @SuppressWarnings("serial") // No serialVersionUID needed due to
                                 // special-casing of enum types.
     public abstract class Enum<E extends Enum<E>>
    -        implements Comparable<E>, Serializable {
    +        implements Constable, Comparable<E>, Serializable {
         /**
          * The name of this enum constant, as declared in the enum declaration.
          * Most programmers should use the {@link #toString} method rather than
    @@ -204,6 +212,21 @@
         }

         /**
    +     * Returns an enum descriptor {@code EnumDesc} for this instance, if one can be
    +     * constructed, or an empty {@link Optional} if one cannot be.
    +     *
    +     * @return An {@link Optional} containing the resulting nominal descriptor,
    +     * or an empty {@link Optional} if one cannot be constructed.
    +     * @since 12
    +     */
    +    @Override
    +    public final Optional<EnumDesc<E>> describeConstable() {
    +        return getDeclaringClass()
    +                .describeConstable()
    +                .map(c -> EnumDesc.of(c, name));
    +    }
    +
    +    /**
          * Returns the enum constant of the specified enum type with the
          * specified name.  The name must match exactly an identifier used
          * to declare an enum constant in this type.  (Extraneous whitespace
    @@ -258,4 +281,56 @@
         private void readObjectNoData() throws ObjectStreamException {
             throw new InvalidObjectException("can't deserialize enum");
         }
    +
    +    /**
    +     * A <a href="package-summary.html#nominal">nominal descriptor</a> for an
    +     * {@code enum} constant.
    +     *
    +     * @param <E> the type of the enum constant
    +     *
    +     * @since 12
    +     */
    +    public static final class EnumDesc<E extends Enum<E>>
    +            extends DynamicConstantDesc<E> {
    +
    +        /**
    +         * Constructs a nominal descriptor for the specified {@code enum} class and name.
    +         *
    +         * @param constantType a {@link ClassDesc} describing the {@code enum} class
    +         * @param constantName the unqualified name of the enum constant
    +         * @throws NullPointerException if any argument is null
    +         * @jvms 4.2.2 Unqualified Names
    +         */
    +        private EnumDesc(ClassDesc constantType, String constantName) {
    +            super(ConstantDescs.BSM_ENUM_CONSTANT, requireNonNull(constantName), requireNonNull(constantType));
    +        }
    +
    +        /**
    +         * Returns a nominal descriptor for the specified {@code enum} class and name
    +         *
    +         * @param <E> the type of the enum constant
    +         * @param enumClass a {@link ClassDesc} describing the {@code enum} class
    +         * @param constantName the unqualified name of the enum constant
    +         * @return the nominal descriptor
    +         * @throws NullPointerException if any argument is null
    +         * @jvms 4.2.2 Unqualified Names
    +         * @since 12
    +         */
    +        public static<E extends Enum<E>> EnumDesc<E> of(ClassDesc enumClass,
    +                                                        String constantName) {
    +            return new EnumDesc<>(enumClass, constantName);
    +        }
    +
    +        @Override
    +        @SuppressWarnings("unchecked")
    +        public E resolveConstantDesc(MethodHandles.Lookup lookup)
    +                throws ReflectiveOperationException {
    +            return Enum.valueOf((Class<E>) constantType().resolveConstantDesc(lookup), constantName());
    +        }
    +
    +        @Override
    +        public String toString() {
    +            return String.format("EnumDesc[%s.%s]", constantType().displayName(), constantName());
    +        }
    +    }
    }
    --- old/src/java.base/share/classes/java/lang/Float.java    2018-11-14 19:59:47.187636145 -0500
    +++ new/src/java.base/share/classes/java/lang/Float.java    2018-11-14 19:59:46.903627930 -0500
    @@ -45,7 +50,8 @@
      * @author  Joseph D. Darcy
      * @since 1.0
      */
    -public final class Float extends Number implements Comparable<Float> {
    +public final class Float extends Number
    +        implements Comparable<Float>, ConstantDesc, Constable {
         /**
          * A constant holding the positive infinity of type
          * {@code float}. It is equal to the value returned by
    @@ -982,6 +988,31 @@
             return Math.min(a, b);
         }

    +    /**
    +     * Returns a nominal descriptor for this instance, which is the instance
    +     * itself.
    +     *
    +     * @return an {@link Optional} describing the {@linkplain Float} instance
    +     * @since 12
    +     */
    +    @Override
    +    public Optional<Float> describeConstable() {
    +        return Optional.of(this);
    +    }
    +
    +    /**
    +     * Resolves this instance as a {@link ConstantDesc}, the result of which is
    +     * the instance itself.
    +     *
    +     * @param lookup ignored
    +     * @return the {@linkplain Float} instance
    +     * @since 12
    +     */
    +    @Override
    +    public Float resolveConstantDesc(MethodHandles.Lookup lookup) {
    +        return this;
    +    }
    +
     /** use serialVersionUID from JDK 1.0.2 for interoperability */
     private static final long serialVersionUID = -2671257302660747028L;
    }
    --- old/src/java.base/share/classes/java/lang/Integer.java  2018-11-14 19:59:48.079661947 -0500
    +++ new/src/java.base/share/classes/java/lang/Integer.java  2018-11-14 19:59:47.795653732 -0500
    @@ -56,7 +61,8 @@
      * @author  Joseph D. Darcy
      * @since 1.0
      */
    -public final class Integer extends Number implements Comparable<Integer> {
    +public final class Integer extends Number
    +        implements Comparable<Integer>, ConstantDesc, Constable {
         /**
          * A constant holding the minimum value an {@code int} can
          * have, -2<sup>31</sup>.
    @@ -1831,6 +1837,31 @@
             return Math.min(a, b);
         }

    +    /**
    +     * Returns a nominal descriptor for this instance, which is the instance
    +     * itself.
    +     *
    +     * @return an {@link Optional} describing the {@linkplain Integer} instance
    +     * @since 12
    +     */
    +    @Override
    +    public Optional<Integer> describeConstable() {
    +        return Optional.of(this);
    +    }
    +
    +    /**
    +     * Resolves this instance as a {@link ConstantDesc}, the result of which is
    +     * the instance itself.
    +     *
    +     * @param lookup ignored
    +     * @return the {@linkplain Integer} instance
    +     * @since 12
    +     */
    +    @Override
    +    public Integer resolveConstantDesc(MethodHandles.Lookup lookup) {
    +        return this;
    +    }
    +
     /** use serialVersionUID from JDK 1.0.2 for interoperability */
     @Native private static final long serialVersionUID = 1360826667806852920L;
    }
    --- old/src/java.base/share/classes/java/lang/Long.java 2018-11-14 19:59:49.007688791 -0500
    +++ new/src/java.base/share/classes/java/lang/Long.java 2018-11-14 19:59:48.723680576 -0500
    @@ -56,7 +61,8 @@
    * @author  Joseph D. Darcy
    * @since   1.0
    */
    -public final class Long extends Number implements Comparable<Long> {
    +public final class Long extends Number
    +        implements Comparable<Long>, ConstantDesc, Constable {
         /**
          * A constant holding the minimum value a {@code long} can
          * have, -2<sup>63</sup>.
    @@ -1960,6 +1966,31 @@
             return Math.min(a, b);
         }

    +    /**
    +     * Returns a nominal descriptor for this instance, which is the instance
    +     * itself.
    +     *
    +     * @return an {@link Optional} describing the {@linkplain Long} instance
    +     * @since 12
    +     */
    +    @Override
    +    public Optional<Long> describeConstable() {
    +        return Optional.of(this);
    +    }
    +
    +    /**
    +     * Resolves this instance as a {@link ConstantDesc}, the result of which is
    +     * the instance itself.
    +     *
    +     * @param lookup ignored
    +     * @return the {@linkplain Long} instance
    +     * @since 12
    +     */
    +    @Override
    +    public Long resolveConstantDesc(MethodHandles.Lookup lookup) {
    +        return this;
    +    }
    +
     /** use serialVersionUID from JDK 1.0.2 for interoperability */
     @Native private static final long serialVersionUID = 4290774380558885855L;
    }
    --- old/src/java.base/share/classes/java/lang/String.java   2018-11-14 19:59:49.947715981 -0500
    +++ new/src/java.base/share/classes/java/lang/String.java   2018-11-14 19:59:49.663707766 -0500
    @@ -126,7 +129,8 @@
    */

    public final class String
    -    implements java.io.Serializable, Comparable<String>, CharSequence {
    +    implements java.io.Serializable, Comparable<String>, CharSequence,
    +               ConstantDesc, Constable {

         /**
          * The value is used for character storage.
    @@ -3538,4 +3543,30 @@
             throw new IllegalArgumentException(
                 format("Not a valid Unicode code point: 0x%X", codePoint));
         }
    +
    +    /**
    +     * Returns a nominal descriptor for this instance, which is the instance
    +     * itself.
    +     *
    +     * @return an {@link Optional} describing the {@linkplain String} instance
    +     * @since 12
    +     */
    +    @Override
    +    public Optional<String> describeConstable() {
    +        return Optional.of(this);
    +    }
    +
    +    /**
    +     * Resolves this instance as a {@link ConstantDesc}, the result of which is
    +     * the instance itself.
    +     *
    +     * @param lookup ignored
    +     * @return the {@linkplain String} instance
    +     * @since 12
    +     */
    +    @Override
    +    public String resolveConstantDesc(MethodHandles.Lookup lookup) {
    +        return this;
    +    }
    +
    }
    --- old/src/java.base/share/classes/java/lang/invoke/MethodHandle.java  2018-11-14 19:59:50.895743403 -0500
    +++ new/src/java.base/share/classes/java/lang/invoke/MethodHandle.java  2018-11-14 19:59:50.611735188 -0500
    @@ -428,7 +437,7 @@
      * @author John Rose, JSR 292 EG
      * @since 1.7
      */
    -public abstract class MethodHandle {
    +public abstract class MethodHandle implements Constable {

         /**
          * Internal marker interface which distinguishes (to the Java compiler)
    @@ -1512,6 +1521,60 @@
         }

         /**
    +     * Return a nominal descriptor for this instance, if one can be
    +     * constructed, or an empty {@link Optional} if one cannot be.
    +     *
    +     * @return An {@link Optional} containing the resulting nominal descriptor,
    +     * or an empty {@link Optional} if one cannot be constructed.
    +     * @since 12
    +     */
    +    @Override
    +    public Optional<MethodHandleDesc> describeConstable() {
    +        MethodHandleInfo info;
    +        ClassDesc owner;
    +        String name;
    +        MethodTypeDesc type;
    +        boolean isInterface;
    +        try {
    +            info = IMPL_LOOKUP.revealDirect(this);
    +            isInterface = info.getDeclaringClass().isInterface();
    +            owner = info.getDeclaringClass().describeConstable().orElseThrow();
    +            type = info.getMethodType().describeConstable().orElseThrow();
    +            name = info.getName();
    +        }
    +        catch (Exception e) {
    +            return Optional.empty();
    +        }
    +
    +        switch (info.getReferenceKind()) {
    +            case REF_getField:
    +                return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.GETTER, owner, name, type.returnType()));
    +            case REF_putField:
    +                return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.SETTER, owner, name, type.parameterType(0)));
    +            case REF_getStatic:
    +                return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.STATIC_GETTER, owner, name, type.returnType()));
    +            case REF_putStatic:
    +                return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.STATIC_SETTER, owner, name, type.parameterType(0)));
    +            case REF_invokeVirtual:
    +                return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.VIRTUAL, owner, name, type));
    +            case REF_invokeStatic:
    +                return isInterface ?
    +                        Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, owner, name, type)) :
    +                        Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, owner, name, type));
    +            case REF_invokeSpecial:
    +                return isInterface ?
    +                        Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_SPECIAL, owner, name, type)) :
    +                        Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.SPECIAL, owner, name, type));
    +            case REF_invokeInterface:
    +                return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, owner, name, type));
    +            case REF_newInvokeSpecial:
    +                return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.CONSTRUCTOR, owner, name, type));
    +            default:
    +                return Optional.empty();
    +        }
    +    }
    +
    +    /**
      * Returns a string representation of the method handle,
      * starting with the string {@code "MethodHandle"} and
      * ending with the string representation of the method handle's type.
    --- old/src/java.base/share/classes/java/lang/invoke/MethodType.java    2018-11-14 19:59:51.819770131 -0500
    +++ new/src/java.base/share/classes/java/lang/invoke/MethodType.java    2018-11-14 19:59:51.539762032 -0500
    @@ -91,7 +100,10 @@
      * @since 1.7
      */
     public final
    -class MethodType implements java.io.Serializable {
    +class MethodType
    +        implements Constable,
    +                   TypeDescriptor.OfMethod<Class<?>, MethodType>,
    +                   java.io.Serializable {
         private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}

         // The rtype and ptypes fields define the structural identity of the method type:
    @@ -1175,10 +1187,43 @@
             return desc;
         }

    +    /**
    +     * Return a field type descriptor string for this type
    +     *
    +     * @return the descriptor string
    +     * @jvms 4.3.2 Field Descriptors
    +     * @since 12
    +     */
    +    @Override
    +    public String descriptorString() {
    +        return toMethodDescriptorString();
    +    }
    +
         /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
             return BytecodeDescriptor.unparse(cls);
         }

    +    /**
    +     * Return a nominal descriptor for this instance, if one can be
    +     * constructed, or an empty {@link Optional} if one cannot be.
    +     *
    +     * @return An {@link Optional} containing the resulting nominal descriptor,
    +     * or an empty {@link Optional} if one cannot be constructed.
    +     * @since 12
    +     */
    +    @Override
    +    public Optional<MethodTypeDesc> describeConstable() {
    +        try {
    +            return Optional.of(MethodTypeDesc.of(returnType().describeConstable().orElseThrow(),
    +                                                 Stream.of(parameterArray())
    +                                                      .map(p -> p.describeConstable().orElseThrow())
    +                                                      .toArray(ClassDesc[]::new)));
    +        }
    +        catch (NoSuchElementException e) {
    +            return Optional.empty();
    +        }
    +    }
    +
     /// Serialization.

     /**
      * A VarHandle is a dynamically strongly typed reference to a variable, or to a
    @@ -437,7 +444,7 @@
      * @see MethodType
      * @since 9
      */
    -public abstract class VarHandle {
    +public abstract class VarHandle implements Constable {
         final VarForm vform;

         VarHandle(VarForm vform) {
    @@ -1857,6 +1864,32 @@
             }
         }

    +    @Override
    +    public final boolean equals(Object o) {
    +        if (this == o) return true;
    +        if (o == null || getClass() != o.getClass()) return false;
    +
    +        VarHandle that = (VarHandle) o;
    +        return accessModeType(AccessMode.GET).equals(that.accessModeType(AccessMode.GET)) &&
    +               internalEquals(that);
    +    }
    +
    +    abstract boolean internalEquals(VarHandle vh);
    +
    +    @Override
    +    public final int hashCode() {
    +        return 31 * accessModeType(AccessMode.GET).hashCode() + internalHashCode();
    +    }
    +
    +    abstract int internalHashCode();
    +
    +    @Override
    +    public final String toString() {
    +        return String.format("VarHandle[varType=%s, coord=%s]",
    +                             varType().getName(),
    +                             coordinateTypes());
    +    }
    +
         /**
          * Returns the variable type of variables referenced by this VarHandle.
          *
    @@ -1951,6 +1984,20 @@
             }
         }

    +    /**
    +     * Return a nominal descriptor for this instance, if one can be
    +     * constructed, or an empty {@link Optional} if one cannot be.
    +     *
    +     * @return An {@link Optional} containing the resulting nominal descriptor,
    +     * or an empty {@link Optional} if one cannot be constructed.
    +     * @since 12
    +     */
    +    @Override
    +    public Optional<VarHandleDesc> describeConstable() {
    +        // partial function for field and array only
    +        return Optional.empty();
    +    }
    +
         @Stable
         TypesAndInvokers typesAndInvokers;

    @@ -2082,4 +2129,163 @@
         public static void storeStoreFence() {
             UNSAFE.storeStoreFence();
         }
    +
    +    /**
    +     * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
    +     * {@link VarHandle} constant.
    +     *
    +     * @since 12
    +     */
    +    public static final class VarHandleDesc extends DynamicConstantDesc<VarHandle> {
    +
    +        /**
    +         * Kinds of variable handle descs
    +         */
    +        private enum Kind {
    +            FIELD(ConstantDescs.BSM_VARHANDLE_FIELD),
    +            STATIC_FIELD(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD),
    +            ARRAY(ConstantDescs.BSM_VARHANDLE_ARRAY);
    +
    +            final DirectMethodHandleDesc bootstrapMethod;
    +
    +            Kind(DirectMethodHandleDesc bootstrapMethod) {
    +                this.bootstrapMethod = bootstrapMethod;
    +            }
    +
    +            ConstantDesc[] toBSMArgs(ClassDesc declaringClass, ClassDesc varType) {
    +                switch (this) {
    +                    case FIELD:
    +                    case STATIC_FIELD:
    +                        return new ConstantDesc[] {declaringClass, varType };
    +                    case ARRAY:
    +                        return new ConstantDesc[] {declaringClass };
    +                    default:
    +                        throw new InternalError("Cannot reach here");
    +                }
    +            }
    +        }
    +
    +        private final Kind kind;
    +        private final ClassDesc declaringClass;
    +        private final ClassDesc varType;
    +
    +        /**
    +         * Construct a {@linkplain VarHandleDesc} given a kind, name, and declaring
    +         * class.
    +         *
    +         * @param kind the kind of of the var handle
    +         * @param name the unqualified name of the field, for field var handles; otherwise ignored
    +         * @param declaringClass a {@link ClassDesc} describing the declaring class,
    +         *                       for field var handles
    +         * @param varType a {@link ClassDesc} describing the type of the variable
    +         * @throws NullPointerException if any required argument is null
    +         * @jvms 4.2.2 Unqualified Names
    +         */
    +        private VarHandleDesc(Kind kind, String name, ClassDesc declaringClass, ClassDesc varType) {
    +            super(kind.bootstrapMethod, name,
    +                  ConstantDescs.CD_VarHandle,
    +                  kind.toBSMArgs(declaringClass, varType));
    +            this.kind = kind;
    +            this.declaringClass = declaringClass;
    +            this.varType = varType;
    +        }
    +
    +        /**
    +         * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
    +         * for an instance field.
    +         *
    +         * @param name the unqualifed name of the field
    +         * @param declaringClass a {@link ClassDesc} describing the declaring class,
    +         *                       for field var handles
    +         * @param fieldType a {@link ClassDesc} describing the type of the field
    +         * @return the {@linkplain VarHandleDesc}
    +         * @throws NullPointerException if any of the arguments are null
    +         * @jvms 4.2.2 Unqualified Names
    +         */
    +        public static VarHandleDesc ofField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
    +            Objects.requireNonNull(declaringClass);
    +            Objects.requireNonNull(name);
    +            Objects.requireNonNull(fieldType);
    +            return new VarHandleDesc(Kind.FIELD, name, declaringClass, fieldType);
    +        }
    +
    +        /**
    +         * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
    +         * for a static field.
    +         *
    +         * @param name the unqualified name of the field
    +         * @param declaringClass a {@link ClassDesc} describing the declaring class,
    +         *                       for field var handles
    +         * @param fieldType a {@link ClassDesc} describing the type of the field
    +         * @return the {@linkplain VarHandleDesc}
    +         * @throws NullPointerException if any of the arguments are null
    +         * @jvms 4.2.2 Unqualified Names
    +         */
    +        public static VarHandleDesc ofStaticField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
    +            Objects.requireNonNull(declaringClass);
    +            Objects.requireNonNull(name);
    +            Objects.requireNonNull(fieldType);
    +            return new VarHandleDesc(Kind.STATIC_FIELD, name, declaringClass, fieldType);
    +        }
    +
    +        /**
    +         * Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
    +         * for for an array type.
    +         *
    +         * @param arrayClass a {@link ClassDesc} describing the type of the array
    +         * @return the {@linkplain VarHandleDesc}
    +         * @throws NullPointerException if any of the arguments are null
    +         */
    +        public static VarHandleDesc ofArray(ClassDesc arrayClass) {
    +            Objects.requireNonNull(arrayClass);
    +            if (!arrayClass.isArray())
    +                throw new IllegalArgumentException("Array class argument not an array: " + arrayClass);
    +            return new VarHandleDesc(Kind.ARRAY, ConstantDescs.DEFAULT_NAME, arrayClass, arrayClass.componentType());
    +        }
    +
    +        /**
    +         * Returns a {@link ClassDesc} describing the type of the variable described
    +         * by this descriptor.
    +         *
    +         * @return the variable type
    +         */
    +        public ClassDesc varType() {
    +            return varType;
    +        }
    +
    +        @Override
    +        public VarHandle resolveConstantDesc(MethodHandles.Lookup lookup)
    +                throws ReflectiveOperationException {
    +            switch (kind) {
    +                case FIELD:
    +                    return lookup.findVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
    +                                                constantName(),
    +                                                (Class<?>) varType.resolveConstantDesc(lookup));
    +                case STATIC_FIELD:
    +                    return lookup.findStaticVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
    +                                                      constantName(),
    +                                                      (Class<?>) varType.resolveConstantDesc(lookup));
    +                case ARRAY:
    +                    return MethodHandles.arrayElementVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup));
    +                default:
    +                    throw new InternalError("Cannot reach here");
    +            }
    +        }
    +
    +        @Override
    +        public String toString() {
    +            switch (kind) {
    +                case FIELD:
    +                case STATIC_FIELD:
    +                    return String.format("VarHandleDesc[%s%s.%s:%s]",
    +                                         (kind == Kind.STATIC_FIELD) ? "static " : "",
    +                                         declaringClass.displayName(), constantName(), varType.displayName());
    +                case ARRAY:
    +                    return String.format("VarHandleDesc[%s[]]", declaringClass.displayName());
    +                default:
    +                    throw new InternalError("Cannot reach here");
    +            }
    +        }
    +    }
    +
    }
    --- old/src/java.base/share/classes/module-info.java    2018-11-14 19:59:56.147895324 -0500
    +++ new/src/java.base/share/classes/module-info.java    2018-11-14 19:59:55.871887340 -0500
    @@ -79,6 +79,7 @@
         exports java.io;
         exports java.lang;
         exports java.lang.annotation;
    +    exports java.lang.constant;
     exports java.lang.invoke;
     exports java.lang.module;
     exports java.lang.ref;
    --- /dev/null   2018-11-14 07:47:04.928729668 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/ClassDesc.java   2018-11-14 20:00:28.112819921 -0500
    @@ -0,0 +1,284 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.constant;
    +
    +import java.lang.invoke.TypeDescriptor;
    +import java.util.stream.Stream;
    +
    +import sun.invoke.util.Wrapper;
    +
    +import static java.lang.constant.ConstantUtils.binaryToInternal;
    +import static java.lang.constant.ConstantUtils.dropLastChar;
    +import static java.lang.constant.ConstantUtils.internalToBinary;
    +import static java.lang.constant.ConstantUtils.validateMemberName;
    +import static java.util.Objects.requireNonNull;
    +import static java.util.stream.Collectors.joining;
    +
    +/**
    + * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
    + * {@link Class} constant.
    + *
    + * <p>For common system types, including all the primitive types, there are
    + * predefined {@linkplain ClassDesc} constants in {@link ConstantDescs}.
    + * (The {@code java.lang.constant} APIs consider {@code void} to be a primitive type.)
    + * To create a {@linkplain ClassDesc} for a class or interface type, use {@link #of} or
    + * {@link #ofDescriptor(String)}; to create a {@linkplain ClassDesc} for an array
    + * type, use {@link #ofDescriptor(String)}, or first obtain a
    + * {@linkplain ClassDesc} for the component type and then call the {@link #arrayType()}
    + * or {@link #arrayType(int)} methods.
    + *
    + * @apiNote In the future, if the Java language permits, {@linkplain ClassDesc}
    + * may become a {@code sealed} interface, which would prohibit subclassing except
    + * by explicitly permitted types.  Non-platform classes should not implement
    + * {@linkplain ClassDesc} directly.
    + *
    + * @see ConstantDescs
    + *
    + * @since 12
    + */
    +public interface ClassDesc
    +        extends ConstantDesc,
    +                TypeDescriptor.OfField<ClassDesc> {
    +
    +    /**
    +     * Returns a {@linkplain ClassDesc} for a class or interface type,
    +     * given the name of the class or interface, such as {@code "java.lang.String"}.
    +     * (To create a descriptor for an array type, either use {@link #ofDescriptor(String)}
    +     * or {@link #arrayType()}; to create a descriptor for a primitive type, use
    +     * {@link #ofDescriptor(String)} or use the predefined constants in
    +     * {@link ConstantDescs}).
    +     *
    +     * @param name the fully qualified (dot-separated) binary class name
    +     * @return a {@linkplain ClassDesc} describing the desired class
    +     * @throws NullPointerException if any argument is {@code null}
    +     * @throws IllegalArgumentException if the name string is not in the
    +     * correct format
    +     */
    +    static ClassDesc of(String name) {
    +        ConstantUtils.validateBinaryClassName(requireNonNull(name));
    +        return ClassDesc.ofDescriptor("L" + binaryToInternal(name) + ";");
    +    }
    +
    +    /**
    +     * Returns a {@linkplain ClassDesc} for a class or interface type,
    +     * given a package name and the unqualified (simple) name for the
    +     * class or interface.
    +     *
    +     * @param packageName the package name (dot-separated); if the package
    +     *                    name is the empty string, the class is considered to
    +     *                    be in the unnamed package
    +     * @param className the unqualified (simple) class name
    +     * @return a {@linkplain ClassDesc} describing the desired class
    +     * @throws NullPointerException if any argument is {@code null}
    +     * @throws IllegalArgumentException if the package name or class name are
    +     * not in the correct format
    +     */
    +    static ClassDesc of(String packageName, String className) {
    +        ConstantUtils.validateBinaryClassName(requireNonNull(packageName));
    +        validateMemberName(requireNonNull(className));
    +        return ofDescriptor(String.format("L%s%s%s;",
    +                                          binaryToInternal(packageName),
    +                                          (packageName.length() > 0 ? "/" : ""),
    +                                          className));
    +    }
    +
    +    /**
    +     * Returns a {@linkplain ClassDesc} given a descriptor string for a class,
    +     * interface, array, or primitive type.
    +     *
    +     * @apiNote
    +     *
    +     * A field type descriptor string for a non-array type is either
    +     * a one-letter code corresponding to a primitive type
    +     * ({@code J,I,C,S,B,D,F,Z,V}), or the letter {@code L}, followed
    +     * by the fully qualified binary name of a class, followed by {@code ;}.
    +     * A field type descriptor for an array type is the character {@code [}
    +     * followed by the field descriptor for the component type.  Examples of
    +     * valid type descriptor strings include {@code Ljava/lang/String;}, {@code I},
    +     * {@code [I}, {@code V}, {@code [Ljava/lang/String;}, etc.
    +     * for more detail.
    +     *
    +     * @param descriptor a field descriptor string
    +     * @return a {@linkplain ClassDesc} describing the desired class
    +     * @throws NullPointerException if any argument is {@code null}
    +     * @throws IllegalArgumentException if the name string is not in the
    +     * correct format
    +     * @jvms 4.3.2 Field Descriptors
    +     */
    +    static ClassDesc ofDescriptor(String descriptor) {
    +        requireNonNull(descriptor);
    +        return (descriptor.length() == 1)
    +               ? new PrimitiveClassDescImpl(descriptor)
    +               : new ReferenceClassDescImpl(descriptor);
    +    }
    +
    +    /**
    +     * Returns a {@linkplain ClassDesc} for an array type whose component type
    +     * is described by this {@linkplain ClassDesc}.
    +     *
    +     * @return a {@linkplain ClassDesc} describing the array type
    +     */
    +    default ClassDesc arrayType() {
    +        return arrayType(1);
    +    }
    +
    +    /**
    +     * Returns a {@linkplain ClassDesc} for an array type of the specified rank,
    +     * whose component type is described by this {@linkplain ClassDesc}.
    +     *
    +     * @param rank the rank of the array
    +     * @return a {@linkplain ClassDesc} describing the array type
    +     * @throws IllegalArgumentException if the rank is zero or negative
    +     */
    +    default ClassDesc arrayType(int rank) {
    +        if (rank <= 0)
    +            throw new IllegalArgumentException("rank: " + rank);
    +        return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString());
    +    }
    +
    +    /**
    +     * Returns a {@linkplain ClassDesc} for a nested class of the class or
    +     * interface type described by this {@linkplain ClassDesc}.
    +     *
    +     * @param nestedName the unqualified name of the nested class
    +     * @return a {@linkplain ClassDesc} describing the nested class
    +     * @throws NullPointerException if any argument is {@code null}
    +     * @throws IllegalStateException if this {@linkplain ClassDesc} does not
    +     * describe a class or interface type
    +     * @throws IllegalArgumentException if the nested class name is invalid
    +     */
    +    default ClassDesc nested(String nestedName) {
    +        validateMemberName(nestedName);
    +        if (!isClassOrInterface())
    +            throw new IllegalStateException("Outer class is not a class or interface type");
    +        return ClassDesc.ofDescriptor(String.format("%s$%s;", dropLastChar(descriptorString()), nestedName));
    +    }
    +
    +    /**
    +     * Returns a {@linkplain ClassDesc} for a nested class of the class or
    +     * interface type described by this {@linkplain ClassDesc}.
    +     *
    +     * @param firstNestedName the unqualified name of the first level of nested class
    +     * @param moreNestedNames the unqualified name(s) of the remaining levels of
    +     *                       nested class
    +     * @return a {@linkplain ClassDesc} describing the nested class
    +     * @throws NullPointerException if any argument is {@code null}
    +     * @throws IllegalStateException if this {@linkplain ClassDesc} does not
    +     * describe a class or interface type
    +     * @throws IllegalArgumentException if the nested class name is invalid
    +     */
    +    default ClassDesc nested(String firstNestedName, String... moreNestedNames) {
    +        if (!isClassOrInterface())
    +            throw new IllegalStateException("Outer class is not a class or interface type");
    +        return moreNestedNames.length == 0
    +               ? nested(firstNestedName)
    +               : nested(firstNestedName + Stream.of(moreNestedNames).collect(joining("$", "$", "")));
    +    }
    +
    +    /**
    +     * Returns whether this {@linkplain ClassDesc} describes an array type.
    +     *
    +     * @return whether this {@linkplain ClassDesc} describes an array type
    +     */
    +    default boolean isArray() {
    +        return descriptorString().startsWith("[");
    +    }
    +
    +    /**
    +     * Returns whether this {@linkplain ClassDesc} describes a primitive type.
    +     *
    +     * @return whether this {@linkplain ClassDesc} describes a primitive type
    +     */
    +    default boolean isPrimitive() {
    +        return descriptorString().length() == 1;
    +    }
    +
    +    /**
    +     * Returns whether this {@linkplain ClassDesc} describes a class or interface type.
    +     *
    +     * @return whether this {@linkplain ClassDesc} describes a class or interface type
    +     */
    +    default boolean isClassOrInterface() {
    +        return descriptorString().startsWith("L");
    +    }
    +
    +    /**
    +     * Returns the component type of this {@linkplain ClassDesc}, if it describes
    +     * an array type, or {@code null} otherwise.
    +     *
    +     * @return a {@linkplain ClassDesc} describing the component type, or {@code null}
    +     * if this descriptor does not describe an array type
    +     */
    +    default ClassDesc componentType() {
    +        return isArray() ? ClassDesc.ofDescriptor(descriptorString().substring(1)) : null;
    +    }
    +
    +    /**
    +     * Returns the package name of this {@linkplain ClassDesc}, if it describes
    +     * a class or interface type.
    +     *
    +     * @return the package name, or the empty string if the class is in the
    +     * default package, or this {@linkplain ClassDesc} does not describe a class or interface type
    +     */
    +    default String packageName() {
    +        if (!isClassOrInterface())
    +            return "";
    +        String className = internalToBinary(ConstantUtils.dropFirstAndLastChar(descriptorString()));
    +        int index = className.lastIndexOf('.');
    +        return (index == -1) ? "" : className.substring(0, index);
    +    }
    +
    +    /**
    +     * Returns a human-readable name for the type described by this descriptor.
    +     *
    +     * @implSpec
    +     * <p>The default implementation returns the simple name
    +     * (e.g., {@code int}) for primitive types, the unqualified class name
    +     * for class or interface types, or the display name of the component type
    +     * suffixed with the appropriate number of {@code []} pairs for array types.
    +     *
    +     * @return the human-readable name
    +     */
    +    default String displayName() {
    +        if (isPrimitive())
    +            return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveSimpleName();
    +        else if (isClassOrInterface()) {
    +            return descriptorString().substring(Math.max(1, descriptorString().lastIndexOf('/') + 1),
    +                                                descriptorString().length() - 1);
    +        }
    +        else if (isArray()) {
    +            int depth = ConstantUtils.arrayDepth(descriptorString());
    +            ClassDesc c = this;
    +            for (int i=0; i<depth; i++)
    +                c = c.componentType();
    +            return c.displayName() + "[]".repeat(depth);
    +        }
    +        else
    +            throw new IllegalStateException(descriptorString());
    +    }
    +
    +    /**
    +     * Returns a field type descriptor string for this type
    +     *
    +     * @return the descriptor string
    +     * @jvms 4.3.2 Field Descriptors
    +     */
    +    String descriptorString();
    +
    +    /**
    +     * Compare the specified object with this descriptor for equality.  Returns
    +     * {@code true} if and only if the specified object is also a
    +     * {@linkplain ClassDesc} and both describe the same type.
    +     *
    +     * @param o the other object
    +     * @return whether this descriptor is equal to the other object
    +     */
    +    boolean equals(Object o);
    +}
    --- /dev/null	2018-12-06 08:43:06.972101591 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/Constable.java	2018-12-06 12:18:59.478331871 -0500
    @@ -0,0 +1,75 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.constant;
    +
    +import java.lang.invoke.MethodHandle;
    +import java.lang.invoke.MethodType;
    +import java.lang.invoke.VarHandle;
    +import java.util.Optional;
    +
    +/**
    + * Represents a type which is <em>constable</em>.  A constable type is one whose
    + * values are constants that can be represented in the constant pool of a Java
    + * classfile as described in JVMS 4.4, and whose instances can describe themselves
    + * nominally as a {@link ConstantDesc}.
    + *
    + * <p>Some constable types have a native representation in the constant pool:
    + * {@link String}, {@link Integer}, {@link Long}, {@link Float},
    + * {@link Double}, {@link Class}, {@link MethodType}, and {@link MethodHandle}.
    + * The types {@link String}, {@link Integer}, {@link Long}, {@link Float},
    + * and {@link Double} serve as their own nominal descriptors; {@link Class},
    + * {@link MethodType}, and {@link MethodHandle} have corresponding nominal
    + * descriptors {@link ClassDesc}, {@link MethodTypeDesc}, and {@link MethodHandleDesc}.
    + *
    + * <p>Other reference types can be constable if their instances can describe
    + * themselves in nominal form as a {@link ConstantDesc}. Examples in the Java SE
    + * Platform API are types that support Java language features such as {@link Enum},
    + * and runtime support classes such as {@link VarHandle}.  These are typically
    + * described with a {@link DynamicConstantDesc}, which describes dynamically
    + * generated constants (JVMS 4.4.10).
    + *
    + * <p>The nominal form of an instance of a constable type is obtained via
    + * {@link #describeConstable()}. A {@linkplain Constable} need
    + * not be able to (or may choose not to) describe all its instances in the form of
    + * a {@link ConstantDesc}; this method returns an {@link Optional} that can be
    + * empty to indicate that a nominal descriptor could not be created for an instance.
    + * (For example, {@link MethodHandle} will produce nominal descriptors for direct
    + * method handles, but not necessarily those produced by method handle
    + * combinators.)
    + * @jvms 4.4 The Constant Pool
    + * @jvms 4.4.10 The CONSTANT_InvokeDynamic_info Structure
    + *
    + * @since 12
    + */
    +public interface Constable {
    +    /**
    +     * Returns a nominal descriptor for this instance, if one can be
    +     * constructed, or an empty {@link Optional} if one cannot be constructed.
    +     *
    +     * @return An {@link Optional} containing the resulting nominal descriptor,
    +     * or an empty {@link Optional} if one cannot be constructed.
    +     */
    +    Optional<? extends ConstantDesc> describeConstable();
    +}
    --- /dev/null	2018-12-06 08:43:06.972101591 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/ConstantDesc.java	2018-12-06 12:19:00.338342441 -0500
    @@ -0,0 +1,104 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.constant;
    +
    +import java.lang.Enum.EnumDesc;
    +import java.lang.invoke.MethodHandle;
    +import java.lang.invoke.MethodHandles;
    +import java.lang.invoke.MethodType;
    +import java.lang.invoke.VarHandle.VarHandleDesc;
    +
    +/**
    + * A <a href="package-summary.html#nominal">nominal descriptor</a> for a loadable
    + * constant value, as defined in JVMS 4.4. Such a descriptor can be resolved via
    + * {@link ConstantDesc#resolveConstantDesc(MethodHandles.Lookup)} to yield the
    + * constant value itself.
    + *
    + * <p>Class names in a nominal descriptor, like class names in the constant pool
    + * of a classfile, must be interpreted with respect to a particular class
    + * loader, which is not part of the nominal descriptor.
    + *
    + * <p>Static constants that are expressible natively in the constant pool ({@link String},
    + * {@link Integer}, {@link Long}, {@link Float}, and {@link Double}) implement
    + * {@link ConstantDesc}, and serve as nominal descriptors for themselves.
    + * Native linkable constants ({@link Class}, {@link MethodType}, and
    + * {@link MethodHandle}) have counterpart {@linkplain ConstantDesc} types:
    + * {@link ClassDesc}, {@link MethodTypeDesc}, and {@link MethodHandleDesc}.
    + * Other constants are represented by subtypes of {@link DynamicConstantDesc}.
    + *
    + * <p>APIs that perform generation or parsing of bytecode are encouraged to use
    + * {@linkplain ConstantDesc} to describe the operand of an {@code ldc} instruction
    + * (including dynamic constants), the static bootstrap arguments of
    + * dynamic constants and {@code invokedynamic} instructions, and other
    + * bytecodes or classfile structures that make use of the constant pool.
    + *
    + * <p>Constants describing various common constants (such as {@link ClassDesc}
    + * instances for platform types) can be found in {@link ConstantDescs}.
    + *
    + * <p>Implementations of {@linkplain ConstantDesc} must be
    + * <a href="../doc-files/ValueBased.html">value-based</a> classes.
    + *
    + * <p>Non-platform classes should not implement {@linkplain ConstantDesc} directly.
    + * Instead, they should extend {@link DynamicConstantDesc} (as {@link EnumDesc}
    + * and {@link VarHandleDesc} do.)
    + *
    + * <p>Nominal descriptors should be compared using the
    + * {@link Object#equals(Object)} method. There is no guarantee that any
    + * particular entity will always be represented by the same descriptor instance.
    + *
    + * @apiNote In the future, if the Java language permits, {@linkplain ConstantDesc}
    + * may become a {@code sealed} interface, which would prohibit subclassing except by
    + * explicitly permitted types.  Clients can assume that the following
    + * set of subtypes is exhaustive: {@link String}, {@link Integer},
    + * {@link Long}, {@link Float}, {@link Double}, {@link ClassDesc},
    + * {@link MethodTypeDesc}, {@link MethodHandleDesc}, and
    + * {@link DynamicConstantDesc}; this list may be extended to reflect future
    + * changes to the constant pool format as defined in JVMS 4.4.
    + *
    + * @see Constable
    + * @see ConstantDescs
    + *
    + * @jvms 4.4 The Constant Pool
    + *
    + * @since 12
    + */
    +public interface ConstantDesc {
    +    /**
    +     * Resolves this descriptor reflectively, emulating the resolution behavior
    +     * of JVMS 5.4.3 and the access control behavior of JVMS 5.4.4.  The resolution
    +     * and access control context is provided by the {@link MethodHandles.Lookup}
    +     * parameter.  No caching of the resulting value is performed.
    +     *
    +     * @param lookup The {@link MethodHandles.Lookup} to provide name resolution
    +     *               and access control context
    +     * @return the resolved constant value
    +     * @throws ReflectiveOperationException if a class, method, or field
    +     * could not be reflectively resolved in the course of resolution
    +     * @throws LinkageError if a linkage error occurs
    +     * @jvms 5.4.3 Resolution
    +     * @jvms 5.4.4 Access Control
    +     */
    +    Object resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException;
    +}
    --- /dev/null	2018-12-06 08:43:06.972101591 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/ConstantDescs.java	2018-12-06 12:19:01.258353748 -0500
    @@ -0,0 +1,298 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.constant;
    +
    +import java.lang.Enum.EnumDesc;
    +import java.lang.invoke.CallSite;
    +import java.lang.invoke.ConstantBootstraps;
    +import java.lang.invoke.MethodHandle;
    +import java.lang.invoke.MethodHandles;
    +import java.lang.invoke.MethodHandles.Lookup;
    +import java.lang.invoke.MethodType;
    +import java.lang.invoke.VarHandle;
    +import java.lang.invoke.VarHandle.VarHandleDesc;
    +import java.util.Collection;
    +import java.util.List;
    +import java.util.Map;
    +import java.util.Set;
    +
    +import static java.lang.constant.DirectMethodHandleDesc.*;
    +import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC;
    +
    +/**
    + * Predefined values of <a href="package-summary.html#nominal">nominal descriptor</a>
    + * for common constants, including descriptors for primitive class types and
    + * other common platform types, and descriptors for method handles for standard
    + * bootstrap methods.
    + *
    + * @see ConstantDesc
    + *
    + * @since 12
    + */
    +public final class ConstantDescs {
    +    // No instances
    +    private ConstantDescs() { }
    +
    +    /** Invocation name to use when no name is needed, such as the name of a
    +     * constructor, or the invocation name of a dynamic constant or dynamic
    +     * callsite when the bootstrap is known to ignore the invocation name.
    +     */
    +    public static final String DEFAULT_NAME = "_";
    +
    +    // Don't change the order of these declarations!
    +
    +    /** {@link ClassDesc} representing {@link Object} */
    +    public static final ClassDesc CD_Object = ClassDesc.of("java.lang.Object");
    +
    +    /** {@link ClassDesc} representing {@link String} */
    +    public static final ClassDesc CD_String = ClassDesc.of("java.lang.String");
    +
    +    /** {@link ClassDesc} representing {@link Class} */
    +    public static final ClassDesc CD_Class = ClassDesc.of("java.lang.Class");
    +
    +    /** {@link ClassDesc} representing {@link Number} */
    +    public static final ClassDesc CD_Number = ClassDesc.of("java.lang.Number");
    +
    +    /** {@link ClassDesc} representing {@link Integer} */
    +    public static final ClassDesc CD_Integer = ClassDesc.of("java.lang.Integer");
    +
    +    /** {@link ClassDesc} representing {@link Long} */
    +    public static final ClassDesc CD_Long = ClassDesc.of("java.lang.Long");
    +
    +    /** {@link ClassDesc} representing {@link Float} */
    +    public static final ClassDesc CD_Float = ClassDesc.of("java.lang.Float");
    +
    +    /** {@link ClassDesc} representing {@link Double} */
    +    public static final ClassDesc CD_Double = ClassDesc.of("java.lang.Double");
    +
    +    /** {@link ClassDesc} representing {@link Short} */
    +    public static final ClassDesc CD_Short = ClassDesc.of("java.lang.Short");
    +
    +    /** {@link ClassDesc} representing {@link Byte} */
    +    public static final ClassDesc CD_Byte = ClassDesc.of("java.lang.Byte");
    +
    +    /** {@link ClassDesc} representing {@link Character} */
    +    public static final ClassDesc CD_Character = ClassDesc.of("java.lang.Character");
    +
    +    /** {@link ClassDesc} representing {@link Boolean} */
    +    public static final ClassDesc CD_Boolean = ClassDesc.of("java.lang.Boolean");
    +
    +    /** {@link ClassDesc} representing {@link Void} */
    +    public static final ClassDesc CD_Void = ClassDesc.of("java.lang.Void");
    +
    +    /** {@link ClassDesc} representing {@link Throwable} */
    +    public static final ClassDesc CD_Throwable = ClassDesc.of("java.lang.Throwable");
    +
    +    /** {@link ClassDesc} representing {@link Exception} */
    +    public static final ClassDesc CD_Exception = ClassDesc.of("java.lang.Exception");
    +
    +    /** {@link ClassDesc} representing {@link Enum} */
    +    public static final ClassDesc CD_Enum = ClassDesc.of("java.lang.Enum");
    +
    +    /** {@link ClassDesc} representing {@link VarHandle} */
    +    public static final ClassDesc CD_VarHandle = ClassDesc.of("java.lang.invoke.VarHandle");
    +
    +    /** {@link ClassDesc} representing {@link MethodHandles} */
    +    public static final ClassDesc CD_MethodHandles = ClassDesc.of("java.lang.invoke.MethodHandles");
    +
    +    /** {@link ClassDesc} representing {@link MethodHandles.Lookup} */
    +    public static final ClassDesc CD_MethodHandles_Lookup = CD_MethodHandles.nested("Lookup");
    +
    +    /** {@link ClassDesc} representing {@link MethodHandle} */
    +    public static final ClassDesc CD_MethodHandle = ClassDesc.of("java.lang.invoke.MethodHandle");
    +
    +    /** {@link ClassDesc} representing {@link MethodType} */
    +    public static final ClassDesc CD_MethodType = ClassDesc.of("java.lang.invoke.MethodType");
    +
    +    /** {@link ClassDesc} representing {@link CallSite} */
    +    public static final ClassDesc CD_CallSite = ClassDesc.of("java.lang.invoke.CallSite");
    +
    +    /** {@link ClassDesc} representing {@link Collection} */
    +    public static final ClassDesc CD_Collection = ClassDesc.of("java.util.Collection");
    +
    +    /** {@link ClassDesc} representing {@link List} */
    +    public static final ClassDesc CD_List = ClassDesc.of("java.util.List");
    +
    +    /** {@link ClassDesc} representing {@link Set} */
    +    public static final ClassDesc CD_Set = ClassDesc.of("java.util.Set");
    +
    +    /** {@link ClassDesc} representing {@link Map} */
    +    public static final ClassDesc CD_Map = ClassDesc.of("java.util.Map");
    +
    +    /** {@link ClassDesc} representing {@link ConstantDesc} */
    +    public static final ClassDesc CD_ConstantDesc = ClassDesc.of("java.lang.constant.ConstantDesc");
    +
    +    /** {@link ClassDesc} representing {@link ClassDesc} */
    +    public static final ClassDesc CD_ClassDesc = ClassDesc.of("java.lang.constant.ClassDesc");
    +
    +    /** {@link ClassDesc} representing {@link EnumDesc} */
    +    public static final ClassDesc CD_EnumDesc = CD_Enum.nested("EnumDesc");
    +
    +    /** {@link ClassDesc} representing {@link MethodTypeDesc} */
    +    public static final ClassDesc CD_MethodTypeDesc = ClassDesc.of("java.lang.constant.MethodTypeDesc");
    +
    +    /** {@link ClassDesc} representing {@link MethodHandleDesc} */
    +    public static final ClassDesc CD_MethodHandleDesc = ClassDesc.of("java.lang.constant.MethodHandleDesc");
    +
    +    /** {@link ClassDesc} representing {@link DirectMethodHandleDesc} */
    +    public static final ClassDesc CD_DirectMethodHandleDesc = ClassDesc.of("java.lang.constant.DirectMethodHandleDesc");
    +
    +    /** {@link ClassDesc} representing {@link VarHandleDesc} */
    +    public static final ClassDesc CD_VarHandleDesc = CD_VarHandle.nested("VarHandleDesc");
    +
    +    /** {@link ClassDesc} representing {@link DirectMethodHandleDesc.Kind} */
    +    public static final ClassDesc CD_MethodHandleDesc_Kind = CD_DirectMethodHandleDesc.nested("Kind");
    +
    +    /** {@link ClassDesc} representing {@link DynamicConstantDesc} */
    +    public static final ClassDesc CD_DynamicConstantDesc = ClassDesc.of("java.lang.constant.DynamicConstantDesc");
    +
    +    /** {@link ClassDesc} representing {@link DynamicCallSiteDesc} */
    +    public static final ClassDesc CD_DynamicCallSiteDesc = ClassDesc.of("java.lang.constant.DynamicCallSiteDesc");
    +
    +    /** {@link ClassDesc} representing {@link ConstantBootstraps} */
    +    public static final ClassDesc CD_ConstantBootstraps = ClassDesc.of("java.lang.invoke.ConstantBootstraps");
    +
    +    private static final ClassDesc[] INDY_BOOTSTRAP_ARGS = {
    +            ConstantDescs.CD_MethodHandles_Lookup,
    +            ConstantDescs.CD_String,
    +            ConstantDescs.CD_MethodType};
    +
    +    private static final ClassDesc[] CONDY_BOOTSTRAP_ARGS = {
    +            ConstantDescs.CD_MethodHandles_Lookup,
    +            ConstantDescs.CD_String,
    +            ConstantDescs.CD_Class};
    +
    +    /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#primitiveClass(Lookup, String, Class) ConstantBootstraps.primitiveClass} */
    +    public static final DirectMethodHandleDesc BSM_PRIMITIVE_CLASS
    +            = ofConstantBootstrap(CD_ConstantBootstraps, "primitiveClass",
    +            CD_Class);
    +
    +    /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#enumConstant(Lookup, String, Class) ConstantBootstraps.enumConstant} */
    +    public static final DirectMethodHandleDesc BSM_ENUM_CONSTANT
    +            = ofConstantBootstrap(CD_ConstantBootstraps, "enumConstant",
    +            CD_Enum);
    +
    +    /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#nullConstant(Lookup, String, Class) ConstantBootstraps.nullConstant} */
    +    public static final DirectMethodHandleDesc BSM_NULL_CONSTANT
    +            = ofConstantBootstrap(CD_ConstantBootstraps, "nullConstant",
    +                                  ConstantDescs.CD_Object);
    +
    +    /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#fieldVarHandle(Lookup, String, Class, Class, Class) ConstantBootstraps.fieldVarHandle} */
    +    public static final DirectMethodHandleDesc BSM_VARHANDLE_FIELD
    +            = ofConstantBootstrap(CD_ConstantBootstraps, "fieldVarHandle",
    +            CD_VarHandle, CD_Class, CD_Class);
    +
    +    /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#staticFieldVarHandle(Lookup, String, Class, Class, Class) ConstantBootstraps.staticVarHandle} */
    +    public static final DirectMethodHandleDesc BSM_VARHANDLE_STATIC_FIELD
    +            = ofConstantBootstrap(CD_ConstantBootstraps, "staticFieldVarHandle",
    +            CD_VarHandle, CD_Class, CD_Class);
    +
    +    /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#arrayVarHandle(Lookup, String, Class, Class) ConstantBootstraps.arrayVarHandle} */
    +    public static final DirectMethodHandleDesc BSM_VARHANDLE_ARRAY
    +            = ofConstantBootstrap(CD_ConstantBootstraps, "arrayVarHandle",
    +            CD_VarHandle, CD_Class);
    +
    +    /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#invoke(Lookup, String, Class, MethodHandle, Object...) ConstantBootstraps.invoke} */
    +    public static final DirectMethodHandleDesc BSM_INVOKE
    +            = ofConstantBootstrap(CD_ConstantBootstraps, "invoke",
    +            CD_Object, CD_MethodHandle, CD_Object.arrayType());
    +
    +    /** {@link ClassDesc} representing the primitive type {@code int} */
    +    public static final ClassDesc CD_int = ClassDesc.ofDescriptor("I");
    +
    +    /** {@link ClassDesc} representing the primitive type {@code long} */
    +    public static final ClassDesc CD_long = ClassDesc.ofDescriptor("J");
    +
    +    /** {@link ClassDesc} representing the primitive type {@code float} */
    +    public static final ClassDesc CD_float = ClassDesc.ofDescriptor("F");
    +
    +    /** {@link ClassDesc} representing the primitive type {@code double} */
    +    public static final ClassDesc CD_double = ClassDesc.ofDescriptor("D");
    +
    +    /** {@link ClassDesc} representing the primitive type {@code short} */
    +    public static final ClassDesc CD_short = ClassDesc.ofDescriptor("S");
    +
    +    /** {@link ClassDesc} representing the primitive type {@code byte} */
    +    public static final ClassDesc CD_byte = ClassDesc.ofDescriptor("B");
    +
    +    /** {@link ClassDesc} representing the primitive type {@code char} */
    +    public static final ClassDesc CD_char = ClassDesc.ofDescriptor("C");
    +
    +    /** {@link ClassDesc} representing the primitive type {@code boolean} */
    +    public static final ClassDesc CD_boolean = ClassDesc.ofDescriptor("Z");
    +
    +    /** {@link ClassDesc} representing the primitive type {@code void} */
    +    public static final ClassDesc CD_void = ClassDesc.ofDescriptor("V");
    +
    +    /** Nominal descriptor representing the constant {@code null} */
    +    public static final ConstantDesc NULL
    +            = DynamicConstantDesc.ofNamed(ConstantDescs.BSM_NULL_CONSTANT,
    +                                          DEFAULT_NAME, ConstantDescs.CD_Object);
    +
    +    static final DirectMethodHandleDesc MHD_METHODHANDLE_ASTYPE
    +            = MethodHandleDesc.ofMethod(Kind.VIRTUAL, CD_MethodHandle, "asType",
    +                                        MethodTypeDesc.of(CD_MethodHandle, CD_MethodType));
    +    /**
    +     * Returns a {@link MethodHandleDesc} corresponding to a bootstrap method for
    +     * an {@code invokedynamic} callsite, which is a static method whose leading
    +     * parameter types are {@code Lookup}, {@code String}, and {@code MethodType}.
    +     *
    +     * @param owner the class declaring the method
    +     * @param name the unqualified name of the method
    +     * @param returnType the return type of the method
    +     * @param paramTypes the types of the static bootstrap arguments, if any
    +     * @return the {@link MethodHandleDesc}
    +     * @throws NullPointerException if any of the arguments are null
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    public static DirectMethodHandleDesc ofCallsiteBootstrap(ClassDesc owner,
    +                                                             String name,
    +                                                             ClassDesc returnType,
    +                                                             ClassDesc... paramTypes) {
    +        return MethodHandleDesc.ofMethod(STATIC, owner, name, MethodTypeDesc.of(returnType, paramTypes)
    +                                                                            .insertParameterTypes(0, INDY_BOOTSTRAP_ARGS));
    +    }
    +
    +    /**
    +     * Returns a {@link MethodHandleDesc} corresponding to a bootstrap method for a
    +     * dynamic constant, which is a static method whose leading arguments are
    +     * {@code Lookup}, {@code String}, and {@code Class}.
    +     *
    +     * @param owner the class declaring the method
    +     * @param name the unqualified name of the method
    +     * @param returnType the return type of the method
    +     * @param paramTypes the types of the static bootstrap arguments, if any
    +     * @return the {@link MethodHandleDesc}
    +     * @throws NullPointerException if any of the arguments are null
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    public static DirectMethodHandleDesc ofConstantBootstrap(ClassDesc owner,
    +                                                             String name,
    +                                                             ClassDesc returnType,
    +                                                             ClassDesc... paramTypes) {
    +        return MethodHandleDesc.ofMethod(STATIC, owner, name, MethodTypeDesc.of(returnType, paramTypes)
    +                                                                            .insertParameterTypes(0, CONDY_BOOTSTRAP_ARGS));
    +    }
    +}
    --- /dev/null   2018-11-14 07:47:04.928729668 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java  2018-11-14 20:00:32.420944534 -0500
    @@ -0,0 +1,241 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.constant;
    +
    +import java.lang.invoke.MethodHandle;
    +import java.lang.invoke.MethodHandleInfo;
    +import java.util.OptionalInt;
    +import java.util.stream.Stream;
    +
    +import jdk.internal.vm.annotation.Stable;
    +
    +import static java.lang.invoke.MethodHandleInfo.REF_getField;
    +import static java.lang.invoke.MethodHandleInfo.REF_getStatic;
    +import static java.lang.invoke.MethodHandleInfo.REF_invokeInterface;
    +import static java.lang.invoke.MethodHandleInfo.REF_invokeSpecial;
    +import static java.lang.invoke.MethodHandleInfo.REF_invokeStatic;
    +import static java.lang.invoke.MethodHandleInfo.REF_invokeVirtual;
    +import static java.lang.invoke.MethodHandleInfo.REF_newInvokeSpecial;
    +import static java.lang.invoke.MethodHandleInfo.REF_putField;
    +import static java.lang.invoke.MethodHandleInfo.REF_putStatic;
    +
    +/**
    + * A <a href="package-summary.html#nominal">nominal descriptor</a> for a direct
    + * {@link MethodHandle}.  A {@linkplain DirectMethodHandleDesc} corresponds to
    + * a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
    + *
    + * @apiNote In the future, if the Java language permits, {@linkplain DirectMethodHandleDesc}
    + * may become a {@code sealed} interface, which would prohibit subclassing except
    + * by explicitly permitted types.  Non-platform classes should not implement
    + * {@linkplain DirectMethodHandleDesc} directly.
    + *
    + * @since 12
    + */
    +public interface DirectMethodHandleDesc extends MethodHandleDesc {
    +    /**
    +     * Kinds of method handles that can be described with {@linkplain DirectMethodHandleDesc}.
    +     *
    +     * @since 12
    +     */
    +    enum Kind {
    +        /** A method handle for a method invoked as with {@code invokestatic} */
    +        STATIC(REF_invokeStatic),
    +        /** A method handle for a method invoked as with {@code invokestatic} */
    +        INTERFACE_STATIC(REF_invokeStatic, true),
    +        /** A method handle for a method invoked as with {@code invokevirtual} */
    +        VIRTUAL(REF_invokeVirtual),
    +        /** A method handle for a method invoked as with {@code invokeinterface} */
    +        INTERFACE_VIRTUAL(REF_invokeInterface, true),
    +        /** A method handle for a method invoked as with {@code invokespecial} */
    +        SPECIAL(REF_invokeSpecial),
    +        /** A method handle for an interface method invoked as with {@code invokespecial} */
    +        INTERFACE_SPECIAL(REF_invokeSpecial, true),
    +        /** A method handle for a constructor */
    +        CONSTRUCTOR(REF_newInvokeSpecial),
    +        /** A method handle for a read accessor for an instance field  */
    +        GETTER(REF_getField),
    +        /** A method handle for a write accessor for an instance field  */
    +        SETTER(REF_putField),
    +        /** A method handle for a read accessor for a static field  */
    +        STATIC_GETTER(REF_getStatic),
    +        /** A method handle for a write accessor for a static field  */
    +        STATIC_SETTER(REF_putStatic);
    +
    +        /** The corresponding {@code refKind} value for this kind of method handle,
    +         * as defined by {@link MethodHandleInfo}
    +         */
    +        public final int refKind;
    +
    +        /** Is this an interface
    +         */
    +        public final boolean isInterface;
    +        Kind(int refKind) {
    +            this(refKind, false);
    +        }
    +
    +        Kind(int refKind, boolean isInterface) { this.refKind = refKind; this.isInterface = isInterface; }
    +
    +        /**
    +         * Returns the enumeration member with the given {@code refKind} field.
    +         * Behaves as if {@code valueOf(refKind, false)}.  As a special case,
    +         * if {@code refKind} is {@code REF_invokeInterface} (9) then the
    +         * {@code isInterface} field will be true.
    +         *
    +         * @param refKind refKind of desired member
    +         * @return the matching enumeration member
    +         * @throws IllegalArgumentException if there is no such member
    +         */
    +        public static Kind valueOf(int refKind) {
    +            return valueOf(refKind, false);
    +        }
    +
    +        /**
    +         * Returns the enumeration member with the given the {@code refKind} and
    +         * {@code isInterface} arguments.
    +         * For most values of {@code refKind} there is an exact match regardless of the value of {@code isInterface}.
    +         * These are:
    +         * <UL>
    +         *     <LI>{@code REF_invokeVirtual} which matches to {@code VIRTUAL}
    +         *     <LI>{@code REF_invokeInterface} which matches to {@code INTERFACE_VIRTUAL}
    +         *     <LI>{@code REF_newInvokeSpecial} which matches to {@code CONSTRUCTOR}
    +         *     <LI>{@code REF_getField} which matches to {@code GETTER}
    +         *     <LI>{@code REF_putField} which matches to {@code SETTER}
    +         *     <LI>{@code REF_getStatic} which matches to {@code STATIC_GETTER}
    +         *     <LI>{@code REF_putStatic} which matches to {@code STATIC_SETTER}
    +         * </UL>
    +         * As for the rest, the returned kind will depend on the value (false or true accordingly) of {@code isInterface}:
    +         * <UL>
    +         *     <LI>{@code REF_invokeStatic} which matches to {@code STATIC} or {@code INTERFACE_STATIC}
    +         *     <LI>{@code REF_invokeSpecial} which matches to {@code SPECIAL} or {@code INTERFACE_SPECIAL}
    +         * </UL>
    +         * @param refKind refKind of desired member
    +         * @param isInterface whether desired member is for interface methods
    +         * @return the matching enumeration member
    +         * @throws IllegalArgumentException if there is no such member
    +         */
    +        public static Kind valueOf(int refKind, boolean isInterface) {
    +            int i = tableIndex(refKind, isInterface);
    +            if (i >= 0 && i < TABLE.length) {
    +                Kind kind = TABLE[i];
    +                if (kind == null) {
    +                    throw new IllegalArgumentException(String.format("refKind=%d", refKind));
    +                }
    +                if (kind.refKind == refKind && kind.isInterface == isInterface) {
    +                    return kind;
    +                }
    +            }
    +            throw new IllegalArgumentException(String.format("refKind=%d", refKind));
    +        }
    +
    +        private static int tableIndex(int refKind, boolean isInterface) {
    +            if (refKind < 0)  return refKind;
    +            return (refKind * 2) + (isInterface ? 1 : 0);
    +        }
    +
    +        private static final @Stable Kind[] TABLE;
    +
    +        static {
    +            // Pack the static table.
    +            int max = 0;
    +            for (Kind k : values())
    +                max = Math.max(max, tableIndex(k.refKind, true));
    +
    +            TABLE = new Kind[max+1];
    +            for (Kind kind : values()) {
    +                int i = tableIndex(kind.refKind, kind.isInterface);
    +                if (i >= TABLE.length || TABLE[i] != null)
    +                    throw new AssertionError("TABLE entry for " + kind);
    +                TABLE[i] = kind;
    +            }
    +
    +            // Pack in some aliases also.
    +            int ii = tableIndex(REF_invokeInterface, false);
    +            if (TABLE[ii] != null)
    +                throw new AssertionError("TABLE entry for (invokeInterface, false) used by " + TABLE[ii]);
    +            TABLE[ii] = INTERFACE_VIRTUAL;
    +
    +            for (Kind kind : values()) {
    +                if (!kind.isInterface) {
    +                    // Add extra cache entry to alias the isInterface case.
    +                    // For example, (REF_getStatic, X) will produce STATIC_GETTER
    +                    // for either truth value of X.
    +                    int i = tableIndex(kind.refKind, true);
    +                    if (TABLE[i] == null) {
    +                        // There is not a specific Kind for interfaces
    +                        if (kind == VIRTUAL)  kind = INTERFACE_VIRTUAL;
    +                        if (TABLE[i] == null)  TABLE[i] = kind;
    +                    }
    +                }
    +            }
    +        }
    +
    +        /**
    +         * Does this {@code Kind} correspond to a virtual method invocation?
    +         *
    +         * @return if this {@code Kind} corresponds to a virtual method invocation
    +         */
    +        boolean isVirtualMethod() {
    +            switch (this) {
    +                case VIRTUAL:
    +                case SPECIAL:
    +                case INTERFACE_VIRTUAL:
    +                case INTERFACE_SPECIAL:
    +                    return true;
    +                default:
    +                    return false;
    +            }
    +        }
    +    }
    +
    +    /**
    +     * Returns the {@code kind} of the method handle described by this nominal
    +     * descriptor.
    +     *
    +     * @return the {@link Kind}
    +     */
    +    Kind kind();
    +
    +    /**
    +     * Returns the {@code refKind} of the method handle described by this nominal
    +     * reference, as defined by {@link MethodHandleInfo}.
    +     *
    +     * @return the reference kind
    +     */
    +    int refKind();
    +
    +    /**
    +     * Indicates if the method is declared by an interface
    +     *
    +     * @return true if the method is declared by an interface
    +     */
    +    boolean isOwnerInterface();
    +
    +    /**
    +     * Returns a {@link ClassDesc} describing the class declaring the
    +     * method or field described by this nominal descriptor.
    +     *
    +     * @return the class declaring the method or field
    +     */
    +    ClassDesc owner();
    +
    +    /**
    +     * Returns the name of the method or field described by this nominal descriptor.
    +     * For constructors, returns the reserved name {@code "<init>"}.
    +     *
    +     * @return the name of the method or field
    +     */
    +    String methodName();
    +
    +    /**
    +     * Returns the lookup descriptor of the method handle described by this descriptor,
    +     * after adjusting for the invocation mode.  This will correspond to either
    +     * a method type descriptor string (for methods and constructors), or a field
    +     * descriptor string (for field access method handles).  The lookup descriptor
    +     * string is in the same format as accepted by {@link MethodHandleDesc#of(Kind, ClassDesc, String, String)}.
    +     *
    +     * @return the lookup descriptor string
    +     */
    +    String lookupDescriptor();
    +}
    --- /dev/null   2018-11-14 07:47:04.928729668 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/DynamicCallSiteDesc.java 2018-11-14 20:00:34.204996138 -0500
    @@ -0,0 +1,271 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.constant;
    +
    +import java.lang.invoke.CallSite;
    +import java.lang.invoke.MethodHandle;
    +import java.lang.invoke.MethodHandles;
    +import java.util.Arrays;
    +import java.util.Objects;
    +import java.util.stream.Stream;
    +
    +import static java.lang.constant.ConstantDescs.CD_String;
    +import static java.lang.constant.ConstantUtils.EMPTY_CONSTANTDESC;
    +import static java.lang.constant.ConstantUtils.validateMemberName;
    +import static java.util.Objects.requireNonNull;
    +import static java.util.stream.Collectors.joining;
    +
    +/**
    + * A <a href="package-summary.html#nominal">nominal descriptor</a> for an
    + * {@code invokedynamic} call site.
    + *
    + * <p>Concrete subtypes of {@linkplain DynamicCallSiteDesc} must be
    + * <a href="../doc-files/ValueBased.html">value-based</a>.
    + *
    + * @since 12
    + */
    +public class DynamicCallSiteDesc {
    +
    +    private final DirectMethodHandleDesc bootstrapMethod;
    +    private final ConstantDesc[] bootstrapArgs;
    +    private final String invocationName;
    +    private final MethodTypeDesc invocationType;
    +
    +    /**
    +     * Creates a nominal descriptor for an {@code invokedynamic} call site.
    +     *
    +     * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
    +     *                        bootstrap method for the {@code invokedynamic}
    +     * @param invocationName The unqualified name that would appear in the {@code NameAndType}
    +     *                       operand of the {@code invokedynamic}
    +     * @param invocationType a {@link MethodTypeDesc} describing the invocation
    +     *                       type that would appear in the {@code NameAndType}
    +     *                       operand of the {@code invokedynamic}
    +     * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
    +     *                      to the bootstrap, that would appear in the
    +     *                      {@code BootstrapMethods} attribute
    +     * @throws NullPointerException if any parameter is null
    +     * @throws IllegalArgumentException if the invocation name has the incorrect
    +     * format
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    private DynamicCallSiteDesc(DirectMethodHandleDesc bootstrapMethod,
    +                                String invocationName,
    +                                MethodTypeDesc invocationType,
    +                                ConstantDesc[] bootstrapArgs) {
    +        this.invocationName = validateMemberName(requireNonNull(invocationName));
    +        this.invocationType = requireNonNull(invocationType);
    +        this.bootstrapMethod = requireNonNull(bootstrapMethod);
    +        this.bootstrapArgs = requireNonNull(bootstrapArgs.clone());
    +        if (invocationName.length() == 0)
    +            throw new IllegalArgumentException("Illegal invocation name: " + invocationName);
    +    }
    +
    +    /**
    +     * Creates a nominal descriptor for an {@code invokedynamic} call site.
    +     *
    +     * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
    +     *                        bootstrap method for the {@code invokedynamic}
    +     * @param invocationName The unqualified name that would appear in the {@code NameAndType}
    +     *                       operand of the {@code invokedynamic}
    +     * @param invocationType a {@link MethodTypeDesc} describing the invocation
    +     *                       type that would appear in the {@code NameAndType}
    +     *                       operand of the {@code invokedynamic}
    +     * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
    +     *                      to the bootstrap, that would appear in the
    +     *                      {@code BootstrapMethods} attribute
    +     * @return the nominal descriptor
    +     * @throws NullPointerException if any parameter is null
    +     * @throws IllegalArgumentException if the invocation name has the incorrect
    +     * format
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
    +                                         String invocationName,
    +                                         MethodTypeDesc invocationType,
    +                                         ConstantDesc... bootstrapArgs) {
    +        return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
    +    }
    +
    +    /**
    +     * Creates a nominal descriptor for an {@code invokedynamic} call site whose
    +     * bootstrap method has no static arguments.
    +     *
    +     * @param bootstrapMethod The bootstrap method for the {@code invokedynamic}
    +     * @param invocationName The invocationName that would appear in the
    +     * {@code NameAndType} operand of the {@code invokedynamic}
    +     * @param invocationType The invocation invocationType that would appear
    +     * in the {@code NameAndType} operand of the {@code invokedynamic}
    +     * @return the nominal descriptor
    +     * @throws NullPointerException if any parameter is null
    +     * @throws IllegalArgumentException if the invocation name has the incorrect
    +     * format
    +     */
    +    public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
    +                                         String invocationName,
    +                                         MethodTypeDesc invocationType) {
    +        return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, EMPTY_CONSTANTDESC);
    +    }
    +
    +    /**
    +     * Creates a nominal descriptor for an {@code invokedynamic} call site whose
    +     * bootstrap method has no static arguments and for which the name parameter
    +     * is {@link ConstantDescs#DEFAULT_NAME}.
    +     *
    +     * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
    +     *                        bootstrap method for the {@code invokedynamic}
    +     * @param invocationType a {@link MethodTypeDesc} describing the invocation
    +     *                       type that would appear in the {@code NameAndType}
    +     *                       operand of the {@code invokedynamic}
    +     * @return the nominal descriptor
    +     * @throws NullPointerException if any parameter is null
    +     */
    +    public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod,
    +                                         MethodTypeDesc invocationType) {
    +        return of(bootstrapMethod, ConstantDescs.DEFAULT_NAME, invocationType);
    +    }
    +
    +    /**
    +     * Returns a nominal descriptor for an {@code invokedynamic} call site whose
    +     * bootstrap method, name, and invocation type are the same as this one, but
    +     * with the specified bootstrap arguments.
    +     *
    +     * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
    +     *                      to the bootstrap, that would appear in the
    +     *                      {@code BootstrapMethods} attribute
    +     * @return the nominal descriptor
    +     * @throws NullPointerException if any parameter is null
    +     */
    +    public DynamicCallSiteDesc withArgs(ConstantDesc... bootstrapArgs) {
    +        return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
    +    }
    +
    +    /**
    +     * Returns a nominal descriptor for an {@code invokedynamic} call site whose
    +     * bootstrap and bootstrap arguments are the same as this one, but with the
    +     * specified invocationName and invocation invocationType
    +     *
    +     * @param invocationName The unqualified name that would appear in the {@code NameAndType}
    +     *                       operand of the {@code invokedynamic}
    +     * @param invocationType a {@link MethodTypeDesc} describing the invocation
    +     *                       type that would appear in the {@code NameAndType}
    +     *                       operand of the {@code invokedynamic}
    +     * @return the nominal descriptor
    +     * @throws NullPointerException if any parameter is null
    +     * @throws IllegalArgumentException if the invocation name has the incorrect
    +     * format
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    public DynamicCallSiteDesc withNameAndType(String invocationName,
    +                                               MethodTypeDesc invocationType) {
    +        return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs);
    +    }
    +
    +    /**
    +     * Returns the invocation name that would appear in the {@code NameAndType}
    +     * operand of the {@code invokedynamic}.
    +     *
    +     * @return the invocation name
    +     */
    +    public String invocationName() {
    +        return invocationName;
    +    }
    +
    +    /**
    +     * Returns a {@link MethodTypeDesc} describing the invocation type that
    +     * would appear in the {@code NameAndType} operand of the {@code invokedynamic}.
    +     *
    +     * @return the invocation type
    +     */
    +    public MethodTypeDesc invocationType() {
    +        return invocationType;
    +    }
    +
    +    /**
    +     * Returns a {@link MethodHandleDesc} describing the bootstrap method for
    +     * the {@code invokedynamic}.
    +     *
    +     * @return the bootstrap method for the {@code invokedynamic}
    +     */
    +    public MethodHandleDesc bootstrapMethod() { return bootstrapMethod; }
    +
    +    /**
    +     * Returns {@link ConstantDesc}s describing the bootstrap arguments for the
    +     * {@code invokedynamic}.
    +     *
    +     * @return the bootstrap arguments for the {@code invokedynamic}
    +     */
    +    public ConstantDesc[] bootstrapArgs() { return bootstrapArgs.clone(); }
    +
    +    /**
    +     * Reflectively invokes the bootstrap method with the specified arguments,
    +     * and return the resulting {@link CallSite}
    +     *
    +     * @param lookup The {@link MethodHandles.Lookup} used to resolve class names
    +     * @return the {@link CallSite}
    +     * @throws Throwable if any exception is thrown by the bootstrap method
    +     */
    +    public CallSite resolveCallSiteDesc(MethodHandles.Lookup lookup) throws Throwable {
    +        assert bootstrapMethod.invocationType().parameterType(1).equals(CD_String);
    +        MethodHandle bsm = (MethodHandle) bootstrapMethod.resolveConstantDesc(lookup);
    +        Object[] args = new Object[bootstrapArgs.length + 3];
    +        args[0] = lookup;
    +        args[1] = invocationName;
    +        args[2] = invocationType.resolveConstantDesc(lookup);
    +        System.arraycopy(bootstrapArgs, 0, args, 3, bootstrapArgs.length);
    +        return (CallSite) bsm.invokeWithArguments(args);
    +    }
    +
    +    /**
    +     * Compares the specified object with this descriptor for equality.  Returns
    +     * {@code true} if and only if the specified object is also a
    +     * {@linkplain DynamicCallSiteDesc}, and both descriptors have equal
    +     * bootstrap methods, bootstrap argument lists, invocation name, and
    +     * invocation type.
    +     *
    +     * @param o the {@code DynamicCallSiteDesc} to compare to this
    +     *       {@code DynamicCallSiteDesc}
    +     * @return {@code true} if the specified {@code DynamicCallSiteDesc} is
    +     *      equals to this {@code DynamicCallSiteDesc}.
    +     */
    +    @Override
    +    public final boolean equals(Object o) {
    +        if (this == o) return true;
    +        if (o == null || getClass() != o.getClass()) return false;
    +        DynamicCallSiteDesc specifier = (DynamicCallSiteDesc) o;
    +        return Objects.equals(bootstrapMethod, specifier.bootstrapMethod) &&
    +               Arrays.equals(bootstrapArgs, specifier.bootstrapArgs) &&
    +               Objects.equals(invocationName, specifier.invocationName) &&
    +               Objects.equals(invocationType, specifier.invocationType);
    +    }
    +
    +    @Override
    +    public final int hashCode() {
    +        int result = Objects.hash(bootstrapMethod, invocationName, invocationType);
    +        result = 31 * result + Arrays.hashCode(bootstrapArgs);
    +        return result;
    +    }
    +
    +    /**
    +     * Returns a compact textual description of this call site description,
    +     * including the bootstrap method, the invocation name and type, and
    +     * the static bootstrap arguments.
    +     *
    +     * @return A compact textual description of this call site descriptor
    +     */
    +    @Override
    +    public String toString() {
    +        return String.format("DynamicCallSiteDesc[%s::%s(%s%s):%s]",
    +                             bootstrapMethod.owner().displayName(),
    +                             bootstrapMethod.methodName(),
    +                             invocationName.equals(ConstantDescs.DEFAULT_NAME) ? "" : invocationName + "/",
    +                             Stream.of(bootstrapArgs).map(Object::toString).collect(joining(",")),
    +                             invocationType.displayDescriptor());
    +    }
    +}
    --- /dev/null	2018-12-06 08:43:06.972101591 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java	2018-12-06 12:19:05.434405072 -0500
    @@ -0,0 +1,397 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.constant;
    +
    +import java.lang.Enum.EnumDesc;
    +import java.lang.invoke.MethodHandle;
    +import java.lang.invoke.MethodHandles;
    +import java.lang.invoke.VarHandle;
    +import java.lang.invoke.VarHandle.VarHandleDesc;
    +import java.util.Arrays;
    +import java.util.List;
    +import java.util.Map;
    +import java.util.Objects;
    +import java.util.function.Function;
    +import java.util.stream.Stream;
    +
    +import static java.lang.constant.ConstantDescs.CD_Class;
    +import static java.lang.constant.ConstantDescs.CD_VarHandle;
    +import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
    +import static java.lang.constant.ConstantUtils.EMPTY_CONSTANTDESC;
    +import static java.lang.constant.ConstantUtils.validateMemberName;
    +import static java.util.Objects.requireNonNull;
    +import static java.util.stream.Collectors.joining;
    +
    +/**
    + * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
    + * dynamic constant (one described in the constant pool with
    + * {@code Constant_Dynamic_info}.)
    + *
    + * <p>Concrete subtypes of {@linkplain DynamicConstantDesc} must be
    + * <a href="../doc-files/ValueBased.html">value-based</a>.
    + *
    + * @param <T> the type of the dynamic constant
    + *
    + * @since 12
    + */
    +public abstract class DynamicConstantDesc<T>
    +        implements ConstantDesc {
    +
    +    private final DirectMethodHandleDesc bootstrapMethod;
    +    private final ConstantDesc[] bootstrapArgs;
    +    private final String constantName;
    +    private final ClassDesc constantType;
    +
    +    private static final Map<MethodHandleDesc, Function<DynamicConstantDesc<?>, ConstantDesc>> canonicalMap
    +            = Map.ofEntries(Map.entry(ConstantDescs.BSM_PRIMITIVE_CLASS, DynamicConstantDesc::canonicalizePrimitiveClass),
    +                            Map.entry(ConstantDescs.BSM_ENUM_CONSTANT, DynamicConstantDesc::canonicalizeEnum),
    +                            Map.entry(ConstantDescs.BSM_NULL_CONSTANT, DynamicConstantDesc::canonicalizeNull),
    +                            Map.entry(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD, DynamicConstantDesc::canonicalizeStaticFieldVarHandle),
    +                            Map.entry(ConstantDescs.BSM_VARHANDLE_FIELD, DynamicConstantDesc::canonicalizeFieldVarHandle),
    +                            Map.entry(ConstantDescs.BSM_VARHANDLE_ARRAY, DynamicConstantDesc::canonicalizeArrayVarHandle)
    +    );
    +
    +    /**
    +     * Creates a nominal descriptor for a dynamic constant.
    +     *
    +     * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
    +     *                        bootstrap method for the constant
    +     * @param constantName The unqualified name that would appear in the {@code NameAndType}
    +     *                     operand of the {@code LDC} for this constant
    +     * @param constantType a {@link ClassDesc} describing the type
    +     *                     that would appear in the {@code NameAndType} operand
    +     *                     of the {@code LDC} for this constant
    +     * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
    +     *                      to the bootstrap, that would appear in the
    +     *                      {@code BootstrapMethods} attribute
    +     * @throws NullPointerException if any argument is null
    +     * @throws IllegalArgumentException if the {@code name} has the incorrect
    +     * format
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    protected DynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod,
    +                                  String constantName,
    +                                  ClassDesc constantType,
    +                                  ConstantDesc... bootstrapArgs) {
    +        this.bootstrapMethod = requireNonNull(bootstrapMethod);
    +        this.constantName = validateMemberName(requireNonNull(constantName));
    +        this.constantType = requireNonNull(constantType);
    +        this.bootstrapArgs = requireNonNull(bootstrapArgs).clone();
    +
    +        if (constantName.length() == 0)
    +            throw new IllegalArgumentException("Illegal invocation name: " + constantName);
    +    }
    +
    +    /**
    +     * Returns a nominal descriptor for a dynamic constant, transforming it into
    +     * a more specific type if the constant bootstrap is a well-known one and a
    +     * more specific nominal descriptor type (e.g., ClassDesc) is available.
    +     *
    +     * <p>Classes whose {@link Constable#describeConstable()} method produce
    +     * a {@linkplain DynamicConstantDesc} with a well-known bootstrap including
    +     * {@link Class} (for instances describing primitive types), {@link Enum},
    +     * and {@link VarHandle}.
    +     *
    +     * <p>Bytecode-reading APIs that process the constant pool and wish to expose
    +     * entries as {@link ConstantDesc} to their callers should generally use this
    +     * method in preference to {@link #ofNamed(DirectMethodHandleDesc, String, ClassDesc, ConstantDesc...)}
    +     * because this may result in a more specific type that can be provided to
    +     * callers.
    +     *
    +     * @param <T> the type of the dynamic constant
    +     * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
    +     *                        bootstrap method for the constant
    +     * @param constantName The unqualified name that would appear in the {@code NameAndType}
    +     *                     operand of the {@code LDC} for this constant
    +     * @param constantType a {@link ClassDesc} describing the type
    +     *                     that would appear in the {@code NameAndType} operand
    +     *                     of the {@code LDC} for this constant
    +     * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
    +     *                      to the bootstrap, that would appear in the
    +     *                      {@code BootstrapMethods} attribute
    +     * @return the nominal descriptor
    +     * @throws NullPointerException if any argument is null
    +     * @throws IllegalArgumentException if the {@code name} has the incorrect
    +     * format
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    public static<T> ConstantDesc ofCanonical(DirectMethodHandleDesc bootstrapMethod,
    +                                              String constantName,
    +                                              ClassDesc constantType,
    +                                              ConstantDesc[] bootstrapArgs) {
    +        return DynamicConstantDesc.<T>ofNamed(bootstrapMethod, constantName, constantType, bootstrapArgs)
    +                .tryCanonicalize();
    +    }
    +
    +    /**
    +     * Returns a nominal descriptor for a dynamic constant.
    +     *
    +     * @param <T> the type of the dynamic constant
    +     * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
    +     *                        bootstrap method for the constant
    +     * @param constantName The unqualified name that would appear in the {@code NameAndType}
    +     *                     operand of the {@code LDC} for this constant
    +     * @param constantType a {@link ClassDesc} describing the type
    +     *                     that would appear in the {@code NameAndType} operand
    +     *                     of the {@code LDC} for this constant
    +     * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
    +     *                      to the bootstrap, that would appear in the
    +     *                      {@code BootstrapMethods} attribute
    +     * @return the nominal descriptor
    +     * @throws NullPointerException if any argument is null
    +     * @throws IllegalArgumentException if the {@code name} has the incorrect
    +     * format
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +
    +    public static<T> DynamicConstantDesc<T> ofNamed(DirectMethodHandleDesc bootstrapMethod,
    +                                                    String constantName,
    +                                                    ClassDesc constantType,
    +                                                    ConstantDesc... bootstrapArgs) {
    +        return new AnonymousDynamicConstantDesc<>(bootstrapMethod, constantName, constantType, bootstrapArgs);
    +    }
    +
    +    /**
    +     * Returns a nominal descriptor for a dynamic constant whose name parameter
    +     * is {@link ConstantDescs#DEFAULT_NAME}, and whose type parameter is always
    +     * the same as the bootstrap method return type.
    +     *
    +     * @param <T> the type of the dynamic constant
    +     * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
    +     *                        bootstrap method for the constant
    +     * @param bootstrapArgs {@link ConstantDesc}s describing the static arguments
    +     *                      to the bootstrap, that would appear in the
    +     *                      {@code BootstrapMethods} attribute
    +     * @return the nominal descriptor
    +     * @throws NullPointerException if any argument is null
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    public static<T> DynamicConstantDesc<T> of(DirectMethodHandleDesc bootstrapMethod,
    +                                               ConstantDesc... bootstrapArgs) {
    +        return ofNamed(bootstrapMethod, DEFAULT_NAME, bootstrapMethod.invocationType().returnType(), bootstrapArgs);
    +    }
    +
    +    /**
    +     * Returns a nominal descriptor for a dynamic constant whose bootstrap has
    +     * no static arguments, whose name parameter is {@link ConstantDescs#DEFAULT_NAME},
    +     * and whose type parameter is always the same as the bootstrap method return type.
    +     *
    +     * @param <T> the type of the dynamic constant
    +     * @param bootstrapMethod a {@link DirectMethodHandleDesc} describing the
    +     *                        bootstrap method for the constant
    +     * @return the nominal descriptor
    +     * @throws NullPointerException if any argument is null
    +     */
    +    public static<T> DynamicConstantDesc<T> of(DirectMethodHandleDesc bootstrapMethod) {
    +        return of(bootstrapMethod, EMPTY_CONSTANTDESC);
    +    }
    +
    +    /**
    +     * Returns the name that would appear in the {@code NameAndType} operand
    +     * of the {@code LDC} for this constant.
    +     *
    +     * @return the constant name
    +     */
    +    public String constantName() {
    +        return constantName;
    +    }
    +
    +    /**
    +     * Returns a {@link ClassDesc} describing the type that would appear in the
    +     * {@code NameAndType} operand of the {@code LDC} for this constant.
    +     *
    +     * @return the constant type
    +     */
    +    public ClassDesc constantType() {
    +        return constantType;
    +    }
    +
    +    /**
    +     * Returns a {@link MethodHandleDesc} describing the bootstrap method for
    +     * this constant.
    +     *
    +     * @return the bootstrap method
    +     */
    +    public DirectMethodHandleDesc bootstrapMethod() {
    +        return bootstrapMethod;
    +    }
    +
    +    /**
    +     * Returns the bootstrap arguments for this constant.
    +     *
    +     * @return the bootstrap arguments
    +     */
    +    public ConstantDesc[] bootstrapArgs() {
    +        return bootstrapArgs.clone();
    +    }
    +
    +    /**
    +     * Returns the bootstrap arguments for this constant as an immutable {@link List}.
    +     *
    +     * @return a {@link List} of the bootstrap arguments
    +     */
    +    public List<ConstantDesc> bootstrapArgsList() {
    +        return List.of(bootstrapArgs);
    +    }
    +
    +    @SuppressWarnings("unchecked")
    +    public T resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException {
    +        try {
    +            MethodHandle bsm = (MethodHandle) bootstrapMethod.resolveConstantDesc(lookup);
    +            if (bsm.type().parameterCount() < 2 ||
    +                !MethodHandles.Lookup.class.isAssignableFrom(bsm.type().parameterType(0))) {
    +                throw new BootstrapMethodError(
    +                        "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod);
    +            }
    +            Object[] bsmArgs = new Object[3 + bootstrapArgs.length];
    +            bsmArgs[0] = lookup;
    +            bsmArgs[1] = constantName;
    +            bsmArgs[2] = constantType.resolveConstantDesc(lookup);
    +            for (int i = 0; i < bootstrapArgs.length; i++)
    +                bsmArgs[3 + i] = bootstrapArgs[i].resolveConstantDesc(lookup);
    +
    +            return (T) bsm.invokeWithArguments(bsmArgs);
    +        } catch (Error e) {
    +            throw e;
    +        } catch (Throwable t) {
    +            throw new BootstrapMethodError(t);
    +        }
    +    }
    +
    +    private ConstantDesc tryCanonicalize() {
    +        Function<DynamicConstantDesc<?>, ConstantDesc> f = canonicalMap.get(bootstrapMethod);
    +        if (f != null) {
    +            try {
    +                return f.apply(this);
    +            }
    +            catch (Throwable t) {
    +                return this;
    +            }
    +        }
    +        return this;
    +    }
    +
    +    private static ConstantDesc canonicalizeNull(DynamicConstantDesc<?> desc) {
    +        if (desc.bootstrapArgs.length != 0)
    +            return desc;
    +        return ConstantDescs.NULL;
    +    }
    +
    +    private static ConstantDesc canonicalizeEnum(DynamicConstantDesc<?> desc) {
    +        if (desc.bootstrapArgs.length != 0
    +            || desc.constantName == null)
    +            return desc;
    +        return EnumDesc.of(desc.constantType, desc.constantName);
    +    }
    +
    +    private static ConstantDesc canonicalizePrimitiveClass(DynamicConstantDesc<?> desc) {
    +        if (desc.bootstrapArgs.length != 0
    +            || !desc.constantType().equals(CD_Class)
    +            || desc.constantName == null)
    +            return desc;
    +        return ClassDesc.ofDescriptor(desc.constantName);
    +    }
    +
    +    private static ConstantDesc canonicalizeStaticFieldVarHandle(DynamicConstantDesc<?> desc) {
    +        if (desc.bootstrapArgs.length != 2
    +                || !desc.constantType().equals(CD_VarHandle))
    +            return desc;
    +        return VarHandleDesc.ofStaticField((ClassDesc) desc.bootstrapArgs[0],
    +                                     desc.constantName,
    +                                     (ClassDesc) desc.bootstrapArgs[1]);
    +    }
    +
    +    private static ConstantDesc canonicalizeFieldVarHandle(DynamicConstantDesc<?> desc) {
    +        if (desc.bootstrapArgs.length != 2
    +            || !desc.constantType().equals(CD_VarHandle))
    +            return desc;
    +        return VarHandleDesc.ofField((ClassDesc) desc.bootstrapArgs[0],
    +                                     desc.constantName,
    +                                     (ClassDesc) desc.bootstrapArgs[1]);
    +    }
    +
    +    private static ConstantDesc canonicalizeArrayVarHandle(DynamicConstantDesc<?> desc) {
    +        if (desc.bootstrapArgs.length != 1
    +            || !desc.constantType().equals(CD_VarHandle))
    +            return desc;
    +        return VarHandleDesc.ofArray((ClassDesc) desc.bootstrapArgs[0]);
    +    }
    +
    +    // @@@ To eventually support in canonicalization: DCR with BSM=MHR_METHODHANDLEDESC_ASTYPE becomes AsTypeMHDesc
    +
    +    /**
    +     * Compares the specified object with this descriptor for equality.  Returns
    +     * {@code true} if and only if the specified object is also a
    +     * {@linkplain DynamicConstantDesc}, and both descriptors have equal
    +     * bootstrap methods, bootstrap argument lists, constant name, and
    +     * constant type.
    +     *
    +     * @param o the {@code DynamicConstantDesc} to compare to this
    +     *       {@code DynamicConstantDesc}
    +     * @return {@code true} if the specified {@code DynamicConstantDesc} is
    +     *      equals to this {@code DynamicConstantDesc}.
    +     *
    +     */
    +    @Override
    +    public final boolean equals(Object o) {
    +        if (this == o) return true;
    +        if (!(o instanceof DynamicConstantDesc)) return false;
    +        DynamicConstantDesc<?> desc = (DynamicConstantDesc<?>) o;
    +        return Objects.equals(bootstrapMethod, desc.bootstrapMethod) &&
    +               Arrays.equals(bootstrapArgs, desc.bootstrapArgs) &&
    +               Objects.equals(constantName, desc.constantName) &&
    +               Objects.equals(constantType, desc.constantType);
    +    }
    +
    +    @Override
    +    public final int hashCode() {
    +        int result = Objects.hash(bootstrapMethod, constantName, constantType);
    +        result = 31 * result + Arrays.hashCode(bootstrapArgs);
    +        return result;
    +    }
    +
    +    /**
    +     * Returns a compact textual description of this constant description,
    +     * including the bootstrap method, the constant name and type, and
    +     * the static bootstrap arguments.
    +     *
    +     * @return A compact textual description of this call site descriptor
    +     */
    +    @Override
    +    public String toString() {
    +        return String.format("DynamicConstantDesc[%s::%s(%s%s)%s]",
    +                             bootstrapMethod.owner().displayName(),
    +                             bootstrapMethod.methodName(),
    +                             constantName.equals(ConstantDescs.DEFAULT_NAME) ? "" : constantName + "/",
    +                             Stream.of(bootstrapArgs).map(Object::toString).collect(joining(",")),
    +                             constantType.displayName());
    +    }
    +
    +    private static class AnonymousDynamicConstantDesc<T> extends DynamicConstantDesc<T> {
    +        AnonymousDynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod, String constantName, ClassDesc constantType, ConstantDesc... bootstrapArgs) {
    +            super(bootstrapMethod, constantName, constantType, bootstrapArgs);
    +        }
    +    }
    +}
    --- /dev/null	2018-12-06 08:43:06.972101591 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java	2018-12-06 12:19:06.298415691 -0500
    @@ -0,0 +1,219 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.constant;
    +
    +import java.lang.invoke.MethodHandle;
    +import java.lang.invoke.MethodHandles;
    +import java.lang.invoke.MethodType;
    +
    +import static java.lang.constant.ConstantDescs.CD_void;
    +import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
    +
    +/**
    + * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
    + * {@link MethodHandle} constant.
    + *
    + * @apiNote In the future, if the Java language permits, {@linkplain MethodHandleDesc}
    + * may become a {@code sealed} interface, which would prohibit subclassing except
    + * by explicitly permitted types.  Non-platform classes should not implement
    + * {@linkplain MethodHandleDesc} directly.
    + *
    + * @since 12
    + */
    +public interface MethodHandleDesc
    +        extends ConstantDesc {
    +
    +    /**
    +     * Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a
    +     * declared method, invocation of a constructor, or access to a field.
    +     *
    +     * <p>The lookup descriptor string has the same format as for the various
    +     * variants of {@code CONSTANT_MethodHandle_info} and for the lookup
    +     * methods on {@link MethodHandles.Lookup}.  For a method or constructor
    +     * invocation, it is interpreted as a method type descriptor; for field
    +     * access, it is interpreted as a field descriptor.  If {@code kind} is
    +     * {@code CONSTRUCTOR}, the {@code name} parameter is ignored and the return
    +     * type of the lookup descriptor must be {@code void}.  If {@code kind}
    +     * corresponds to a virtual method invocation, the lookup type includes the
    +     * method parameters but not the receiver type.
    +     *
    +     * @param kind The kind of method handle to be described
    +     * @param owner a {@link ClassDesc} describing the class containing the
    +     *              method, constructor, or field
    +     * @param name the unqualified name of the method or field (ignored if
    +     *             {@code kind} is {@code CONSTRUCTOR})
    +     * @param lookupDescriptor a method descriptor string the lookup type,
    +     *                         if the request is for a method invocation, or
    +     *                         describing the invocation type, if the request is
    +     *                         for a field or constructor
    +     * @return the {@linkplain MethodHandleDesc}
    +     * @throws NullPointerException if any of the non-ignored arguments are null
    +     * @jvms 4.4.8 The CONSTANT_MethodHandle_info Structure
    +     * @jvms 4.2.2 Unqualified Names
    +     * @jvms 4.3.2 Field Descriptors
    +     * @jvms 4.3.3 Method Descriptors
    +     */
    +    static DirectMethodHandleDesc of(DirectMethodHandleDesc.Kind kind,
    +                                     ClassDesc owner,
    +                                     String name,
    +                                     String lookupDescriptor) {
    +        switch (kind) {
    +            case GETTER:
    +            case SETTER:
    +            case STATIC_GETTER:
    +            case STATIC_SETTER:
    +                return ofField(kind, owner, name, ClassDesc.ofDescriptor(lookupDescriptor));
    +            default:
    +                return new DirectMethodHandleDescImpl(kind, owner, name, MethodTypeDesc.ofDescriptor(lookupDescriptor));
    +        }
    +    }
    +
    +    /**
    +     * Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a
    +     * declared method or constructor.
    +     *
    +     * <p>The lookup descriptor string has the same format as for the lookup
    +     * methods on {@link MethodHandles.Lookup}.  If {@code kind} is
    +     * {@code CONSTRUCTOR}, the name is ignored and the return type of the lookup
    +     * type must be {@code void}.  If {@code kind} corresponds to a virtual method
    +     * invocation, the lookup type includes the method parameters but not the
    +     * receiver type.
    +     *
    +     * @param kind The kind of method handle to be described; must be one of
    +     *             {@code SPECIAL, VIRTUAL, STATIC, INTERFACE_SPECIAL,
    +     *             INTERFACE_VIRTUAL, INTERFACE_STATIC, CONSTRUCTOR}
    +     * @param owner a {@link ClassDesc} describing the class containing the
    +     *              method or constructor
    +     * @param name the unqualified name of the method (ignored if {@code kind}
    +     *             is {@code CONSTRUCTOR})
    +     * @param lookupMethodType a {@link MethodTypeDesc} describing the lookup type
    +     * @return the {@linkplain MethodHandleDesc}
    +     * @throws NullPointerException if any non-ignored arguments are null
    +     * @throws IllegalArgumentException if the {@code name} has the incorrect
    +     * format, or the kind is invalid
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    static DirectMethodHandleDesc ofMethod(DirectMethodHandleDesc.Kind kind,
    +                                           ClassDesc owner,
    +                                           String name,
    +                                           MethodTypeDesc lookupMethodType) {
    +        switch (kind) {
    +            case GETTER:
    +            case SETTER:
    +            case STATIC_GETTER:
    +            case STATIC_SETTER:
    +                throw new IllegalArgumentException(kind.toString());
    +            case VIRTUAL:
    +            case SPECIAL:
    +            case INTERFACE_VIRTUAL:
    +            case INTERFACE_SPECIAL:
    +            case INTERFACE_STATIC:
    +            case STATIC:
    +            case CONSTRUCTOR:
    +                return new DirectMethodHandleDescImpl(kind, owner, name, lookupMethodType);
    +            default:
    +                throw new IllegalArgumentException(kind.toString());
    +        }
    +    }
    +
    +    /**
    +     * Creates a {@linkplain MethodHandleDesc} corresponding to a method handle
    +     * that accesses a field.
    +     *
    +     * @param kind the kind of the method handle to be described; must be one of {@code GETTER},
    +     *             {@code SETTER}, {@code STATIC_GETTER}, or {@code STATIC_SETTER}
    +     * @param owner a {@link ClassDesc} describing the class containing the field
    +     * @param fieldName the unqualified name of the field
    +     * @param fieldType a {@link ClassDesc} describing the type of the field
    +     * @return the {@linkplain MethodHandleDesc}
    +     * @throws NullPointerException if any of the arguments are null
    +     * @throws IllegalArgumentException if the {@code kind} is not one of the
    +     * valid values or if the field name is not valid
    +     * @jvms 4.2.2 Unqualified Names
    +     */
    +    static DirectMethodHandleDesc ofField(DirectMethodHandleDesc.Kind kind,
    +                                          ClassDesc owner,
    +                                          String fieldName,
    +                                          ClassDesc fieldType) {
    +        MethodTypeDesc mtr;
    +        switch (kind) {
    +            case GETTER: mtr = MethodTypeDesc.of(fieldType, owner); break;
    +            case SETTER: mtr = MethodTypeDesc.of(CD_void, owner, fieldType); break;
    +            case STATIC_GETTER: mtr = MethodTypeDesc.of(fieldType); break;
    +            case STATIC_SETTER: mtr = MethodTypeDesc.of(CD_void, fieldType); break;
    +            default:
    +                throw new IllegalArgumentException(kind.toString());
    +        }
    +        return new DirectMethodHandleDescImpl(kind, owner, fieldName, mtr);
    +    }
    +
    +    /**
    +     * Returns a {@linkplain MethodHandleDesc} corresponding to invocation of a constructor
    +     *
    +     * @param owner a {@link ClassDesc} describing the class containing the
    +     *              constructor
    +     * @param paramTypes {@link ClassDesc}s describing the parameter types of
    +     *                   the constructor
    +     * @return the {@linkplain MethodHandleDesc}
    +     * @throws NullPointerException if any of the arguments are null
    +     */
    +    static DirectMethodHandleDesc ofConstructor(ClassDesc owner,
    +                                                ClassDesc... paramTypes) {
    +        return MethodHandleDesc.ofMethod(CONSTRUCTOR, owner, ConstantDescs.DEFAULT_NAME,
    +                                         MethodTypeDesc.of(CD_void, paramTypes));
    +    }
    +
    +    /**
    +     * Returns a {@linkplain MethodHandleDesc} that describes this method handle
    +     * adapted to a different type, as if by {@link MethodHandle#asType(MethodType)}.
    +     *
    +     * @param type a {@link MethodHandleDesc} describing the new method type
    +     * @return a {@linkplain MethodHandleDesc} for the adapted method handle
    +     */
    +    default MethodHandleDesc asType(MethodTypeDesc type) {
    +        return (invocationType().equals(type)) ? this : new AsTypeMethodHandleDesc(this, type);
    +    }
    +
    +    /**
    +     * Returns a {@link MethodTypeDesc} describing the invocation type of the
    +     * method handle described by this nominal descriptor.  The invocation type
    +     * describes the full set of stack values that are consumed by the invocation
    +     * (including the receiver, if any).
    +     *
    +     * @return a {@linkplain MethodHandleDesc} describing the method handle type
    +     */
    +    MethodTypeDesc invocationType();
    +
    +    /**
    +     * Compares the specified object with this descriptor for equality.  Returns
    +     * {@code true} if and only if the specified object is also a
    +     * {@linkplain MethodHandleDesc}, and both encode the same nominal description
    +     * of a method handle.
    +     *
    +     * @param o the other object
    +     * @return whether this descriptor is equal to the other object
    +     */
    +    boolean equals(Object o);
    +}
    --- /dev/null	2018-12-06 08:43:06.972101591 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java	2018-12-06 12:19:07.242427293 -0500
    @@ -0,0 +1,201 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.constant;
    +
    +import java.lang.invoke.MethodType;
    +import java.lang.invoke.TypeDescriptor;
    +import java.util.List;
    +import java.util.stream.Collectors;
    +import java.util.stream.Stream;
    +
    +/**
    + * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
    + * {@linkplain MethodType} constant.
    + *
    + * @apiNote In the future, if the Java language permits, {@linkplain MethodTypeDesc}
    + * may become a {@code sealed} interface, which would prohibit subclassing except
    + * by explicitly permitted types.  Non-platform classes should not implement
    + * {@linkplain MethodTypeDesc} directly.
    + *
    + * @since 12
    + */
    +public interface MethodTypeDesc
    +        extends ConstantDesc,
    +                TypeDescriptor.OfMethod<ClassDesc, MethodTypeDesc> {
    +    /**
    +     * Creates a {@linkplain MethodTypeDesc} given a method descriptor string.
    +     *
    +     * @param descriptor a method descriptor string
    +     * @return a {@linkplain MethodTypeDesc} describing the desired method type
    +     * @throws NullPointerException if any argument is {@code null}
    +     * @throws IllegalArgumentException if the descriptor string is not a valid
    +     * method descriptor
    +     * @jvms 4.3.3 Method Descriptors
    +     */
    +    static MethodTypeDesc ofDescriptor(String descriptor) {
    +        return MethodTypeDescImpl.ofDescriptor(descriptor);
    +    }
    +
    +    /**
    +     * Returns a {@linkplain MethodTypeDesc} given the return type and parameter
    +     * types.
    +     *
    +     * @param returnDesc a {@linkplain ClassDesc} describing the return type
    +     * @param paramDescs {@linkplain ClassDesc}s describing the argument types
    +     * @return a {@linkplain MethodTypeDesc} describing the desired method type
    +     * @throws NullPointerException if any argument is {@code null}
    +     */
    +    static MethodTypeDesc of(ClassDesc returnDesc, ClassDesc... paramDescs) {
    +        return new MethodTypeDescImpl(returnDesc, paramDescs);
    +    }
    +
    +    /**
    +     * Gets the return type of the method type described by this {@linkplain MethodTypeDesc}.
    +     *
    +     * @return a {@link ClassDesc} describing the return type of the method type
    +     */
    +    ClassDesc returnType();
    +
    +    /**
    +     * Returns the number of parameters of the method type described by
    +     * this {@linkplain MethodTypeDesc}.
    +     * @return the number of parameters
    +     */
    +    int parameterCount();
    +
    +    /**
    +     * Returns the parameter type of the {@code index}'th parameter of the method type
    +     * described by this {@linkplain MethodTypeDesc}.
    +     *
    +     * @param index the index of the parameter to retrieve
    +     * @return a {@link ClassDesc} describing the desired parameter type
    +     * @throws IndexOutOfBoundsException if the index is outside the half-open
    +     * range {[0, parameterCount())}
    +     */
    +    ClassDesc parameterType(int index);
    +
    +    /**
    +     * Returns the parameter types as an immutable {@link List}.
    +     *
    +     * @return a {@link List} of {@link ClassDesc} describing the parameter types
    +     */
    +    List<ClassDesc> parameterList();
    +
    +    /**
    +     * Returns the parameter types as an array.
    +     *
    +     * @return an array of {@link ClassDesc} describing the parameter types
    +     */
    +    ClassDesc[] parameterArray();
    +
    +    /**
    +     * Returns a {@linkplain MethodTypeDesc} that is identical to
    +     * this one, except with the specified return type.
    +     *
    +     * @param returnType a {@link ClassDesc} describing the new return type
    +     * @return a {@linkplain MethodTypeDesc} describing the desired method type
    +     * @throws NullPointerException if any argument is {@code null}
    +     */
    +    MethodTypeDesc changeReturnType(ClassDesc returnType);
    +
    +    /**
    +     * Returns a {@linkplain MethodTypeDesc} that is identical to this one,
    +     * except that a single parameter type has been changed to the specified type.
    +     *
    +     * @param index the index of the parameter to change
    +     * @param paramType a {@link ClassDesc} describing the new parameter type
    +     * @return a {@linkplain MethodTypeDesc} describing the desired method type
    +     * @throws NullPointerException if any argument is {@code null}
    +     * @throws IndexOutOfBoundsException if the index is outside the half-open
    +     * range {[0, parameterCount)}
    +     */
    +    MethodTypeDesc changeParameterType(int index, ClassDesc paramType);
    +
    +    /**
    +     * Returns a {@linkplain MethodTypeDesc} that is identical to this one,
    +     * except that a range of parameter types have been removed.
    +     *
    +     * @param start the index of the first parameter to remove
    +     * @param end the index after the last parameter to remove
    +     * @return a {@linkplain MethodTypeDesc} describing the desired method type
    +     * @throws IndexOutOfBoundsException if {@code start} is outside the half-open
    +     * range {[0, parameterCount)}, or {@code end} is outside the closed range
    +     * {@code [0, parameterCount]}
    +     */
    +    MethodTypeDesc dropParameterTypes(int start, int end);
    +
    +    /**
    +     * Returns a {@linkplain MethodTypeDesc} that is identical to this one,
    +     * except that a range of additional parameter types have been inserted.
    +     *
    +     * @param pos the index at which to insert the first inserted parameter
    +     * @param paramTypes {@link ClassDesc}s describing the new parameter types
    +     *                   to insert
    +     * @return a {@linkplain MethodTypeDesc} describing the desired method type
    +     * @throws NullPointerException if any argument is {@code null}
    +     * @throws IndexOutOfBoundsException if {@code pos} is outside the closed
    +     * range {[0, parameterCount]}
    +     */
    +    MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes);
    +
    +    /**
    +     * Returns the method type descriptor string.
    +     *
    +     * @return the method type descriptor string
    +     * @jvms 4.3.3 Method Descriptors
    +     */
    +    default String descriptorString() {
    +        return String.format("(%s)%s",
    +                             Stream.of(parameterArray())
    +                                   .map(ClassDesc::descriptorString)
    +                                   .collect(Collectors.joining()),
    +                             returnType().descriptorString());
    +    }
    +
    +    /**
    +     * Returns a human-readable descriptor for this method type, using the
    +     * canonical names for parameter and return types.
    +     *
    +     * @return the human-readable descriptor for this method type
    +     */
    +    default String displayDescriptor() {
    +        return String.format("(%s)%s",
    +                             Stream.of(parameterArray())
    +                                   .map(ClassDesc::displayName)
    +                                   .collect(Collectors.joining(",")),
    +                             returnType().displayName());
    +    }
    +
    +    /**
    +     * Compares the specified object with this descriptor for equality.  Returns
    +     * {@code true} if and only if the specified object is also a
    +     * {@linkplain MethodTypeDesc} both have the same arity, their return types
    +     * are equal, and each pair of corresponding parameter types are equal.
    +     *
    +     * @param o the other object
    +     * @return whether this descriptor is equal to the other object
    +     */
    +    boolean equals(Object o);
    +}
    --- /dev/null   2018-11-14 07:47:04.928729668 -0500
    +++ new/src/java.base/share/classes/java/lang/constant/package-info.java    2018-11-14 20:00:40.465177217 -0500
    @@ -0,0 +1,96 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +
    +/**
    + * Classes and interfaces to represent <em>nominal descriptors</em> for run-time
    + * entities such as classes or method handles, and classfile entities such as
    + * constant pool entries or {@code invokedynamic} call sites.  These classes
    + * are suitable for use in bytecode reading and writing APIs, {@code invokedynamic}
    + * bootstraps, bytecode intrinsic APIs, and compile-time or link-time program
    + * analysis tools.
    + *
    + * <p>Every API that reads and writes bytecode instructions needs to model the
    + * operands to these instructions and other classfile structures (such as entries
    + * in the bootstrap methods table or stack maps, which frequently reference
    + * entries in the classfile constant pool.) Such entries can denote values of
    + * fundamental types, such as strings or integers; parts of a program, such as
    + * classes or method handles; or values of arbitrary user-defined types.  The
    + * {@link java.lang.constant.ConstantDesc} hierarchy provides a representation of
    + * constant pool entries in nominal form that is convenient for APIs to model
    + * operands of bytecode instructions.
    + *
    + * <h2><a id="nominal"></a>Nominal Descriptors</h2>
    + *
    + * <p>A {@link java.lang.constant.ConstantDesc} is a description of a constant
    + * value.  Such a description is the <em>nominal form</em> of the constant value;
    + * it is not the value itself, but rather a "recipe" for describing the value,
    + * storing the value in a constant pool entry, or reconstituting the value given
    + * a class loading context.  Every {@link java.lang.constant.ConstantDesc}
    + * knows how to <em>resolve</em> itself -- compute the value that it describes --
    + * via {@link java.lang.constant.ConstantDesc#resolveConstantDesc(java.lang.invoke.MethodHandles.Lookup)}.
    + * This allows an API which accepts {@link java.lang.constant.ConstantDesc}
    + * objects to evaluate them reflectively, provided that the classes and methods
    + * referenced in their nominal description are present and accessible.
    + *
    + * <p>The subtypes of {@link java.lang.constant.ConstantDesc} describe various kinds
    + * of constant values.  For each type of loadable constant pool entry defined in JVMS 4.4,
    + * there is a corresponding subtype of {@link java.lang.constant.ConstantDesc}:
    + * {@link java.lang.constant.ClassDesc}, {@link java.lang.constant.MethodTypeDesc},
    + * {@link java.lang.constant.DirectMethodHandleDesc}, {@link java.lang.String},
    + * {@link java.lang.Integer}, {@link java.lang.Long}, {@link java.lang.Float},
    + * {@link java.lang.Double}, and {@link java.lang.constant.DynamicConstantDesc}.  These classes
    + * provide type-specific accessor methods to extract the nominal information for
    + * that kind of constant.  When a bytecode-writing API encounters a {@link java.lang.constant.ConstantDesc},
    + * it should examine it to see which of these types it is, cast it, extract
    + * its nominal information, and generate the corresponding entry to the constant pool.
    + * When a bytecode-reading API encounters a constant pool entry, it can
    + * convert it to the appropriate type of nominal descriptor.  For dynamic
    + * constants, bytecode-reading APIs may wish to use the factory
    + * {@link java.lang.constant.DynamicConstantDesc#ofCanonical(DirectMethodHandleDesc, java.lang.String, ClassDesc, ConstantDesc[])},
    + * which will inspect the bootstrap and, for well-known bootstraps, return
    + * a more specific subtype of {@link java.lang.constant.DynamicConstantDesc}, such as
    + * {@link java.lang.Enum.EnumDesc}.
    + *
    + * <p>Another way to obtain the nominal description of a value is to ask the value
    + * itself.  A {@link java.lang.constant.Constable} is a type whose values
    + * can describe themselves in nominal form as a {@link java.lang.constant.ConstantDesc}.
    + * Fundamental types such as {@link java.lang.String} and {@link java.lang.Class}
    + * implement {@link java.lang.constant.Constable}, as can user-defined
    + * classes.  Entities that generate classfiles (such as compilers) can introspect
    + * over constable objects to obtain a more efficient way to represent their values
    + * in classfiles.
    + *
    + * <p>This package also includes {@link java.lang.constant.DynamicCallSiteDesc},
    + * which represents a (non-loadable) {@code Constant_InvokeDynamic_info} constant
    + * pool entry.  It describes the bootstrap method, invocation name and type,
    + * and bootstrap arguments associated with an {@code invokedynamic} instruction.
    + * It is also suitable for describing {@code invokedynamic} call sites in bytecode
    + * reading and writing APIs.
    + *
    + * @jvms 4.4 The Constant Pool
    + *
    + * @since 12
    + */
    +package java.lang.constant;
    --- /dev/null	2018-12-06 08:43:06.972101591 -0500
    +++ new/src/java.base/share/classes/java/lang/invoke/TypeDescriptor.java	2018-12-06 12:19:11.666481666 -0500
    @@ -0,0 +1,187 @@
    +/*
    + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.  Oracle designates this
    + * particular file as subject to the "Classpath" exception as provided
    + * by Oracle in the LICENSE file that accompanied this code.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    + * or visit www.oracle.com if you need additional information or have any
    + * questions.
    + */
    +package java.lang.invoke;
    +
    +import java.util.List;
    +
    +/**
    + * An entity that has a field or method type descriptor
    + *
    + * @jvms 4.3.2 Field Descriptors
    + * @jvms 4.3.3 Method Descriptors
    + *
    + * @since 12
    + */
    +public interface TypeDescriptor {
    +    /**
    +     * Return the type descriptor string for this instance, which must be either
    +     * a field type descriptor (JVMS 4.3.2) or method type descriptor (JVMS 4.3.3).
    +     *
    +     * @return the type descriptor
    +     * @jvms 4.3.2 Field Descriptors
    +     * @jvms 4.3.3 Method Descriptors
    +     */
    +    String descriptorString();
    +
    +
    +    /**
    +     * An entity that has a field type descriptor
    +     *
    +     * @param <F> the class implementing {@linkplain TypeDescriptor.OfField}
    +     * @jvms 4.3.2 Field Descriptors
    +     * @since 12
    +     */
    +    interface OfField<F extends TypeDescriptor.OfField<F>> extends TypeDescriptor {
    +        /**
    +         * Does this field descriptor describe an array type?
    +         * @return whether this field descriptor describes an array type
    +         */
    +        boolean isArray();
    +
    +        /**
    +         * Does this field descriptor describe a primitive type?
    +         * @return whether this field descriptor describes a primitive type
    +         */
    +        boolean isPrimitive();
    +
    +        /**
    +         * If this field descriptor describes an array type, return
    +         * a descriptor for its component type, otherwise return {@code null}.
    +         * @return the component type, or {@code null} if this field descriptor does
    +         * not describe an array type
    +         */
    +        F componentType();
    +
    +        /**
    +         * Return a descriptor for the array type whose component type is described by this
    +         * descriptor
    +         * @return the descriptor for the array type
    +         */
    +        F arrayType();
    +    }
    +
    +
    +    /**
    +     * An entity that has a method type descriptor
    +     *
    +     * @param <F> the type representing field type descriptors
    +     * @param <M> the class implementing {@linkplain TypeDescriptor.OfMethod}
    +     * @jvms 4.3.2 Field Descriptors
    +     * @jvms 4.3.3 Method Descriptors
    +     * @since 12
    +     */
    +    interface OfMethod<F extends TypeDescriptor.OfField<F>, M extends TypeDescriptor.OfMethod<F, M>>
    +            extends TypeDescriptor {
    +
    +        /**
    +         * Return the number of parameters in the method type
    +         * @return the number of parameters
    +         */
    +        int parameterCount();
    +
    +        /**
    +         * Return a field descriptor describing the requested parameter of the method type
    +         * described by this descriptor
    +         * @param i the index of the parameter
    +         * @return a field descriptor for the requested parameter type
    +         * @throws IndexOutOfBoundsException if the index is outside the half-open
    +         * range {[0, parameterCount)}
    +         */
    +        F parameterType(int i);
    +
    +        /**
    +         * Return a field descriptor describing the return type of the method type described
    +         * by this descriptor
    +         * @return a field descriptor for the return type
    +         */
    +        F returnType();
    +
    +        /**
    +         * Return an array of field descriptors for the parameter types of the method type
    +         * described by this descriptor
    +         * @return field descriptors for the parameter types
    +         */
    +        F[] parameterArray();
    +
    +        /**
    +         * Return an immutable list of field descriptors for the parameter types of the method type
    +         * described by this descriptor
    +         * @return field descriptors for the parameter types
    +         */
    +        List<F> parameterList();
    +
    +        /**
    +         * Return a method descriptor that is identical to this one, except that the return
    +         * type has been changed to the specified type
    +         *
    +         * @param newReturn a field descriptor for the new return type
    +         * @throws NullPointerException if any argument is {@code null}
    +         * @return the new method descriptor
    +         */
    +        M changeReturnType(F newReturn);
    +
    +        /**
    +         * Return a method descriptor that is identical to this one,
    +         * except that a single parameter type has been changed to the specified type.
    +         *
    +         * @param index the index of the parameter to change
    +         * @param paramType a field descriptor describing the new parameter type
    +         * @return the new method descriptor
    +         * @throws NullPointerException if any argument is {@code null}
    +         * @throws IndexOutOfBoundsException if the index is outside the half-open
    +         * range {[0, parameterCount)}
    +         */
    +        M changeParameterType(int index, F paramType);
    +
    +        /**
    +         * Return a method descriptor that is identical to this one,
    +         * except that a range of parameter types have been removed.
    +         *
    +         * @param start the index of the first parameter to remove
    +         * @param end the index after the last parameter to remove
    +         * @return the new method descriptor
    +         *
    +         * @throws IndexOutOfBoundsException if {@code start} is outside the half-open
    +         * range {@code [0, parameterCount)}, or {@code end} is outside the closed range
    +         * {@code [0, parameterCount]}, or if {@code start > end}
    +         */
    +        M dropParameterTypes(int start, int end);
    +
    +        /**
    +         * Return a method descriptor that is identical to this one,
    +         * except that a range of additional parameter types have been inserted.
    +         *
    +         * @param pos the index at which to insert the first inserted parameter
    +         * @param paramTypes field descriptors describing the new parameter types
    +         *                   to insert
    +         * @return the new method descriptor
    +         * @throws NullPointerException if any argument is {@code null}
    +         * @throws IndexOutOfBoundsException if {@code pos} is outside the closed
    +         * range {[0, parameterCount]}
    +         */
    +        @SuppressWarnings("unchecked")
    +        M insertParameterTypes(int pos, F... paramTypes);
    +    }
    +}

References
-------

* webrev: http://cr.openjdk.java.net/~vromero/8210031/webrev.14/

* javadoc: http://cr.openjdk.java.net/~vromero/8210031/javadoc.21/overview-summary.html

* specdiff: http://cr.openjdk.java.net/~vromero/8210031/specdiff.11/overview-summary.html
Comments
> Some parts of the core API do contain disclaimers such as the following in java.lang.reflect.AnnotatedElement: > "The arrays returned by methods of this interface may be modified by callers without affecting the arrays returned to other callers." For the API in question here, the sibling method which returns a lists states the list is immutable so there is local contrast with the array-returning method which doesn't have such an explicit statement (although the implemented behavior is of course reasonable). This is exactly the sort of over-specification I was trying to avoid. In an imaginable future, one where we have frozen arrays, we would want to be able to return a frozen array; if the spec gave clients permission to mutate, we'd likely be stuck having to return a mutable array (and therefore a freshly copied array) each time, forever. Since there's no value in specifying that the caller can mutate the elements, and doing so would potentially destroy valuable options in the future, it seems best to promise nothing.
11-12-2018

>> The question is: given a ClassDesc for foo.Bar.Baz (nested type Baz inside of class Bar of package foo), how does one determine the enclosing type foo.Bar? > Currently, there is not a way to do this. That is because the construction of a descriptor for a nested class is information destroying; once you render to a descriptor, it's not clear whether A$B is simply a class called A$B, or a nested class B within A. We could provide some methods for parsing descriptors, but then they would have to guess about the semantics of $, which seems questionable -- better to let the user ask for the descriptor and do so. Similarly, we could retain the nested-ness based on how it was constructed (say, using nested), but then it would be problematic to create a ClassDesc from a descriptor. As a general comment, I'll often review an API to see if given an object, enough information is available from calling its public methods to construct an equivalent object. There are many cases where reconstructability is not reasonable or desirable, but it is easy to omit accidentally and can lead to moral hazards, like parsing unspecified toString output. As you've explained the intention of the API, direct model of JVM-level structures, I agree allow reconstruction of Java source-level semantics is not called for. Thanks for the explanation.
11-12-2018

>>DynamicConstantDesc.bootstrapArgs returning an array: is there a general disclaimer elsewhere in the API that the caller can modify the array, etc.? Same comment for MethodTypeDesc.parameterArray(). >I do not want to specify that a unique copy is made, since in the future (when we have frozen arrays) this will become an unnecessary mandate. There is no way currently to make an array unmodifiable, so I think it would be weird to talk about whether the user can modify the array. The current implementation is to make a defensive copy, but documenting that merely encourages callers to think that mutating the array is OK. I am at a loss for a good way to specify what you've got in mind here, which is: "we're careful enough that mutations of this array won't shoot anyone else in the foot, but only idiots would do that anyway. Some parts of the core API do contain disclaimers such as the following in java.lang.reflect.AnnotatedElement: "The arrays returned by methods of this interface may be modified by callers without affecting the arrays returned to other callers." For the API in question here, the sibling method which returns a lists states the list is immutable so there is local contrast with the array-returning method which doesn't have such an explicit statement (although the implemented behavior is of course reasonable).
11-12-2018

>>The question is: given a ClassDesc for foo.Bar.Baz (nested type Baz inside of class Bar of package foo), how does one determine the enclosing type foo.Bar? >Currently, there is not a way to do this. That is because the construction of a descriptor for a nested class is information destroying; once you render to a descriptor, it's not clear whether A$B is simply a class called A$B, or a nested class B within A. So presumably then if other language environments wanted to provide an interface to this API, for convenience they would provide their own factories to deal with language-specific desugaring/lowering processes.
10-12-2018

> VarHandle.{equals, hashCode, toString} OK > In TypeDescriptor.OfField.isPrimitive(), please clarify the handling of void. This is explicitly mentioned in the Class override and mentioned in the type-level docs of java.lang.constant.ClassDesc. I don't think the note in ClassDesc that "(The java.lang.constant APIs consider void to be a primitive type.)" has sufficient prominence/discoverability to handle all the cases of void-as-primitive in the API. > OK > For Class.componentType, the note "Equivalent to getComponentType()." could be represented as an @implSpec tag. > I consider this to be specification, not implementation specification (which is primarily relevant to default methods.) > For {Float, Double, Integer, Long, String}.describeConstable, contain a method declaration like: > public java.util.Optional describeConstable() > "Returns a nominal descriptor for this instance, which is the instance itself. " > Pedantically speaking, the return statement as written is not true; a wrapper around the object is not the same as the object. Please reword to convey the intended meaning, e.g. "... which is an Optional whose value is the this instance itself." > OK > The the package javadoc for java.lang.constant, please use the two-argument flavor of @link in > 51 * ... compute the value that it describes -- 52 * via {@link java.lang.constant.ConstantDesc#resolveConstantDesc(java.lang.invoke.MethodHandles.Lookup)}. > such as > 51 * ... compute the value that it describes -- 52 * via {@link java.lang.constant.ConstantDesc#resolveConstantDesc(java.lang.invoke.MethodHandles.Lookup) ConstantDesc.resolveConstantDesc}. > Likewise for the DynamicConstantDesc.ofCanonical reference. OK. > In a case like > 107 /** 108 * Returns a {@linkplain ClassDesc} given a descriptor string for a class, 109 * interface, array, or primitive type. 110 * 111 * @apiNote 112 * 113 * A field type descriptor string for a non-array type is either 114 * a one-letter code corresponding to a primitive type 115 * ({@code J,I,C,S,B,D,F,Z,V}), or the letter {@code L}, followed 116 * by the fully qualified binary name of a class, followed by {@code ;}. 117 * A field type descriptor for an array type is the character {@code \[} 118 * followed by the field descriptor for the component type. Examples of 119 * valid type descriptor strings include {@code Ljava/lang/String;}, {@code I}, 120 * {@code \[I}, {@code V}, {@code \[Ljava/lang/String;}, etc. 121 * for more detail. 122 * 123 * @param descriptor a field descriptor string 124 * @return a {@linkplain ClassDesc} describing the desired class 125 * @throws NullPointerException if any argument is {@code null} 126 * @throws IllegalArgumentException if the name string is not in the 127 * correct format 128 * @jvms 4.3.2 Field Descriptors 129 */ 130 static ClassDesc ofDescriptor(String descriptor) > I think it would be clearly if quotes were put around the strings.E.g. > 115 * ({@code J,I,C,S,B,D,F,Z,V}), or the letter "{@code L}", followed 116 * by the fully qualified binary name of a class, followed by "{@code ;}". OK > Line 121 > 121 * for more detail. > seems to be dangling. OK > For ClassDesc.nested, I think the javadoc > default ClassDesc nested​(String nestedName) > Returns a ClassDesc for a nested class of the class or interface type described by this ClassDesc. > would be improved by the addition of an API note or similar "If this ClassDesc represents foo.Bar, class Bar of package foo, to created the a ClassDesc for the nested class foo.Bar.Baz, use ..." OK > DynamicConstantDesc.bootstrapArgs returning an array: is there a general disclaimer elsewhere in the API that the caller can modify the array, etc.? > Same comment for MethodTypeDesc.parameterArray(). > I do not want to specify that a unique copy is made, since in the future (when we have frozen arrays) this will become an unnecessary mandate. There is no way currently to make an arry unmodifiable, so I think it would be weird to talk about whether the user can modify the array. The current implementation is to make a defensive copy, but documenting that merely encourages callers to think that mutating the array is OK. I am at a loss for a good way to specify what you've got in mind here, which is: "we're careful enough that mutations of this array won't shoot anyone else in the foot, but only idiots would do that anyway."
10-12-2018

> The question is: given a ClassDesc for foo.Bar.Baz (nested type Baz inside of class Bar of package foo), how does one determine the enclosing type foo.Bar? Currently, there is not a way to do this. That is because the construction of a descriptor for a nested class is information destroying; once you render to a descriptor, it's not clear whether `A$B` is simply a class called `A$B`, or a nested class `B` within `A`. We could provide some methods for parsing descriptors, but then they would have to guess about the semantics of `$`, which seems questionable -- better to let the user ask for the descriptor and do so. Similarly, we could retain the nested-ness based on how it was constructed (say, using `nested`), but then it would be problematic to create a `ClassDesc` from a descriptor. The bottom line here is that this API models how classfiles describe constants; the semantics of inner-ness is up there at the language level, where the classfile mostly ignores. The `nested()` factory is largely a convenience for callers, but the intent is to normalize nominal descriptors down to the information that is retained in the classfile, and erase other information. (A similar thing happens, for example, with the "varargs" bit of method handles; there's no way we can statically track it, so we don't try.)
08-12-2018

Voting to Approve with comments and one question. The comments are non-normative changes I think should be made before the API is pushed. The question is: given a ClassDesc for foo.Bar.Baz (nested type Baz inside of class Bar of package foo), how does one determine the enclosing type foo.Bar? Basically, is there an analouge for the Class.getEnclosingClass (or similar) or javax.lang.model.element.TypeElement.getEnclosingElement method? The comments: VarHandle.{equals, hashCode, toString} In TypeDescriptor.OfField.isPrimitive(), please clarify the handling of void. This is explicitly mentioned in the Class override and mentioned in the type-level docs of java.lang.constant.ClassDesc. I don't think the note in ClassDesc that "(The java.lang.constant APIs consider void to be a primitive type.)" has sufficient prominence/discoverability to handle all the cases of void-as-primitive in the API. For Class.componentType, the note "Equivalent to getComponentType()." could be represented as an @implSpec tag. For {Float, Double, Integer, Long, String}.describeConstable, contain a method declaration like: public java.util.Optional<Float> describeConstable() "Returns a nominal descriptor for this instance, which is the instance itself. " Pedantically speaking, the return statement as written is not true; a wrapper around the object is not the same as the object. Please reword to convey the intended meaning, e.g. "... which is an Optional whose value is the this instance itself." The the package javadoc for java.lang.constant, please use the two-argument flavor of @link in 51 * ... compute the value that it describes -- 52 * via {@link java.lang.constant.ConstantDesc#resolveConstantDesc(java.lang.invoke.MethodHandles.Lookup)}. such as 51 * ... compute the value that it describes -- 52 * via {@link java.lang.constant.ConstantDesc#resolveConstantDesc(java.lang.invoke.MethodHandles.Lookup) ConstantDesc.resolveConstantDesc}. Likewise for the DynamicConstantDesc.ofCanonical reference. In a case like 107 /** 108 * Returns a {@linkplain ClassDesc} given a descriptor string for a class, 109 * interface, array, or primitive type. 110 * 111 * @apiNote 112 * 113 * A field type descriptor string for a non-array type is either 114 * a one-letter code corresponding to a primitive type 115 * ({@code J,I,C,S,B,D,F,Z,V}), or the letter {@code L}, followed 116 * by the fully qualified binary name of a class, followed by {@code ;}. 117 * A field type descriptor for an array type is the character {@code [} 118 * followed by the field descriptor for the component type. Examples of 119 * valid type descriptor strings include {@code Ljava/lang/String;}, {@code I}, 120 * {@code [I}, {@code V}, {@code [Ljava/lang/String;}, etc. 121 * for more detail. 122 * 123 * @param descriptor a field descriptor string 124 * @return a {@linkplain ClassDesc} describing the desired class 125 * @throws NullPointerException if any argument is {@code null} 126 * @throws IllegalArgumentException if the name string is not in the 127 * correct format 128 * @jvms 4.3.2 Field Descriptors 129 */ 130 static ClassDesc ofDescriptor(String descriptor) I think it would be clearly if quotes were put around the strings.E.g. 115 * ({@code J,I,C,S,B,D,F,Z,V}), or the letter "{@code L}", followed 116 * by the fully qualified binary name of a class, followed by "{@code ;}". Line 121 121 * for more detail. seems to be dangling. For ClassDesc.nested, I think the javadoc default ClassDesc nested​(String nestedName) Returns a ClassDesc for a nested class of the class or interface type described by this ClassDesc. would be improved by the addition of an API note or similar "If this ClassDesc represents foo.Bar, class Bar of package foo, to created the a ClassDesc for the nested class foo.Bar.Baz, use ..." As a code review comment, the lists to Collection, List, Set, and Map in ConstantDescs.{CD_Collection, CD_List, CD_Set, and CD_Map} are *not* being generated as links in the provided javadoc. Please make sure this is correct in a docs build of the repo. DynamicConstantDesc.bootstrapArgs returning an array: is there a general disclaimer elsewhere in the API that the caller can modify the array, etc.? Same comment for MethodTypeDesc.parameterArray().
08-12-2018

Thank you [~vromero]!
07-12-2018

[~dholmes] I have renamed the ClassDesc::inner methods to ::nested, all links and the specification section has been updated
06-12-2018

FWIW, old relevant blog entry: https://blogs.oracle.com/darcy/nested,-inner,-member,-and-top-level-classes
06-12-2018

[~briangoetz] In that case the name "inner" is wrong, it should be "nested".
06-12-2018

[~dholmes] Any sort of nested class. `Foo$Bar`.
06-12-2018

Is ClassDesc.inner() really limited to inner classes (non-static named nested types), or can other forms of nested types be created?
06-12-2018

> Throughout, should "clazz" be used as the go-to parameter name for ClassDesc rather than something like "classDesc"? Basically, is conflating the usual naming for a java.lang.Class and its descriptor okay? > No. Those that are part of (class, name, descriptor) tuples should be `owner`; others should be `classDesc`. Fixed. > In the package javadoc of java.lang.constant, in "The subtypes of of ConstantDesc describe various kinds of constant values. For each type of loadable constant pool entry defined in JVMS 4.4, there is a corresponding subtype of ConstantDesc: ClassDesc, MethodTypeDesc, DirectMethodHandleDescImpl, String, Integer, Long, Float, Double, and DynamicConstantDesc." "DirectMethodHandleDescImpl" should be replaced by "DirectMethodHandleDesc." Fixed. > "When a bytecode-writing API encounters a ConstantDesc, it should examine it to see which of these types it is, cast it, extract its nominal information, and generate the corresponding entry to the constant pool." > Longer-term is pattern matching the envisioned cast-free way to program against this API? I assume a visitor pattern was considered and rejected. Yes, eventually one will be able to pattern match on these. > While java.lang.constant.Constable meets the defintition of a functional interface, it doesn't seem like it would often be used as one as I agree there is not a need to annotate it with @FunctionalInterface. Likewise for java.lang.invoke.TypeDesciptor. > Correct. These are not intended as behavior objects; they are more traditional interfaces which happen to have a single method (like Comparable). > Why is Character.UnicodeScript rather than java.lang.Charactrer listed as implementing Constable in the .08 specdiff? Is the specdiff and webrev out of sync on this point? Character does not have a native form in the constant pool, and we have not (yet) exposed condy bootstraps for the remaining primitive types (char, short, byte, boolean). Character.UnicodeScript is Constable because it's an Enum; all Enums are Constable. > The java.lang types modeling character, boolean, short, etc. are_not_Constable since their constant pool entries use ints? Should java.lang.Short be Constable with a public java.util.Optional<Integer> describeConstable() > method? It could be, and this could be added later. Constable support is more properly the next phase of this story, which is better constant folding (JEP 303). That's when Constable-ness will be critically important, and we will re-review JDK types for which need to be Constable as part of that story. > Let me check my understanding: the ClassDesc.innter methods are basically a way to get "$" into the right location in the name used in the class file, right? > Correct. > Each of > default ClassDesc inner​(String firstInnerName, String... moreInnerNames) and > default ClassDesc inner​(String innerName) > > could be written in term of the other given the proper split/join logic for the names, correct? As could `ClassDesc.of(String className)`. They are all front-ends (with additional name validation) to `ClassDesc.ofDescriptor(String descriptor)`. > In ConstantDescs, the CD_List.{Collection, List, Set, Map} constants should be proper links to java.util.{List, Set, Map}. The webrev looks correct, but the specdiff doesn't display links for these types. (There is a name collision with "java.util.List" and "java.awt.List" although java.util.List is implied in this context of course.) I believe they are: ``` /** {@link ClassDesc} representing {@link List} */ public static final ClassDesc CD_List = ClassDesc.of("java.util.List"); ``` > Presumnably "DirectMethodHandleDesc" is meant rather thn "DirectMethodHandleDescImpl". Fixed. > For the BSM constants in ConstantDescs, please use the two-argument form of the {@link} tag to control the displayed text. In other words, I don't think displying the method argument lists is helpful in this context. > Fixed. >DirectMethodHandleDesc.methodName() > Does the behavior in case of a constructor need to be specified? > Added. > For DirectMethodHandleDesc.Kind.valueOf​, IIRC nest mates or other feature in a recent JDK release increased the number of cases where invokeinterface can be used as opposed to relying on one of the other invoke instructions (for private methods IIRC). Is this listing current with those changes? > Yes, though in the future, some of the distinctions may no longer be releavant, in which case (say) SPECIAL and INTERFACE_SPECIAL will become synonyms. > DynamicCallSiteDesc > Typo: Returns a MethodHandleDesc_descripbing_the bootstrap method for the invokedynamic. > Fixed. > Please add explict javadoc for DynamicCallSiteDesc.{toString, equals} "An informative string representation ..." , "Obeys the general equals contract", etc. Was already there for equals; added for toString(). > DynamicConstantDesc > For DynamicConstantDesc​, > bootstrapMethod - a DirectMethodHandleDescImpl describing the bootstrap method for the constant > Is DirectMethodHandleDes without_Impl_meant here? Yes, fixed. > Please review uses of "DirectMethodHandleDescImpl" in the spec. Refactoring error. Fixed. > DynamicConstantDesc.bootstrapArgs on returning an array, is there a disclaimer somewhere about what happens if the user modifies the array? > No; the array is cloned before being returned. Callers are free to scribble at will. > If DynamicConstantDesc is meant to be subclassed, I'd recommend having a nominal override for the javadoc of the hashCode method as well as toString. > Equals and hashCode are final. Can you be more specific about what you want here? > In MethodTypeDesc, rather than a class-level comment like > "Two MethodTypeDesc objects are considered Object.equals(Object) if they have the same arity, their return types are equal, and each pair of corresponding parameter types are equal." > I think this would work better as javadoc for an equals method on the interface. For comparison, see javax.lang.model.element.Element.equals. > > VarHandle.VarHandleDesc: overrides without overridden javadoc. > VarHandle.{equals, hashCode} please add javadoc. > In TypeDescriptor.OfMethod, how problematic is that that F[] parameterArray() returns an array of a type parameter? Given the goals for these types (that they abstracts over both the live and nominal forms of Class/MethodType), this is what we want. Enum.EnumDesc: please add javadoc overrrides.
04-12-2018

Please make sure to run any subsequent specdiffs based on a javadoc build where the @jvms tags are present in the output. Not all of these comments/question would merit a re-spin the CSR, but please review the list. Throughout, should "clazz" be used as the go-to parameter name for ClassDesc rather than something like "classDesc"? Basically, is conflating the usual naming for a java.lang.Class and its descriptor okay? In the package javadoc of java.lang.constant, in "The subtypes of of ConstantDesc describe various kinds of constant values. For each type of loadable constant pool entry defined in JVMS 4.4, there is a corresponding subtype of ConstantDesc: ClassDesc, MethodTypeDesc, DirectMethodHandleDescImpl, String, Integer, Long, Float, Double, and DynamicConstantDesc." "DirectMethodHandleDescImpl" should be replaced by "DirectMethodHandleDesc." "When a bytecode-writing API encounters a ConstantDesc, it should examine it to see which of these types it is, cast it, extract its nominal information, and generate the corresponding entry to the constant pool." Longer-term is pattern matching the envisioned cast-free way to program against this API? I assume a visitor pattern was considered and rejected. While java.lang.constant.Constable meets the defintition of a functional interface, it doesn't seem like it would often be used as one as I agree there is not a need to annotate it with @FunctionalInterface. Likewise for java.lang.invoke.TypeDesciptor. Why is Character.UnicodeScript rather than java.lang.Charactrer listed as implementing Constable in the .08 specdiff? Is the specdiff and webrev out of sync on this point? The java.lang types modeling character, boolean, short, etc. are *not* Constable since their constant pool entries use ints? Should java.lang.Short be Constable with a public java.util.Optional<Integer> describeConstable() method? Let me check my understanding: the ClassDesc.innter methods are basically a way to get "$" into the right location in the name used in the class file, right? Each of default ClassDesc inner​(String firstInnerName, String... moreInnerNames) and default ClassDesc inner​(String innerName) could be written in term of the other given the proper split/join logic for the names, correct? In ConstantDescs, the CD_List.{Collection, List, Set, Map} constants should be proper links to java.util.{List, Set, Map}. The webrev looks correct, but the specdiff doesn't display links for these types. (There is a name collision with "java.util.List" and "java.awt.List" although java.util.List is implied in this context of course.) In CD_DirectMethodHandleDesc public static final ClassDesc CD_DirectMethodHandleDesc ClassDesc representing DirectMethodHandleDescImpl Presumnably "DirectMethodHandleDesc" is meant rather thn "DirectMethodHandleDescImpl". For the BSM constants in ConstantDescs, please use the two-argument form of the {@link} tag to control the displayed text. In other words, I don't think displying the method argument lists is helpful in this context. DirectMethodHandleDesc.methodName() Does the behavior in case of a constructor need to be specified? For DirectMethodHandleDesc.Kind.valueOf​, IIRC nest mates or other feature in a recent JDK release increased the number of cases where invokeinterface can be used as opposed to relying on one of the other invoke instructions (for private methods IIRC). Is this listing current with those changes? DynamicCallSiteDesc Typo: Returns a MethodHandleDesc *descripbing* the bootstrap method for the invokedynamic. Please add explict javadoc for DynamicCallSiteDesc.{toString, equals} "An informative string representation ..." , "Obeys the general equals contract", etc. DynamicConstantDesc For DynamicConstantDesc​, bootstrapMethod - a DirectMethodHandleDescImpl describing the bootstrap method for the constant Is DirectMethodHandleDes without *Impl* meant here? Please review uses of "DirectMethodHandleDescImpl" in the spec. DynamicConstantDesc.bootstrapArgs on returning an array, is there a disclaimer somewhere about what happens if the user modifies the array? If DynamicConstantDesc is meant to be subclassed, I'd recommend having a nominal override for the javadoc of the hashCode method as well as toString. In MethodTypeDesc, rather than a class-level comment like "Two MethodTypeDesc objects are considered Object.equals(Object) if they have the same arity, their return types are equal, and each pair of corresponding parameter types are equal." I think this would work better as javadoc for an equals method on the interface. For comparison, see javax.lang.model.element.Element.equals. VarHandle.VarHandleDesc: overrides without overridden javadoc. VarHandle.{equals, hashCode} please add javadoc. In TypeDescriptor.OfMethod, how problematic is that that F[] parameterArray() returns an array of a type parameter? Enum.EnumDesc: please add javadoc overrrides.
04-12-2018

My sense is that this API will need at least a round or two of further polishing before being ready to be pushed, but the API is mature enough for the corresponding JEP to go through the proposed to target phase.
21-11-2018

Next batch of comments and reactions to earlier replies. For F-bounds, there are certainly cases where they are useful, but sometimes not worth the extra complexity. For example, java.lang.reflect.TypeVariable would likely have been better without them. There ware way the F-found in java.lang.Enum makes it more awkward to program over any enum since Enum<?> fieldToHoldArbitraryEnum =... doesn't really do what you want. The types in java.lang.constant which override Object methods should provide some javadoc of their own, even if just the "Obeys the general contract of $METHOD". In various places the API makes reference to specific JVMS sections. Those numbers are mostly stable. I'd prefer to have these in-line JVMS references augmented (or in some cases replaced) by uses of the "@jvms" tag, which is analogous to the @jls tag and used elsewhere in the code base. Such @jvms tags should also include the section name to make fix-ups after any future renumberings easier. Some more specific comments: In java.lang.Class "public Class<?> arrayType() Create a Class for an array type whose component type is described by this ClassDesc. " The inherited javadoc is a bit odd in the context of java.lang.Class. Is "described by this Class" meant rather than "described by this ClassDesc"? I would prefer if one of Class.getComponentType and Class.componentType were specified in terms of the other. The default methods in java.lang.constant.ClassDesc would be improved with some @implSpec information about the default implementations, especially if one than one implementation is intended. In one of the @param tags of DynamicConstantDesc.ofCanonical "bootstrapMethod - a DirectMethodHandleDescImpl describing the bootstrap method for the constant " presumably "a DirectMethodHandleDesc describing..." is meant instead. DynamicConstantDesc.constantName: capitalization typo: "Returns The name that would appear in the NameAndType operand of the LDC for this constant " DynamicConstantDesc.bootstrapArgsList Should anything be said about the nature of the returned list? Same question for TypeDescriptor.OfMethod.parameterList and similar occurrences. MethodHandleDesc.ofField " kind - the kind of the method handle to be described; must be one of GETTER, SETTER, STATIC_GETTER, or STATIC_SETTER " If kind is something else, is an exception thrown? TypeDescriptor.OfMethod.dropParameterTypes Does start < end have to be true? Based on the rendered html, there looks to be a formatting issues in the @throws clause.
21-11-2018

> For F-bounds, there are certainly cases where they are useful, but sometimes not worth the extra complexity. For example, java.lang.reflect.TypeVariable would likely have been better without them. There ware way the F-found in java.lang.Enum makes it more awkward to program over any enum since Enum fieldToHoldArbitraryEnum =... doesn't really do what you want. In this case, the F-bound is needed to express the desired semantic constraints. For example, we expect that when a TypeDescriptor.OfField is asked "what is your array type", it gives the answer in the same form it is in (Class or ClassDesc.) Having a Class returne a ClassDesc from `arrayType()` would not be useful to any client. Will address the remaining issues in a patch, soon.
21-11-2018

> Why use fields in `DirectMethodHandleDesc.Kind`? Kind here is an enum; it enumerates the method handle invocation modes currently specified by the JVMS. While its possible these will be extended in the future (and enums can do that), this seems a pretty stable list. > Why can `displayName()` throw ISE? This will only happen if there is a bug in a subclass. Eventually, we will likely seal this interface (and then probably push this method down into the known subclasses.) > What is the evolution path for new kinds of constants? When a new constant pool form is added to the classfile format, we will create a corresponding subtype (class or interface, depending) of `ConstantDesc` to model it, and update the documentation that advises classfile parsing/generation APIs (and other APIs that use `ConstantDesc` to model constants) that as of a given classfile version, they should be prepared to encounter / generate the new subtype of `ConstantDesc`. Because the classfile is heavily versioned, it is reasonable to expect those that deal directly in the classfile format to periodically adjust their model.
13-11-2018

Addressing some more review comments (but not all of them yet): > Is unqualified name the same thing as simple name? Simple name is a term from the JLS; Unqualified name is a term from the JVMS. This class models a classfile entity and works in terms of classfile descriptors, so the JVMS terminology is preferable. For clarity, though, I've added "(simple name)" after "unqualified name" for users who are familiar with the latter term. > Are the F-bounds needed in `TypeDescriptor.OfField`? Yes. The purpose of this class is to abstract over the live (`java.lang.Class`) and nominal (`java.lang.constant.ClassDesc`) descriptions of a single type. Since this interface has methods that return new type descriptions, the use of F-bounds constrains them to return the _same kind_ of type description. So `ClassDesc::arrayType` will return a `ClassDesc`, but `Class::arrayType` will return a `Class`. > Why does `TypeDescriptor.OfMethod` contain both `parameterTypes()` and `parameterList()`? As with the previous, the purpose of this class is to abstract over the live (`java.lang.invoke.MethodType`) and nominal (`java.lang.constant.MethodTypeDesc`) descriptions of a method descriptor. `MethodType` already contains both of these methods -- which are both useful in different situations. Therefore, it made sense for MT's nominal counterpart (MTDesc) to have these methods, and similarly for the extracted interface to cover both of them.
13-11-2018

Remaining code review comments; > Clarify “class or interface type” in ClassDesc::of factories Will do. > Provide examples of descriptors in `ClassDesc::ofDescriptor`` Will do. > Consider returning null from componentType() This is already done. > Consider returning empty string for package when no package / primitive Will do. > Clarify that void is treated as a primitive type Will do. > Clarify treatment of the unnamed package? Will do. > Document equals() behavior Will do. Will provide a patch soon that covers all these.
13-11-2018

I've made another pass over the API and have some additional comments. I expect at least one more and possibly several more passes will be needed before I'm comfortable approving the API. Having some version of the spec changes included in the proposal does not remove the utility of a specdiff or webev also being available, even as attachments :-) The comments on the draft: + /** + * Create a {@linkplain ClassDesc} given a package name and an unqualified + * class name. + * + * @param packageName the package name (dot-separated) + * @param className the unqualified class name + * @return a {@linkplain ClassDesc} describing the desired class + * @throws NullPointerException if any argument is {@code null} + * @throws IllegalArgumentException if the package name or class name are + * not in the correct format + */ And what about unnamed package? + /** + * Create a {@linkplain ClassDesc} for an inner class of the class or + * interface type described by this {@linkplain ClassDesc}. + * + * @param innerName the unqualified name of the inner class + * @return a {@linkplain ClassDesc} describing the inner class + * @throws NullPointerException if any argument is {@code null} + * @throws IllegalStateException if this {@linkplain ClassDesc} does not + * describe a class or interface type + */ + default ClassDesc inner(String innerName) { + validateMemberName(innerName); Is what is meant instead of "unqualified name" the concept "simple name" (https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.5.5.1)? Whether or not void is treated as a primitive type by the new API should be more directly addressed in the spec. For the purposes of core reflection void is a primitive type but it is not a type in the JLS.
09-11-2018

Added some comments from [~briangoetz]: > Should the static factories have any notation of modules? No. This API models symbolic references of the kind that would appear in the constant pool of a class. The symbolic references in a classfile are purely nominal; in order to turn those into a live type, some sort of lookup context is required, which subsumes class loading context, access control context, etc. So all nominal references are implicitly qualified with "same class loading and access control context as me." The same is true for the nominal descriptors here. > I'd prefer to see the String -> ClassRef factory discussing how primitives and void and handled more explicitly than just referring to a JVMS chapter. Are you speaking specifically of ClassDesc::ofDescriptor?
06-11-2018

This CSR will require one or more additional iterations before being approved. Structurally, some persistent form of the proposed spec changes will need to be associated with the CSR. Links to cr.openjdk are convenient and appreciated, but not sufficient for archival purposes. It would be helpful to include up-to-date overview information from the JEP in this CSR. More detailed comments: Do we really want f-bounds in interface OfField<F extends TypeDescriptor.OfField<F>> extends TypeDescriptor What about void? Why are both of these methods present OfMethod: 113 /** 114 * Return an array of field descriptors for the parameter types of the method type 115 * described by this descriptor 116 * @return field descriptors for the parameter types 117 */ 118 F[] parameterArray(); 119 120 /** 121 * Return a list of field descriptors for the parameter types of the method type 122 * described by this descriptor 123 * @return field descriptors for the parameter types 124 */ In DirectMethodHandleDesc.Kind, I strongly recommend the public fields be public methods instead. ClassDesc.java module name? Not very friendly that default String displayName() { can throw an IllegalStateException java/lang/constant/package-info.java What is the evolution path when new kinds of constants are added, or does dynamic constant cover all future bases?
06-11-2018

From an initial skim over the finalized CSR: * The javadoc on new methods is missing @since tags * As a code review comment, in VarHandle.equals, it would be helpful to at least have comment explicitly noting why an instanceof check is not needed. * In additional to helpful links, some kind of attached or in-line version of the spec / webrev is needed as well. I expect to have more substantive comments on subsequent reviews.
02-11-2018

Moving to Provisional. Before the request is Finalized, the full javadoc needs to be attached in some way to the CSR, specdiff, webrev, etc. A specdiff would be a good complement to a webrev for a large request like this one. A few comments and questions around ClassRef. Should the static factories have any notation of modules? (At least in some contexts, one can have types with the same full-qualified name living in different modules.) I'd prefer to see the String -> ClassRef factory discussing how primitives and void and handled more explicitly than just referring to a JVMS chapter. 204 /** 205 * Returns the component type of this {@linkplain ClassDesc}, if it describes 206 * an array type. 207 * 208 * @return a {@linkplain ClassDesc} describing the component type 209 * @throws IllegalStateException if this {@linkplain ClassDesc} does not 210 * describe an array type 211 */ This method and several other methods seem a bit punitive in their exception handling as opposed to returning null or being redeclared to return Optional<Foo>. One could debate whether or not IllegalArgumentException was a more appropriate exception here; I haven't looked over if IllegalArgumentException is used elsewhere for conditions on the receiver. 219 /** 220 * Returns the package name of this {@linkplain ClassDesc}, if it describes 221 * a class or interface type. 222 * 223 * @return the package name, or the empty string if no package 224 * @throws IllegalStateException if this {@linkplain ClassDesc} does not 225 * describe a class or interface type 226 */ 227 default String packageName() Pedantically, wouldn't it be more correct to say an empty string if the class or interface is in a default package rather than no package? For types like ClassDesc, I recommend putting some discussions of equals(Object) requirements in the interface definitions. See javax.lang.model.element.Element.equals as one possible model. As a code review comment, we've stopped placing @author tags in new code.
14-05-2018