8215300: additional changes to constants API
authorvromero
Thu, 13 Dec 2018 10:35:09 -0500
changeset 53019 4ddd3c410a85
parent 53018 8bf9268df0e2
child 53020 c403f39ec349
8215300: additional changes to constants API Reviewed-by: goetz
src/java.base/share/classes/java/lang/Double.java
src/java.base/share/classes/java/lang/Float.java
src/java.base/share/classes/java/lang/Integer.java
src/java.base/share/classes/java/lang/Long.java
src/java.base/share/classes/java/lang/String.java
src/java.base/share/classes/java/lang/constant/ClassDesc.java
src/java.base/share/classes/java/lang/constant/Constable.java
src/java.base/share/classes/java/lang/constant/ConstantUtils.java
src/java.base/share/classes/java/lang/constant/package-info.java
src/java.base/share/classes/java/lang/invoke/TypeDescriptor.java
src/java.base/share/classes/java/lang/invoke/VarHandle.java
test/jdk/java/lang/constant/ClassDescTest.java
--- a/src/java.base/share/classes/java/lang/Double.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/Double.java	Thu Dec 13 10:35:09 2018 -0500
@@ -1077,8 +1077,8 @@
     }
 
     /**
-     * Returns a nominal descriptor for this instance, which is the instance
-     * itself.
+     * Returns an {@link Optional} containing the nominal descriptor for this
+     * instance, which is the instance itself.
      *
      * @return an {@link Optional} describing the {@linkplain Double} instance
      * @since 12
--- a/src/java.base/share/classes/java/lang/Float.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/Float.java	Thu Dec 13 10:35:09 2018 -0500
@@ -989,8 +989,8 @@
     }
 
     /**
-     * Returns a nominal descriptor for this instance, which is the instance
-     * itself.
+     * Returns an {@link Optional} containing the nominal descriptor for this
+     * instance, which is the instance itself.
      *
      * @return an {@link Optional} describing the {@linkplain Float} instance
      * @since 12
--- a/src/java.base/share/classes/java/lang/Integer.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/Integer.java	Thu Dec 13 10:35:09 2018 -0500
@@ -1838,8 +1838,8 @@
     }
 
     /**
-     * Returns a nominal descriptor for this instance, which is the instance
-     * itself.
+     * Returns an {@link Optional} containing the nominal descriptor for this
+     * instance, which is the instance itself.
      *
      * @return an {@link Optional} describing the {@linkplain Integer} instance
      * @since 12
--- a/src/java.base/share/classes/java/lang/Long.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/Long.java	Thu Dec 13 10:35:09 2018 -0500
@@ -1967,8 +1967,8 @@
     }
 
     /**
-     * Returns a nominal descriptor for this instance, which is the instance
-     * itself.
+     * Returns an {@link Optional} containing the nominal descriptor for this
+     * instance, which is the instance itself.
      *
      * @return an {@link Optional} describing the {@linkplain Long} instance
      * @since 12
--- a/src/java.base/share/classes/java/lang/String.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/String.java	Thu Dec 13 10:35:09 2018 -0500
@@ -3545,8 +3545,8 @@
     }
 
     /**
-     * Returns a nominal descriptor for this instance, which is the instance
-     * itself.
+     * Returns an {@link Optional} containing the nominal descriptor for this
+     * instance, which is the instance itself.
      *
      * @return an {@link Optional} describing the {@linkplain String} instance
      * @since 12
--- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java	Thu Dec 13 10:35:09 2018 -0500
@@ -112,13 +112,13 @@
      *
      * 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 [}
+     * ({@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.
+     * valid type descriptor strings include {@code "Ljava/lang/String;"}, {@code "I"},
+     * {@code "[I"}, {@code "V"}, {@code "[Ljava/lang/String;"}, etc.
+     * See JVMS 4.3.2 ("Field Descriptors") for more detail.
      *
      * @param descriptor a field descriptor string
      * @return a {@linkplain ClassDesc} describing the desired class
@@ -126,9 +126,15 @@
      * @throws IllegalArgumentException if the name string is not in the
      * correct format
      * @jvms 4.3.2 Field Descriptors
+     * @jvms 4.4.1 The CONSTANT_Class_info Structure
      */
     static ClassDesc ofDescriptor(String descriptor) {
         requireNonNull(descriptor);
+        int depth = ConstantUtils.arrayDepth(descriptor);
+        if (depth > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
+            throw new IllegalArgumentException(String.format("Cannot create an array type descriptor with more than %d dimensions",
+                    ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS));
+        }
         return (descriptor.length() == 1)
                ? new PrimitiveClassDescImpl(descriptor)
                : new ReferenceClassDescImpl(descriptor);
@@ -139,8 +145,15 @@
      * is described by this {@linkplain ClassDesc}.
      *
      * @return a {@linkplain ClassDesc} describing the array type
+     * @throws IllegalStateException if the resulting {@linkplain ClassDesc} would have an array rank of greater than 255
+     * @jvms 4.4.1 The CONSTANT_Class_info Structure
      */
     default ClassDesc arrayType() {
+        int depth = ConstantUtils.arrayDepth(descriptorString());
+        if (depth >= ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
+            throw new IllegalStateException(String.format("Cannot create an array type descriptor with more than %d dimensions",
+                    ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS));
+        }
         return arrayType(1);
     }
 
@@ -150,11 +163,14 @@
      *
      * @param rank the rank of the array
      * @return a {@linkplain ClassDesc} describing the array type
-     * @throws IllegalArgumentException if the rank is zero or negative
+     * @throws IllegalArgumentException if the rank is less than zero or if the rank of the resulting array type is
+     * greater than 255
+     * @jvms 4.4.1 The CONSTANT_Class_info Structure
      */
     default ClassDesc arrayType(int rank) {
-        if (rank <= 0)
-            throw new IllegalArgumentException("rank: " + rank);
+        int currentDepth = ConstantUtils.arrayDepth(descriptorString());
+        if (rank <= 0 || currentDepth + rank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS)
+            throw new IllegalArgumentException("rank: " + currentDepth + rank);
         return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString());
     }
 
