CSR :
|
|
Duplicate :
|
|
Relates :
|
|
Relates :
|
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
|