8215300: additional changes to constants API

Reviewed-by: goetz
This commit is contained in:
Vicente Romero 2018-12-13 10:35:09 -05:00
parent a3df1d618e
commit 650f3fc113
12 changed files with 96 additions and 24 deletions

@ -1077,8 +1077,8 @@ public final class Double extends Number
}
/**
* 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

@ -989,8 +989,8 @@ public final class Float extends Number
}
/**
* 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

@ -1838,8 +1838,8 @@ public final class Integer extends Number
}
/**
* 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

@ -1967,8 +1967,8 @@ public final class Long extends Number
}
/**
* 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

@ -3545,8 +3545,8 @@ public final class String
}
/**
* 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

@ -112,13 +112,13 @@ public interface ClassDesc
*
* 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 @@ public interface ClassDesc
* @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 @@ public interface ClassDesc
* 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 @@ public interface 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
* @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 @@ public interface ClassDesc
* 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}

@ -65,8 +65,9 @@ import java.util.Optional;
*/
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.

@ -37,6 +37,7 @@ class ConstantUtils {
/** 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>");

@ -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}.

@ -61,7 +61,8 @@ public interface TypeDescriptor {
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();

@ -1864,6 +1864,16 @@ public abstract class VarHandle implements Constable {
}
}
/**
* 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 @@ public abstract class VarHandle implements Constable {
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 @@ public abstract class VarHandle implements Constable {
}
}
/**
* 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) {

@ -244,6 +244,29 @@ public class ClassDescTest extends SymbolicDescTest {
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) {