@@ -162,6 +178,12 @@
      * Returns a {@linkplain ClassDesc} for a nested class of the class or
      * interface type described by this {@linkplain ClassDesc}.
      *
+     * @apiNote
+     *
+     * Example: If descriptor {@code d} describes the class {@code java.util.Map}, a
+     * descriptor for the class {@code java.util.Map.Entry} could be obtained
+     * by {@code d.nested("Entry")}.
+     *
      * @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}
--- a/src/java.base/share/classes/java/lang/constant/Constable.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/constant/Constable.java	Thu Dec 13 10:35:09 2018 -0500
@@ -65,8 +65,9 @@
  */
 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.
+     * Returns an {@link Optional} containing the 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.
--- a/src/java.base/share/classes/java/lang/constant/ConstantUtils.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/constant/ConstantUtils.java	Thu Dec 13 10:35:09 2018 -0500
@@ -37,6 +37,7 @@
     /** an empty constant descriptor */
     public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0];
     static final Constable[] EMPTY_CONSTABLE = new Constable[0];
+    static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255;
 
     private static final Set<String> pointyNames = Set.of("<init>", "<clinit>");
 
--- a/src/java.base/share/classes/java/lang/constant/package-info.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/constant/package-info.java	Thu Dec 13 10:35:09 2018 -0500
@@ -49,7 +49,7 @@
  * 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)}.
+ * via {@link java.lang.constant.ConstantDesc#resolveConstantDesc(java.lang.invoke.MethodHandles.Lookup) ConstantDesc.resolveConstantDesc}.
  * 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.
@@ -68,7 +68,7 @@
  * 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[])},
+ * {@link java.lang.constant.DynamicConstantDesc#ofCanonical(DirectMethodHandleDesc, java.lang.String, ClassDesc, ConstantDesc[]) DynamicConstantDesc.ofCanonical},
  * 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}.
--- a/src/java.base/share/classes/java/lang/invoke/TypeDescriptor.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/TypeDescriptor.java	Thu Dec 13 10:35:09 2018 -0500
@@ -61,7 +61,8 @@
         boolean isArray();
 
         /**
-         * Does this field descriptor describe a primitive type?
+         * Does this field descriptor describe a primitive type (including void.)
+         *
          * @return whether this field descriptor describes a primitive type
          */
         boolean isPrimitive();
--- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java	Thu Dec 13 10:35:09 2018 -0500
@@ -1864,6 +1864,16 @@
         }
     }
 
+    /**
+     * Compare this {@linkplain VarHandle} with another object for equality.
+     * Two {@linkplain VarHandle}s are considered equal if they both describe the
+     * same instance field, both describe the same static field, both describe
+     * array elements for arrays with the same component type, or both describe
+     * the same component of an off-heap structure.
+     *
+     * @param o the other object
+     * @return Whether this {@linkplain VarHandle} is equal to the other object
+     */
     @Override
     public final boolean equals(Object o) {
         if (this == o) return true;
@@ -1883,6 +1893,12 @@
 
     abstract int internalHashCode();
 
+    /**
+     * Returns a compact textual description of this {@linkplain VarHandle},
+     * including the type of variable described, and a description of its coordinates.
+     *
+     * @return A compact textual description of this {@linkplain VarHandle}
+     */
     @Override
     public final String toString() {
         return String.format("VarHandle[varType=%s, coord=%s]",
@@ -2272,6 +2288,14 @@
             }
         }
 
+        /**
+         * Returns a compact textual description of this constant description.
+         * For a field {@linkplain VarHandle}, includes the owner, name, and type
+         * of the field, and whether it is static; for an array {@linkplain VarHandle},
+         * the name of the component type.
+         *
+         * @return A compact textual description of this descriptor
+         */
         @Override
         public String toString() {
             switch (kind) {
--- a/test/jdk/java/lang/constant/ClassDescTest.java	Thu Dec 13 15:31:05 2018 +0100
+++ b/test/jdk/java/lang/constant/ClassDescTest.java	Thu Dec 13 10:35:09 2018 -0500
@@ -244,6 +244,29 @@
             testBadNestedClasses(ClassDesc.ofDescriptor(p.descriptor), "any");
             testBadNestedClasses(ClassDesc.ofDescriptor(p.descriptor), "any", "other");
         }
+
+        ClassDesc stringDesc = ClassDesc.ofDescriptor("Ljava/lang/String;");
+        ClassDesc stringArrDesc = stringDesc.arrayType(255);
+        try {
+            ClassDesc arrGreaterThan255 = stringArrDesc.arrayType();
+            fail("can't create an array type descriptor with more than 255 dimensions");
+        } catch (IllegalStateException e) {
+            // good
+        }
+        String descWith255ArrayDims = new String(new char[255]).replace('\0', '[');
+        try {
+            ClassDesc arrGreaterThan255 = ClassDesc.ofDescriptor(descWith255ArrayDims + "[Ljava/lang/String;");
+            fail("can't create an array type descriptor with more than 255 dimensions");
+        } catch (IllegalArgumentException e) {
+            // good
+        }
+        try {
+            ClassDesc arrWith255Dims = ClassDesc.ofDescriptor(descWith255ArrayDims + "Ljava/lang/String;");
+            arrWith255Dims.arrayType(1);
+            fail("can't create an array type descriptor with more than 255 dimensions");
+        } catch (IllegalArgumentException e) {
+            // good
+        }
     }
 
     private void testBadNestedClasses(ClassDesc cr, String firstNestedName, String... moreNestedNames) {