8338544: Dedicated Array class descriptor implementation

Reviewed-by: redestad, mchung, jvernee
This commit is contained in:
Chen Liang 2024-10-24 02:40:08 +00:00
parent 158b93d19a
commit 25c2f48d45
20 changed files with 619 additions and 398 deletions

View File

@ -26,22 +26,13 @@ package java.lang.constant;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.TypeDescriptor;
import java.util.stream.Stream;
import jdk.internal.constant.ArrayClassDescImpl;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.PrimitiveClassDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import sun.invoke.util.Wrapper;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import static java.util.stream.Collectors.joining;
import static jdk.internal.constant.ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS;
import static jdk.internal.constant.ConstantUtils.arrayDepth;
import static jdk.internal.constant.ConstantUtils.binaryToInternal;
import static jdk.internal.constant.ConstantUtils.concat;
import static jdk.internal.constant.ConstantUtils.forPrimitiveType;
import static jdk.internal.constant.ConstantUtils.internalToBinary;
import static jdk.internal.constant.ConstantUtils.validateBinaryClassName;
import static jdk.internal.constant.ConstantUtils.validateInternalClassName;
import static jdk.internal.constant.ConstantUtils.validateMemberName;
import static jdk.internal.constant.ConstantUtils.*;
/**
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
@ -64,7 +55,8 @@ public sealed interface ClassDesc
extends ConstantDesc,
TypeDescriptor.OfField<ClassDesc>
permits PrimitiveClassDescImpl,
ReferenceClassDescImpl {
ClassOrInterfaceDescImpl,
ArrayClassDescImpl {
/**
* Returns a {@linkplain ClassDesc} for a class or interface type,
@ -84,7 +76,7 @@ public sealed interface ClassDesc
*/
static ClassDesc of(String name) {
validateBinaryClassName(name);
return ClassDesc.ofDescriptor(concat("L", binaryToInternal(name), ";"));
return ConstantUtils.binaryNameToDesc(name);
}
/**
@ -110,7 +102,7 @@ public sealed interface ClassDesc
*/
static ClassDesc ofInternalName(String name) {
validateInternalClassName(name);
return ClassDesc.ofDescriptor(concat("L", name, ";"));
return ConstantUtils.internalNameToDesc(name);
}
/**
@ -129,11 +121,11 @@ public sealed interface ClassDesc
*/
static ClassDesc of(String packageName, String className) {
validateBinaryClassName(packageName);
if (packageName.isEmpty()) {
return of(className);
}
validateMemberName(className, false);
return ofDescriptor('L' + binaryToInternal(packageName) +
if (packageName.isEmpty()) {
return internalNameToDesc(className);
}
return ClassOrInterfaceDescImpl.ofValidated('L' + binaryToInternal(packageName) +
'/' + className + ';');
}
@ -168,7 +160,7 @@ public sealed interface ClassDesc
return (descriptor.length() == 1)
? forPrimitiveType(descriptor, 0)
// will throw IAE on descriptor.length == 0 or if array dimensions too long
: ReferenceClassDescImpl.of(descriptor);
: parseReferenceTypeDesc(descriptor);
}
/**
@ -180,20 +172,7 @@ public sealed interface ClassDesc
* ClassDesc} would have an array rank of greater than 255
* @jvms 4.4.1 The CONSTANT_Class_info Structure
*/
default ClassDesc arrayType() {
String desc = descriptorString();
int depth = arrayDepth(desc);
if (depth >= MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
throw new IllegalStateException(
"Cannot create an array type descriptor with more than " +
MAX_ARRAY_TYPE_DESC_DIMENSIONS + " dimensions");
}
String newDesc = "[".concat(desc);
if (desc.length() == 1 && desc.charAt(0) == 'V') {
throw new IllegalArgumentException("not a valid reference type descriptor: " + newDesc);
}
return ReferenceClassDescImpl.ofValidated(newDesc);
}
ClassDesc arrayType();
/**
* Returns a {@linkplain ClassDesc} for an array type of the specified rank,
@ -206,24 +185,7 @@ public sealed interface ClassDesc
* 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 + " is not a positive value");
}
String desc = descriptorString();
long currentDepth = arrayDepth(desc);
long netRank = currentDepth + rank;
if (netRank > MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
throw new IllegalArgumentException("rank: " + netRank +
" exceeds maximum supported dimension of " +
MAX_ARRAY_TYPE_DESC_DIMENSIONS);
}
String newDesc = new StringBuilder(desc.length() + rank).repeat('[', rank).append(desc).toString();
if (desc.length() == 1 && desc.charAt(0) == 'V') {
throw new IllegalArgumentException("not a valid reference type descriptor: " + newDesc);
}
return ReferenceClassDescImpl.ofValidated(newDesc);
}
ClassDesc arrayType(int rank);
/**
* Returns a {@linkplain ClassDesc} for a nested class of the class or
@ -243,13 +205,7 @@ public sealed interface ClassDesc
* @throws IllegalArgumentException if the nested class name is invalid
*/
default ClassDesc nested(String nestedName) {
validateMemberName(nestedName, false);
if (!isClassOrInterface())
throw new IllegalStateException("Outer class is not a class or interface type");
String desc = descriptorString();
StringBuilder sb = new StringBuilder(desc.length() + nestedName.length() + 1);
sb.append(desc, 0, desc.length() - 1).append('$').append(nestedName).append(';');
return ReferenceClassDescImpl.ofValidated(sb.toString());
throw new IllegalStateException("Outer class is not a class or interface type");
}
/**
@ -266,16 +222,7 @@ public sealed interface ClassDesc
* @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");
validateMemberName(firstNestedName, false);
// implicit null-check
for (String addNestedNames : moreNestedNames) {
validateMemberName(addNestedNames, false);
}
return moreNestedNames.length == 0
? nested(firstNestedName)
: nested(firstNestedName + Stream.of(moreNestedNames).collect(joining("$", "$", "")));
throw new IllegalStateException("Outer class is not a class or interface type");
}
/**
@ -284,7 +231,7 @@ public sealed interface ClassDesc
* @return whether this {@linkplain ClassDesc} describes an array type
*/
default boolean isArray() {
return descriptorString().charAt(0) == '[';
return false;
}
/**
@ -293,7 +240,7 @@ public sealed interface ClassDesc
* @return whether this {@linkplain ClassDesc} describes a primitive type
*/
default boolean isPrimitive() {
return descriptorString().length() == 1;
return false;
}
/**
@ -302,7 +249,7 @@ public sealed interface ClassDesc
* @return whether this {@linkplain ClassDesc} describes a class or interface type
*/
default boolean isClassOrInterface() {
return descriptorString().charAt(0) == 'L';
return false;
}
/**
@ -313,14 +260,6 @@ public sealed interface ClassDesc
* if this descriptor does not describe an array type
*/
default ClassDesc componentType() {
if (isArray()) {
String desc = descriptorString();
if (desc.length() == 2) {
return Wrapper.forBasicType(desc.charAt(1)).basicClassDescriptor();
} else {
return ReferenceClassDescImpl.ofValidated(desc.substring(1));
}
}
return null;
}
@ -332,41 +271,17 @@ public sealed interface ClassDesc
* default package, or this {@linkplain ClassDesc} does not describe a class or interface type
*/
default String packageName() {
if (!isClassOrInterface())
return "";
String desc = descriptorString();
int index = desc.lastIndexOf('/');
return (index == -1) ? "" : internalToBinary(desc.substring(1, index));
return "";
}
/**
* 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
* {@return a human-readable name for this {@code ClassDesc}}
* For primitive types, this method returns the simple name (such as {@code int}).
* For class or interface types, this method returns the unqualified class name.
* For array types, this method returns the human-readable name of the component
* type suffixed with the appropriate number of {@code []} pairs.
*/
default String displayName() {
if (isPrimitive())
return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveSimpleName();
else if (isClassOrInterface()) {
String desc = descriptorString();
return desc.substring(Math.max(1, desc.lastIndexOf('/') + 1), desc.length() - 1);
}
else if (isArray()) {
int depth = arrayDepth(descriptorString());
ClassDesc c = this;
for (int i=0; i<depth; i++)
c = c.componentType();
return c.displayName().concat("[]".repeat(depth));
}
else
throw new IllegalStateException(descriptorString());
}
String displayName();
/**
* Returns a field type descriptor string for this type

View File

@ -24,9 +24,10 @@
*/
package java.lang.constant;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.PrimitiveClassDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import java.lang.Enum.EnumDesc;
import java.lang.invoke.CallSite;
@ -68,115 +69,120 @@ public final class ConstantDescs {
// Don't change the order of these declarations!
/** {@link ClassDesc} representing {@link Object} */
public static final ClassDesc CD_Object = ReferenceClassDescImpl.ofValidated("Ljava/lang/Object;");
public static final ClassDesc CD_Object = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Object;");
/** {@link ClassDesc} representing {@link String} */
public static final ClassDesc CD_String = ReferenceClassDescImpl.ofValidated("Ljava/lang/String;");
public static final ClassDesc CD_String = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/String;");
/** {@link ClassDesc} representing {@link Class} */
public static final ClassDesc CD_Class = ReferenceClassDescImpl.ofValidated("Ljava/lang/Class;");
public static final ClassDesc CD_Class = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Class;");
/** {@link ClassDesc} representing {@link Number} */
public static final ClassDesc CD_Number = ReferenceClassDescImpl.ofValidated("Ljava/lang/Number;");
public static final ClassDesc CD_Number = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Number;");
/** {@link ClassDesc} representing {@link Integer} */
public static final ClassDesc CD_Integer = ReferenceClassDescImpl.ofValidated("Ljava/lang/Integer;");
public static final ClassDesc CD_Integer = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Integer;");
/** {@link ClassDesc} representing {@link Long} */
public static final ClassDesc CD_Long = ReferenceClassDescImpl.ofValidated("Ljava/lang/Long;");
public static final ClassDesc CD_Long = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Long;");
/** {@link ClassDesc} representing {@link Float} */
public static final ClassDesc CD_Float = ReferenceClassDescImpl.ofValidated("Ljava/lang/Float;");
public static final ClassDesc CD_Float = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Float;");
/** {@link ClassDesc} representing {@link Double} */
public static final ClassDesc CD_Double = ReferenceClassDescImpl.ofValidated("Ljava/lang/Double;");
public static final ClassDesc CD_Double = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Double;");
/** {@link ClassDesc} representing {@link Short} */
public static final ClassDesc CD_Short = ReferenceClassDescImpl.ofValidated("Ljava/lang/Short;");
public static final ClassDesc CD_Short = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Short;");
/** {@link ClassDesc} representing {@link Byte} */
public static final ClassDesc CD_Byte = ReferenceClassDescImpl.ofValidated("Ljava/lang/Byte;");
public static final ClassDesc CD_Byte = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Byte;");
/** {@link ClassDesc} representing {@link Character} */
public static final ClassDesc CD_Character = ReferenceClassDescImpl.ofValidated("Ljava/lang/Character;");
public static final ClassDesc CD_Character = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Character;");
/** {@link ClassDesc} representing {@link Boolean} */
public static final ClassDesc CD_Boolean = ReferenceClassDescImpl.ofValidated("Ljava/lang/Boolean;");
public static final ClassDesc CD_Boolean = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Boolean;");
/** {@link ClassDesc} representing {@link Void} */
public static final ClassDesc CD_Void = ReferenceClassDescImpl.ofValidated("Ljava/lang/Void;");
public static final ClassDesc CD_Void = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Void;");
/** {@link ClassDesc} representing {@link Throwable} */
public static final ClassDesc CD_Throwable = ReferenceClassDescImpl.ofValidated("Ljava/lang/Throwable;");
public static final ClassDesc CD_Throwable = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Throwable;");
/** {@link ClassDesc} representing {@link Exception} */
public static final ClassDesc CD_Exception = ReferenceClassDescImpl.ofValidated("Ljava/lang/Exception;");
public static final ClassDesc CD_Exception = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Exception;");
/** {@link ClassDesc} representing {@link Enum} */
public static final ClassDesc CD_Enum = ReferenceClassDescImpl.ofValidated("Ljava/lang/Enum;");
public static final ClassDesc CD_Enum = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Enum;");
/** {@link ClassDesc} representing {@link VarHandle} */
public static final ClassDesc CD_VarHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/VarHandle;");
public static final ClassDesc CD_VarHandle = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/VarHandle;");
/** {@link ClassDesc} representing {@link MethodHandles} */
public static final ClassDesc CD_MethodHandles = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandles;");
public static final ClassDesc CD_MethodHandles = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodHandles;");
/** {@link ClassDesc} representing {@link MethodHandles.Lookup} */
public static final ClassDesc CD_MethodHandles_Lookup = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandles$Lookup;");
public static final ClassDesc CD_MethodHandles_Lookup = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodHandles$Lookup;");
/** {@link ClassDesc} representing {@link MethodHandle} */
public static final ClassDesc CD_MethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandle;");
public static final ClassDesc CD_MethodHandle = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodHandle;");
/** {@link ClassDesc} representing {@link MethodType} */
public static final ClassDesc CD_MethodType = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodType;");
public static final ClassDesc CD_MethodType = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodType;");
/** {@link ClassDesc} representing {@link CallSite} */
public static final ClassDesc CD_CallSite = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/CallSite;");
public static final ClassDesc CD_CallSite = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/CallSite;");
/** {@link ClassDesc} representing {@link Collection} */
public static final ClassDesc CD_Collection = ReferenceClassDescImpl.ofValidated("Ljava/util/Collection;");
public static final ClassDesc CD_Collection = ClassOrInterfaceDescImpl.ofValidated("Ljava/util/Collection;");
/** {@link ClassDesc} representing {@link List} */
public static final ClassDesc CD_List = ReferenceClassDescImpl.ofValidated("Ljava/util/List;");
public static final ClassDesc CD_List = ClassOrInterfaceDescImpl.ofValidated("Ljava/util/List;");
/** {@link ClassDesc} representing {@link Set} */
public static final ClassDesc CD_Set = ReferenceClassDescImpl.ofValidated("Ljava/util/Set;");
public static final ClassDesc CD_Set = ClassOrInterfaceDescImpl.ofValidated("Ljava/util/Set;");
/** {@link ClassDesc} representing {@link Map} */
public static final ClassDesc CD_Map = ReferenceClassDescImpl.ofValidated("Ljava/util/Map;");
public static final ClassDesc CD_Map = ClassOrInterfaceDescImpl.ofValidated("Ljava/util/Map;");
/** {@link ClassDesc} representing {@link ConstantDesc} */
public static final ClassDesc CD_ConstantDesc = ReferenceClassDescImpl.ofValidated("Ljava/lang/constant/ConstantDesc;");
public static final ClassDesc CD_ConstantDesc = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/constant/ConstantDesc;");
/** {@link ClassDesc} representing {@link ClassDesc} */
public static final ClassDesc CD_ClassDesc = ReferenceClassDescImpl.ofValidated("Ljava/lang/constant/ClassDesc;");
public static final ClassDesc CD_ClassDesc = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/constant/ClassDesc;");
/** {@link ClassDesc} representing {@link EnumDesc} */
public static final ClassDesc CD_EnumDesc = ReferenceClassDescImpl.ofValidated("Ljava/lang/Enum$EnumDesc;");
public static final ClassDesc CD_EnumDesc = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Enum$EnumDesc;");
/** {@link ClassDesc} representing {@link MethodTypeDesc} */
public static final ClassDesc CD_MethodTypeDesc = ReferenceClassDescImpl.ofValidated("Ljava/lang/constant/MethodTypeDesc;");
public static final ClassDesc CD_MethodTypeDesc = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/constant/MethodTypeDesc;");
/** {@link ClassDesc} representing {@link MethodHandleDesc} */
public static final ClassDesc CD_MethodHandleDesc = ReferenceClassDescImpl.ofValidated("Ljava/lang/constant/MethodHandleDesc;");
public static final ClassDesc CD_MethodHandleDesc = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/constant/MethodHandleDesc;");
/** {@link ClassDesc} representing {@link DirectMethodHandleDesc} */
public static final ClassDesc CD_DirectMethodHandleDesc = ReferenceClassDescImpl.ofValidated("Ljava/lang/constant/DirectMethodHandleDesc;");
public static final ClassDesc CD_DirectMethodHandleDesc = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/constant/DirectMethodHandleDesc;");
/** {@link ClassDesc} representing {@link VarHandleDesc} */
public static final ClassDesc CD_VarHandleDesc = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/VarHandle$VarHandleDesc;");
public static final ClassDesc CD_VarHandleDesc = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/VarHandle$VarHandleDesc;");
/** {@link ClassDesc} representing {@link DirectMethodHandleDesc.Kind} */
public static final ClassDesc CD_MethodHandleDesc_Kind = ReferenceClassDescImpl.ofValidated("Ljava/lang/constant/DirectMethodHandleDesc$Kind;");
public static final ClassDesc CD_MethodHandleDesc_Kind = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/constant/DirectMethodHandleDesc$Kind;");
/** {@link ClassDesc} representing {@link DynamicConstantDesc} */
public static final ClassDesc CD_DynamicConstantDesc = ReferenceClassDescImpl.ofValidated("Ljava/lang/constant/DynamicConstantDesc;");
public static final ClassDesc CD_DynamicConstantDesc = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/constant/DynamicConstantDesc;");
/** {@link ClassDesc} representing {@link DynamicCallSiteDesc} */
public static final ClassDesc CD_DynamicCallSiteDesc = ReferenceClassDescImpl.ofValidated("Ljava/lang/constant/DynamicCallSiteDesc;");
public static final ClassDesc CD_DynamicCallSiteDesc = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/constant/DynamicCallSiteDesc;");
/** {@link ClassDesc} representing {@link ConstantBootstraps} */
public static final ClassDesc CD_ConstantBootstraps = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/ConstantBootstraps;");
public static final ClassDesc CD_ConstantBootstraps = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/ConstantBootstraps;");
static {
// avoid circular initialization
ConstantUtils.CD_Object_array = CD_Object.arrayType();
}
private static final ClassDesc[] INDY_BOOTSTRAP_ARGS = {
CD_MethodHandles_Lookup,
@ -229,7 +235,7 @@ public final class ConstantDescs {
/** {@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());
CD_Object, CD_MethodHandle, ConstantUtils.CD_Object_array);
/**
* {@link MethodHandleDesc} representing {@link ConstantBootstraps#explicitCast(Lookup, String, Class, Object) ConstantBootstraps.explicitCast}

View File

@ -42,8 +42,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import jdk.internal.loader.BootLoader;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.BytecodeName;
@ -65,8 +66,8 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/*non-public*/
abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesData> {
private static final ClassDesc CD_LambdaForm = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;");
private static final ClassDesc CD_BoundMethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/BoundMethodHandle;");
private static final ClassDesc CD_LambdaForm = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;");
private static final ClassDesc CD_BoundMethodHandle = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/BoundMethodHandle;");
private final Class<T> topClass;
private final Class<K> keyType;
@ -974,7 +975,7 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
: cls == MethodType.class ? CD_MethodType
: cls == LambdaForm.class ? CD_LambdaForm
: cls == BoundMethodHandle.class ? CD_BoundMethodHandle
: ReferenceClassDescImpl.ofValidated(cls.descriptorString());
: ConstantUtils.referenceClassDesc(cls.descriptorString());
}
static MethodTypeDesc methodDesc(MethodType mt) {

View File

@ -25,6 +25,7 @@
package java.lang.invoke;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.misc.CDS;
import jdk.internal.util.ClassFileDumper;
import sun.invoke.util.VerifyAccess;
@ -53,10 +54,8 @@ import java.lang.classfile.constantpool.ConstantPoolBuilder;
import static java.lang.constant.ConstantDescs.*;
import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS;
import static java.lang.invoke.MethodHandleNatives.Constants.STRONG_LOADER_LINK;
import static java.lang.invoke.MethodType.methodType;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.Wrapper;
@ -157,7 +156,7 @@ import sun.invoke.util.Wrapper;
implMethodDesc = methodDesc(implInfo.getMethodType());
constructorType = factoryType.changeReturnType(Void.TYPE);
lambdaClassName = lambdaClassName(targetClass);
lambdaClassEntry = pool.classEntry(ReferenceClassDescImpl.ofValidated(ConstantUtils.concat("L", lambdaClassName, ";")));
lambdaClassEntry = pool.classEntry(ConstantUtils.internalNameToDesc(lambdaClassName));
// If the target class invokes a protected method inherited from a
// superclass in a different package, or does 'invokespecial', the
// lambda class has no access to the resolved method, or does
@ -407,9 +406,9 @@ import sun.invoke.util.Wrapper;
private static class SerializationSupport {
// Serialization support
private static final ClassDesc CD_SerializedLambda = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/SerializedLambda;");
private static final ClassDesc CD_ObjectOutputStream = ReferenceClassDescImpl.ofValidated("Ljava/io/ObjectOutputStream;");
private static final ClassDesc CD_ObjectInputStream = ReferenceClassDescImpl.ofValidated("Ljava/io/ObjectInputStream;");
private static final ClassDesc CD_SerializedLambda = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/SerializedLambda;");
private static final ClassDesc CD_ObjectOutputStream = ClassOrInterfaceDescImpl.ofValidated("Ljava/io/ObjectOutputStream;");
private static final ClassDesc CD_ObjectInputStream = ClassOrInterfaceDescImpl.ofValidated("Ljava/io/ObjectInputStream;");
private static final MethodTypeDesc MTD_Object = MethodTypeDescImpl.ofValidated(CD_Object);
private static final MethodTypeDesc MTD_void_ObjectOutputStream = MethodTypeDescImpl.ofValidated(CD_void, CD_ObjectOutputStream);
private static final MethodTypeDesc MTD_void_ObjectInputStream = MethodTypeDescImpl.ofValidated(CD_void, CD_ObjectInputStream);
@ -418,10 +417,10 @@ import sun.invoke.util.Wrapper;
private static final String NAME_METHOD_READ_OBJECT = "readObject";
private static final String NAME_METHOD_WRITE_OBJECT = "writeObject";
static final ClassDesc CD_NotSerializableException = ReferenceClassDescImpl.ofValidated("Ljava/io/NotSerializableException;");
static final ClassDesc CD_NotSerializableException = ClassOrInterfaceDescImpl.ofValidated("Ljava/io/NotSerializableException;");
static final MethodTypeDesc MTD_CTOR_NOT_SERIALIZABLE_EXCEPTION = MethodTypeDescImpl.ofValidated(CD_void, CD_String);
static final MethodTypeDesc MTD_CTOR_SERIALIZED_LAMBDA = MethodTypeDescImpl.ofValidated(CD_void,
CD_Class, CD_String, CD_String, CD_String, CD_int, CD_String, CD_String, CD_String, CD_String, ReferenceClassDescImpl.ofValidated("[Ljava/lang/Object;"));
CD_Class, CD_String, CD_String, CD_String, CD_int, CD_String, CD_String, CD_String, CD_String, ConstantUtils.CD_Object_array);
}
@ -557,12 +556,12 @@ import sun.invoke.util.Wrapper;
}
static ClassDesc implClassDesc(Class<?> cls) {
return cls.isHidden() ? null : ReferenceClassDescImpl.ofValidated(cls.descriptorString());
return cls.isHidden() ? null : ConstantUtils.referenceClassDesc(cls.descriptorString());
}
static ClassDesc classDesc(Class<?> cls) {
return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
: ReferenceClassDescImpl.ofValidated(cls.descriptorString());
: ConstantUtils.referenceClassDesc(cls.descriptorString());
}
static MethodTypeDesc methodDesc(MethodType mt) {

View File

@ -25,6 +25,8 @@
package java.lang.invoke;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.constant.ConstantUtils;
import sun.invoke.util.VerifyAccess;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
@ -50,7 +52,6 @@ import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import static java.lang.classfile.ClassFile.*;
import static java.lang.constant.ConstantDescs.*;
@ -59,7 +60,6 @@ import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
import static jdk.internal.constant.ConstantUtils.concat;
import static jdk.internal.constant.ConstantUtils.validateInternalClassName;
/**
@ -69,16 +69,16 @@ import static jdk.internal.constant.ConstantUtils.validateInternalClassName;
*/
class InvokerBytecodeGenerator {
/** Define class names for convenience. */
private static final ClassDesc CD_CasesHolder = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$CasesHolder;");
private static final ClassDesc CD_DirectMethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/DirectMethodHandle;");
private static final ClassDesc CD_MemberName = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MemberName;");
private static final ClassDesc CD_MethodHandleImpl = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl;");
private static final ClassDesc CD_LambdaForm = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;");
private static final ClassDesc CD_LambdaForm_Name = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Name;");
private static final ClassDesc CD_LoopClauses = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$LoopClauses;");
private static final ClassDesc CD_Object_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/Object;");
private static final ClassDesc CD_MethodHandle_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/invoke/MethodHandle;");
private static final ClassDesc CD_MethodHandle_array2 = ReferenceClassDescImpl.ofValidated("[[Ljava/lang/invoke/MethodHandle;");
private static final ClassDesc CD_CasesHolder = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$CasesHolder;");
private static final ClassDesc CD_DirectMethodHandle = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/DirectMethodHandle;");
private static final ClassDesc CD_MemberName = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MemberName;");
private static final ClassDesc CD_MethodHandleImpl = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl;");
private static final ClassDesc CD_LambdaForm = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;");
private static final ClassDesc CD_LambdaForm_Name = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Name;");
private static final ClassDesc CD_LoopClauses = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/MethodHandleImpl$LoopClauses;");
private static final ClassDesc CD_Object_array = ConstantUtils.CD_Object_array;
private static final ClassDesc CD_MethodHandle_array = CD_MethodHandle.arrayType();
private static final ClassDesc CD_MethodHandle_array2 = CD_MethodHandle_array.arrayType();
private static final MethodTypeDesc MTD_boolean_Object = MethodTypeDescImpl.ofValidated(CD_boolean, CD_Object);
private static final MethodTypeDesc MTD_Object_int = MethodTypeDescImpl.ofValidated(CD_Object, CD_int);
@ -133,7 +133,7 @@ class InvokerBytecodeGenerator {
this.name = name;
this.className = CLASS_PREFIX.concat(name);
validateInternalClassName(name);
this.classEntry = pool.classEntry(ReferenceClassDescImpl.ofValidated(concat("L", className, ";")));
this.classEntry = pool.classEntry(ConstantUtils.internalNameToDesc(className));
this.lambdaForm = lambdaForm;
this.invokerName = invokerName;
this.invokerType = invokerType;
@ -517,11 +517,11 @@ class InvokerBytecodeGenerator {
return true;
}
static final Annotation DONTINLINE = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljdk/internal/vm/annotation/DontInline;"));
static final Annotation FORCEINLINE = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljdk/internal/vm/annotation/ForceInline;"));
static final Annotation HIDDEN = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljdk/internal/vm/annotation/Hidden;"));
static final Annotation INJECTEDPROFILE = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/InjectedProfile;"));
static final Annotation LF_COMPILED = Annotation.of(ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Compiled;"));
static final Annotation DONTINLINE = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljdk/internal/vm/annotation/DontInline;"));
static final Annotation FORCEINLINE = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljdk/internal/vm/annotation/ForceInline;"));
static final Annotation HIDDEN = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljdk/internal/vm/annotation/Hidden;"));
static final Annotation INJECTEDPROFILE = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/InjectedProfile;"));
static final Annotation LF_COMPILED = Annotation.of(ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm$Compiled;"));
// Suppress method in backtraces displayed to the user, mark this method as
// a compiled LambdaForm, then either force or prohibit inlining.
@ -1649,7 +1649,7 @@ class InvokerBytecodeGenerator {
: cls == MemberName.class ? CD_MemberName
: cls == MethodType.class ? CD_MethodType
: cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
: ReferenceClassDescImpl.ofValidated(cls.descriptorString());
: ConstantUtils.referenceClassDesc(cls.descriptorString());
}
static MethodTypeDesc methodDesc(MethodType mt) {

View File

@ -27,8 +27,9 @@ package java.lang.invoke;
import jdk.internal.access.JavaLangInvokeAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import jdk.internal.foreign.abi.NativeEntryPoint;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
@ -54,7 +55,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Stream;
@ -67,7 +67,6 @@ import static java.lang.invoke.MethodHandleNatives.Constants.MN_HIDDEN_MEMBER;
import static java.lang.invoke.MethodHandleNatives.Constants.NESTMATE_CLASS;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
/**
* Trusted implementation code for MethodHandle.
@ -1038,7 +1037,7 @@ abstract class MethodHandleImpl {
// That way we can lazily load the code and set up the constants.
private static class BindCaller {
private static final ClassDesc CD_Object_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/Object;");
private static final ClassDesc CD_Object_array = ConstantUtils.CD_Object_array;
private static final MethodType INVOKER_MT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
private static final MethodType REFLECT_INVOKER_MT = MethodType.methodType(Object.class, MethodHandle.class, Object.class, Object[].class);
@ -1267,7 +1266,7 @@ abstract class MethodHandleImpl {
// }
// }
// }
return ClassFile.of().build(ReferenceClassDescImpl.ofValidated("LInjectedInvoker;"), clb -> clb
return ClassFile.of().build(ClassOrInterfaceDescImpl.ofValidated("LInjectedInvoker;"), clb -> clb
.withFlags(ACC_PRIVATE | ACC_SUPER)
.withMethodBody(
"invoke_V",

View File

@ -28,9 +28,9 @@ package java.lang.invoke;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import jdk.internal.misc.VM;
import jdk.internal.util.ClassFileDumper;
import jdk.internal.util.ReferenceKey;
@ -1088,10 +1088,10 @@ public final class StringConcatFactory {
static final MethodHandles.Lookup STR_LOOKUP = new MethodHandles.Lookup(String.class);
static final ClassDesc CD_CONCAT = ConstantUtils.binaryNameToDesc(CLASS_NAME);
static final ClassDesc CD_StringConcatHelper = ReferenceClassDescImpl.ofValidated("Ljava/lang/StringConcatHelper;");
static final ClassDesc CD_StringConcatBase = ReferenceClassDescImpl.ofValidated("Ljava/lang/StringConcatHelper$StringConcatBase;");
static final ClassDesc CD_Array_byte = ReferenceClassDescImpl.ofValidated("[B");
static final ClassDesc CD_Array_String = ReferenceClassDescImpl.ofValidated("[Ljava/lang/String;");
static final ClassDesc CD_StringConcatHelper = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/StringConcatHelper;");
static final ClassDesc CD_StringConcatBase = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/StringConcatHelper$StringConcatBase;");
static final ClassDesc CD_Array_byte = CD_byte.arrayType();
static final ClassDesc CD_Array_String = CD_String.arrayType();
static final MethodTypeDesc MTD_byte_char = MethodTypeDescImpl.ofValidated(CD_byte, CD_char);
static final MethodTypeDesc MTD_byte = MethodTypeDescImpl.ofValidated(CD_byte);

View File

@ -30,8 +30,9 @@ import java.lang.classfile.CodeBuilder;
import java.lang.classfile.TypeKind;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.MethodRefEntry;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import sun.invoke.util.Wrapper;
import static java.lang.constant.ConstantDescs.*;
@ -202,6 +203,6 @@ class TypeConvertingMethodAdapter {
return cls.isPrimitive() ? Wrapper.forPrimitiveType(cls).basicClassDescriptor()
: cls == Object.class ? CD_Object
: cls == String.class ? CD_String
: ReferenceClassDescImpl.ofValidated(cls.descriptorString());
: ConstantUtils.referenceClassDesc(cls.descriptorString());
}
}

View File

@ -39,9 +39,10 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import sun.security.action.GetBooleanAction;
import static java.lang.classfile.ClassFile.*;
@ -64,18 +65,18 @@ final class ProxyGenerator {
ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS);
private static final ClassDesc
CD_ClassLoader = ReferenceClassDescImpl.ofValidated("Ljava/lang/ClassLoader;"),
CD_Class_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/Class;"),
CD_ClassNotFoundException = ReferenceClassDescImpl.ofValidated("Ljava/lang/ClassNotFoundException;"),
CD_NoClassDefFoundError = ReferenceClassDescImpl.ofValidated("Ljava/lang/NoClassDefFoundError;"),
CD_IllegalAccessException = ReferenceClassDescImpl.ofValidated("Ljava/lang/IllegalAccessException;"),
CD_InvocationHandler = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/InvocationHandler;"),
CD_Method = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/Method;"),
CD_NoSuchMethodError = ReferenceClassDescImpl.ofValidated("Ljava/lang/NoSuchMethodError;"),
CD_NoSuchMethodException = ReferenceClassDescImpl.ofValidated("Ljava/lang/NoSuchMethodException;"),
CD_Object_array = ReferenceClassDescImpl.ofValidated("[Ljava/lang/Object;"),
CD_Proxy = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/Proxy;"),
CD_UndeclaredThrowableException = ReferenceClassDescImpl.ofValidated("Ljava/lang/reflect/UndeclaredThrowableException;");
CD_ClassLoader = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/ClassLoader;"),
CD_Class_array = CD_Class.arrayType(),
CD_ClassNotFoundException = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/ClassNotFoundException;"),
CD_NoClassDefFoundError = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/NoClassDefFoundError;"),
CD_IllegalAccessException = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/IllegalAccessException;"),
CD_InvocationHandler = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/reflect/InvocationHandler;"),
CD_Method = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/reflect/Method;"),
CD_NoSuchMethodError = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/NoSuchMethodError;"),
CD_NoSuchMethodException = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/NoSuchMethodException;"),
CD_Object_array = ConstantUtils.CD_Object_array,
CD_Proxy = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/reflect/Proxy;"),
CD_UndeclaredThrowableException = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/reflect/UndeclaredThrowableException;");
private static final MethodTypeDesc
MTD_boolean = MethodTypeDescImpl.ofValidated(CD_boolean),

View File

@ -48,9 +48,9 @@ import java.lang.classfile.ClassFile;
import java.lang.classfile.Label;
import java.lang.classfile.instruction.SwitchCase;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import jdk.internal.misc.PreviewFeatures;
import jdk.internal.vm.annotation.Stable;
@ -82,8 +82,8 @@ public class SwitchBootstraps {
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
private static final boolean previewEnabled = PreviewFeatures.isEnabled();
private static final ClassDesc CD_BiPredicate = ReferenceClassDescImpl.ofValidated("Ljava/util/function/BiPredicate;");
private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;");
private static final ClassDesc CD_BiPredicate = ClassOrInterfaceDescImpl.ofValidated("Ljava/util/function/BiPredicate;");
private static final ClassDesc CD_Objects = ClassOrInterfaceDescImpl.ofValidated("Ljava/util/Objects;");
private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR =
MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_int);
@ -584,7 +584,7 @@ public class SwitchBootstraps {
TypePairs typePair = TypePairs.of(Wrapper.asPrimitiveType(selectorType), classLabel);
String methodName = TypePairs.typePairToName.get(typePair);
cb.invokestatic(referenceClassDesc(ExactConversionsSupport.class),
cb.invokestatic(ConstantUtils.referenceClassDesc(ExactConversionsSupport.class),
methodName,
MethodTypeDesc.of(CD_boolean, classDesc(typePair.from)))
.ifeq(next);

View File

@ -34,8 +34,6 @@ import java.lang.constant.MethodTypeDesc;
import java.util.Arrays;
import java.util.List;
import jdk.internal.constant.ConstantUtils;
import static java.lang.classfile.constantpool.PoolEntry.*;
import static java.util.Objects.requireNonNull;

View File

@ -43,11 +43,10 @@ import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import jdk.internal.constant.PrimitiveClassDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.util.Preconditions;
import static java.lang.classfile.ClassFile.ACC_STATIC;
import static java.lang.classfile.ClassFile.*;
import static java.lang.classfile.constantpool.PoolEntry.*;
import static java.lang.constant.ConstantDescs.*;
import static jdk.internal.classfile.impl.RawBytecodeHelper.*;
@ -1059,7 +1058,7 @@ public final class StackMapGenerator {
if (desc == CD_double) return pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
return desc == CD_void ? this
: pushStack(
desc instanceof PrimitiveClassDescImpl
desc.isPrimitive()
? (desc == CD_float ? Type.FLOAT_TYPE : Type.INTEGER_TYPE)
: Type.referenceType(desc));
}
@ -1069,7 +1068,7 @@ public final class StackMapGenerator {
if (desc == CD_double) return decStack1PushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE);
return desc == CD_void ? this
: decStack1PushStack(
desc instanceof PrimitiveClassDescImpl
desc.isPrimitive()
? (desc == CD_float ? Type.FLOAT_TYPE : Type.INTEGER_TYPE)
: Type.referenceType(desc));
}
@ -1274,7 +1273,7 @@ public final class StackMapGenerator {
locals[localsSize + 1] = Type.DOUBLE2_TYPE;
localsSize += 2;
} else {
if (desc instanceof ReferenceClassDescImpl) {
if (!desc.isPrimitive()) {
type = Type.referenceType(desc);
} else if (desc == CD_float) {
type = Type.FLOAT_TYPE;
@ -1459,14 +1458,14 @@ public final class StackMapGenerator {
//frequently used types to reduce footprint
static final Type OBJECT_TYPE = referenceType(CD_Object),
THROWABLE_TYPE = referenceType(CD_Throwable),
INT_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[I")),
BOOLEAN_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[Z")),
BYTE_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[B")),
CHAR_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[C")),
SHORT_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[S")),
LONG_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[J")),
DOUBLE_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[D")),
FLOAT_ARRAY_TYPE = referenceType(ReferenceClassDescImpl.ofValidated("[F")),
INT_ARRAY_TYPE = referenceType(CD_int.arrayType()),
BOOLEAN_ARRAY_TYPE = referenceType(CD_boolean.arrayType()),
BYTE_ARRAY_TYPE = referenceType(CD_byte.arrayType()),
CHAR_ARRAY_TYPE = referenceType(CD_char.arrayType()),
SHORT_ARRAY_TYPE = referenceType(CD_short.arrayType()),
LONG_ARRAY_TYPE = referenceType(CD_long.arrayType()),
DOUBLE_ARRAY_TYPE = referenceType(CD_double.arrayType()),
FLOAT_ARRAY_TYPE = referenceType(CD_float.arrayType()),
STRING_TYPE = referenceType(CD_String),
CLASS_TYPE = referenceType(CD_Class),
METHOD_HANDLE_TYPE = referenceType(CD_MethodHandle),
@ -1531,8 +1530,8 @@ public final class StackMapGenerator {
}
}
private static final ClassDesc CD_Cloneable = ReferenceClassDescImpl.ofValidated("Ljava/lang/Cloneable;");
private static final ClassDesc CD_Serializable = ReferenceClassDescImpl.ofValidated("Ljava/io/Serializable;");
private static final ClassDesc CD_Cloneable = ClassOrInterfaceDescImpl.ofValidated("Ljava/lang/Cloneable;");
private static final ClassDesc CD_Serializable = ClassOrInterfaceDescImpl.ofValidated("Ljava/io/Serializable;");
private Type mergeReferenceFrom(Type from, ClassHierarchyImpl context) {
if (from == NULL_TYPE) {

View File

@ -42,7 +42,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import jdk.internal.access.SharedSecrets;
import jdk.internal.constant.ReferenceClassDescImpl;
import jdk.internal.constant.ClassOrInterfaceDescImpl;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
@ -134,8 +134,8 @@ public class Util {
}
public static String toInternalName(ClassDesc cd) {
if (cd instanceof ReferenceClassDescImpl rcd) {
return rcd.internalName();
if (cd instanceof ClassOrInterfaceDescImpl coi) {
return coi.internalName();
}
throw new IllegalArgumentException(cd.descriptorString());
}

View File

@ -0,0 +1,155 @@
/*
* Copyright (c) 2024, 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 jdk.internal.constant;
import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.Wrapper;
import static java.lang.constant.ConstantDescs.CD_void;
import static jdk.internal.constant.ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS;
/**
* An array class descriptor.
* Restrictions: <ul>
* <li>{@code rank} must be in {@code [1, 255]}
* <li>{@code element} must not be void or array
* </ul>
*/
public final class ArrayClassDescImpl implements ClassDesc {
private final ClassDesc elementType;
private final int rank;
private @Stable String cachedDescriptorString;
public static ArrayClassDescImpl ofValidatedDescriptor(String desc) {
assert desc.charAt(0) == '[';
var lastChar = desc.charAt(desc.length() - 1);
ArrayClassDescImpl ret;
if (lastChar != ';') {
// Primitive element arrays
ret = ofValidated(Wrapper.forBasicType(lastChar).basicClassDescriptor(), desc.length() - 1);
} else {
int level = ConstantUtils.arrayDepth(desc, 0);
ret = ofValidated(ClassOrInterfaceDescImpl.ofValidated(desc.substring(level)), level);
}
ret.cachedDescriptorString = desc;
return ret;
}
public static ArrayClassDescImpl ofValidated(ClassDesc elementType, int rank) {
assert !elementType.isArray() && elementType != CD_void;
assert rank > 0 && rank <= MAX_ARRAY_TYPE_DESC_DIMENSIONS;
return new ArrayClassDescImpl(elementType, rank);
}
private ArrayClassDescImpl(ClassDesc elementType, int rank) {
this.elementType = elementType;
this.rank = rank;
}
@Override
public ClassDesc arrayType() {
int rank = this.rank + 1;
if (rank > MAX_ARRAY_TYPE_DESC_DIMENSIONS)
throw new IllegalStateException(ConstantUtils.invalidArrayRankMessage(rank));
return new ArrayClassDescImpl(elementType, rank);
}
@Override
public ClassDesc arrayType(int rank) {
if (rank <= 0) {
throw new IllegalArgumentException("rank " + rank + " is not a positive value");
}
rank += this.rank;
ConstantUtils.validateArrayRank(rank);
return new ArrayClassDescImpl(elementType, rank);
}
@Override
public boolean isArray() {
return true;
}
@Override
public ClassDesc componentType() {
return rank == 1 ? elementType : new ArrayClassDescImpl(elementType, rank - 1);
}
@Override
public String displayName() {
return elementType.displayName() + "[]".repeat(rank);
}
@Override
public String descriptorString() {
var desc = cachedDescriptorString;
if (desc != null)
return desc;
return cachedDescriptorString = computeDescriptor();
}
private String computeDescriptor() {
var componentDesc = elementType.descriptorString();
StringBuilder sb = new StringBuilder(rank + componentDesc.length());
sb.repeat('[', rank);
sb.append(componentDesc);
return sb.toString();
}
@Override
public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException {
if (elementType.isPrimitive()) {
return lookup.findClass(descriptorString());
}
// Class.forName is slow on class or interface arrays
Class<?> clazz = elementType.resolveConstantDesc(lookup);
for (int i = 0; i < rank; i++)
clazz = clazz.arrayType();
return clazz;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof ArrayClassDescImpl constant) {
return elementType.equals(constant.elementType) && rank == constant.rank;
}
return false;
}
@Override
public int hashCode() {
return descriptorString().hashCode();
}
@Override
public String toString() {
return String.format("ArrayClassDesc[%s, %d]", elementType.displayName(), rank);
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2018, 2024, 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 jdk.internal.constant;
import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles;
import jdk.internal.vm.annotation.Stable;
import static jdk.internal.constant.ConstantUtils.*;
/**
* A class or interface descriptor.
* Restrictions:
* <ul>
* <li>Starts with 'L'
* <li>Ends with ';'
* <li>No '.' or '[' or ';' in the middle
* <li>No leading/trailing/consecutive '/'
* </ul>
*/
public final class ClassOrInterfaceDescImpl implements ClassDesc {
private final String descriptor;
private @Stable String internalName;
/**
* Creates a {@linkplain ClassOrInterfaceDescImpl} from a pre-validated descriptor string
* for a class or interface.
*/
public static ClassOrInterfaceDescImpl ofValidated(String descriptor) {
assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length())
== descriptor.length() : descriptor;
assert descriptor.charAt(0) == 'L';
return new ClassOrInterfaceDescImpl(descriptor);
}
ClassOrInterfaceDescImpl(String descriptor) {
this.descriptor = descriptor;
}
public String internalName() {
var internalName = this.internalName;
if (internalName == null) {
this.internalName = internalName = dropFirstAndLastChar(descriptor);
}
return internalName;
}
@Override
public ClassDesc arrayType(int rank) {
ConstantUtils.validateArrayRank(rank);
return ArrayClassDescImpl.ofValidated(this, rank);
}
@Override
public ClassDesc arrayType() {
return ArrayClassDescImpl.ofValidated(this, 1);
}
@Override
public ClassDesc nested(String nestedName) {
validateMemberName(nestedName, false);
String desc = descriptorString();
StringBuilder sb = new StringBuilder(desc.length() + nestedName.length() + 1);
sb.append(desc, 0, desc.length() - 1).append('$').append(nestedName).append(';');
return ofValidated(sb.toString());
}
@Override
public ClassDesc nested(String firstNestedName, String... moreNestedNames) {
validateMemberName(firstNestedName, false);
// implicit null-check
for (String addNestedNames : moreNestedNames) {
validateMemberName(addNestedNames, false);
}
return moreNestedNames.length == 0
? nested(firstNestedName)
: nested(firstNestedName + "$" + String.join("$", moreNestedNames));
}
@Override
public boolean isClassOrInterface() {
return true;
}
@Override
public String packageName() {
String desc = descriptorString();
int index = desc.lastIndexOf('/');
return (index == -1) ? "" : internalToBinary(desc.substring(1, index));
}
@Override
public String displayName() {
String desc = descriptorString();
return desc.substring(Math.max(1, desc.lastIndexOf('/') + 1), desc.length() - 1);
}
@Override
public String descriptorString() {
return descriptor;
}
@Override
public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup)
throws ReflectiveOperationException {
return lookup.findClass(internalToBinary(internalName()));
}
/**
* Returns {@code true} if this {@linkplain ClassOrInterfaceDescImpl} is
* equal to another {@linkplain ClassOrInterfaceDescImpl}. Equality is
* determined by the two class descriptors having equal class descriptor
* strings.
*
* @param o the {@code ClassDesc} to compare to this
* {@code ClassDesc}
* @return {@code true} if the specified {@code ClassDesc}
* is equal to this {@code ClassDesc}.
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof ClassOrInterfaceDescImpl constant) {
return descriptor.equals(constant.descriptor);
}
return false;
}
@Override
public int hashCode() {
return descriptor.hashCode();
}
@Override
public String toString() {
return String.format("ClassOrInterfaceDesc[%s]", displayName());
}
}

View File

@ -24,6 +24,7 @@
*/
package jdk.internal.constant;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.Wrapper;
import java.lang.constant.ClassDesc;
@ -31,8 +32,6 @@ import java.lang.constant.ConstantDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import jdk.internal.access.JavaLangAccess;
@ -50,6 +49,7 @@ public final class ConstantUtils {
public static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0];
public static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255;
public static final ClassDesc CD_module_info = binaryNameToDesc("module-info");
public static @Stable ClassDesc CD_Object_array; // set from ConstantDescs, avoid circular initialization
private static final Set<String> pointyNames = Set.of(ConstantDescs.INIT_NAME, ConstantDescs.CLASS_INIT_NAME);
@ -70,7 +70,18 @@ public final class ConstantUtils {
* @param binaryName a binary name
*/
public static ClassDesc binaryNameToDesc(String binaryName) {
return ReferenceClassDescImpl.ofValidated(concat("L", binaryToInternal(binaryName), ";"));
return internalNameToDesc(binaryToInternal(binaryName));
}
/**
* Creates a {@linkplain ClassDesc} from a pre-validated internal name
* for a class or interface type. Validated version of {@link
* ClassDesc#ofInternalName(String)}.
*
* @param internalName a binary name
*/
public static ClassDesc internalNameToDesc(String internalName) {
return ClassOrInterfaceDescImpl.ofValidated(concat("L", internalName, ";"));
}
/**
@ -91,7 +102,21 @@ public final class ConstantUtils {
* class or interface or an array type with a non-hidden component type.
*/
public static ClassDesc referenceClassDesc(Class<?> type) {
return ReferenceClassDescImpl.ofValidated(type.descriptorString());
return referenceClassDesc(type.descriptorString());
}
/**
* Creates a {@linkplain ClassDesc} from a pre-validated descriptor string
* for a class or interface type or an array type.
*
* @param descriptor a field descriptor string for a class or interface type
* @jvms 4.3.2 Field Descriptors
*/
public static ClassDesc referenceClassDesc(String descriptor) {
if (descriptor.charAt(0) == '[') {
return ArrayClassDescImpl.ofValidatedDescriptor(descriptor);
}
return ClassOrInterfaceDescImpl.ofValidated(descriptor);
}
/**
@ -128,6 +153,26 @@ public final class ConstantUtils {
return MethodTypeDescImpl.ofValidated(returnDesc, paramDescs);
}
/**
* Creates a {@linkplain ClassDesc} from a descriptor string for a class or
* interface type or an array type.
*
* @param descriptor a field descriptor string for a class or interface type
* @throws IllegalArgumentException if the descriptor string is not a valid
* field descriptor string, or does not describe a class or interface type
* @jvms 4.3.2 Field Descriptors
*/
public static ClassDesc parseReferenceTypeDesc(String descriptor) {
int dLen = descriptor.length();
int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen);
if (len <= 1 || len != dLen)
throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor));
if (descriptor.charAt(0) == '[') {
return ArrayClassDescImpl.ofValidatedDescriptor(descriptor);
}
return ClassOrInterfaceDescImpl.ofValidated(descriptor);
}
/**
* Validates the correctness of a binary class name. In particular checks for the presence of
* invalid characters in the name.
@ -140,8 +185,9 @@ public final class ConstantUtils {
public static String validateBinaryClassName(String name) {
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '/')
throw new IllegalArgumentException("Invalid class name: " + name);
if (ch == ';' || ch == '[' || ch == '/'
|| ch == '.' && (i == 0 || i + 1 == name.length() || name.charAt(i - 1) == '.'))
throw invalidClassName(name);
}
return name;
}
@ -158,8 +204,9 @@ public final class ConstantUtils {
public static String validateInternalClassName(String name) {
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '.')
throw new IllegalArgumentException("Invalid class name: " + name);
if (ch == ';' || ch == '[' || ch == '.'
|| ch == '/' && (i == 0 || i + 1 == name.length() || name.charAt(i - 1) == '/'))
throw invalidClassName(name);
}
return name;
}
@ -256,10 +303,24 @@ public final class ConstantUtils {
throw new IllegalArgumentException("not a class or interface type: " + classDesc);
}
public static int arrayDepth(String descriptorString) {
public static void validateArrayRank(int rank) {
// array rank must be representable with u1 and nonzero
if (rank == 0 || (rank & ~0xFF) != 0) {
throw new IllegalArgumentException(invalidArrayRankMessage(rank));
}
}
/**
* Retrieves the array depth on a trusted descriptor.
* Uses a simple loop with the assumption that most descriptors have
* 0 or very low array depths.
*/
public static int arrayDepth(String descriptorString, int off) {
int depth = 0;
while (descriptorString.charAt(depth) == '[')
while (descriptorString.charAt(off) == '[') {
depth++;
off++;
}
return depth;
}
@ -296,7 +357,22 @@ public final class ConstantUtils {
}
// Pre-verified in MethodTypeDescImpl#ofDescriptor; avoid redundant verification
return ReferenceClassDescImpl.ofValidated(descriptor.substring(start, start + len));
int arrayDepth = arrayDepth(descriptor, start);
if (arrayDepth == 0) {
return ClassOrInterfaceDescImpl.ofValidated(descriptor.substring(start, start + len));
} else if (arrayDepth + 1 == len) {
return ArrayClassDescImpl.ofValidated(forPrimitiveType(descriptor, start + arrayDepth), arrayDepth);
} else {
return ArrayClassDescImpl.ofValidated(ClassOrInterfaceDescImpl.ofValidated(descriptor.substring(start + arrayDepth, start + len)), arrayDepth);
}
}
static String invalidArrayRankMessage(int rank) {
return "Array rank must be within [1, 255]: " + rank;
}
static IllegalArgumentException invalidClassName(String className) {
return new IllegalArgumentException("Invalid class name: ".concat(className));
}
static IllegalArgumentException badMethodDescriptor(String descriptor) {

View File

@ -39,13 +39,13 @@ import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import static java.lang.constant.ConstantDescs.CD_void;
import static java.util.Objects.requireNonNull;
import static jdk.internal.constant.ConstantUtils.badMethodDescriptor;
import static jdk.internal.constant.ConstantUtils.resolveClassDesc;
import static jdk.internal.constant.ConstantUtils.skipOverFieldSignature;
import static jdk.internal.constant.ConstantUtils.EMPTY_CLASSDESC;
import static jdk.internal.constant.PrimitiveClassDescImpl.CD_void;
/**
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
@ -86,7 +86,7 @@ public final class MethodTypeDescImpl implements MethodTypeDesc {
}
private static ClassDesc validateArgument(ClassDesc arg) {
if (arg.descriptorString().charAt(0) == 'V') // implicit null check
if (requireNonNull(arg) == CD_void)
throw new IllegalArgumentException("Void parameters not permitted");
return arg;
}

View File

@ -93,6 +93,31 @@ public final class PrimitiveClassDescImpl
return this.lazyWrapper = Wrapper.forBasicType(descriptorString().charAt(0));
}
@Override
public boolean isPrimitive() {
return true;
}
@Override
public ClassDesc arrayType(int rank) {
ConstantUtils.validateArrayRank(rank);
if (this == CD_void)
throw new IllegalArgumentException("not a valid reference type descriptor: " + "[".repeat(rank) + "V");
return ArrayClassDescImpl.ofValidated(this, rank);
}
@Override
public ClassDesc arrayType() {
if (this == CD_void)
throw new IllegalArgumentException("not a valid reference type descriptor: [V");
return ArrayClassDescImpl.ofValidated(this, 1);
}
@Override
public String displayName() {
return wrapper().primitiveSimpleName();
}
@Override
public String descriptorString() {
return descriptor;

View File

@ -1,147 +0,0 @@
/*
* Copyright (c) 2018, 2024, 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 jdk.internal.constant;
import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles;
import jdk.internal.vm.annotation.Stable;
import static jdk.internal.constant.ConstantUtils.*;
/**
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a class,
* interface, or array type. A {@linkplain ReferenceClassDescImpl} corresponds to a
* {@code Constant_Class_info} entry in the constant pool of a classfile.
*/
public final class ReferenceClassDescImpl implements ClassDesc {
private final String descriptor;
private @Stable String internalName;
private ReferenceClassDescImpl(String descriptor) {
this.descriptor = descriptor;
}
/**
* Creates a {@linkplain ClassDesc} from a descriptor string for a class or
* interface type or an array type.
*
* @param descriptor a field descriptor string for a class or interface type
* @throws IllegalArgumentException if the descriptor string is not a valid
* field descriptor string, or does not describe a class or interface type
* @jvms 4.3.2 Field Descriptors
*/
public static ReferenceClassDescImpl of(String descriptor) {
int dLen = descriptor.length();
int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen);
if (len <= 1 || len != dLen)
throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor));
return new ReferenceClassDescImpl(descriptor);
}
/**
* Creates a {@linkplain ClassDesc} from a pre-validated descriptor string
* for a class or interface type or an array type.
*
* @param descriptor a field descriptor string for a class or interface type
* @jvms 4.3.2 Field Descriptors
*/
public static ReferenceClassDescImpl ofValidated(String descriptor) {
assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length())
== descriptor.length() : descriptor;
return new ReferenceClassDescImpl(descriptor);
}
@Override
public String descriptorString() {
return descriptor;
}
public String internalName() {
var internalName = this.internalName;
if (internalName == null) {
var desc = this.descriptor;
this.internalName = internalName = desc.charAt(0) == 'L' ? dropFirstAndLastChar(desc) : desc;
}
return internalName;
}
@Override
public Class<?> resolveConstantDesc(MethodHandles.Lookup lookup)
throws ReflectiveOperationException {
if (isArray()) {
if (isPrimitiveArray()) {
return lookup.findClass(descriptor);
}
// Class.forName is slow on class or interface arrays
int depth = ConstantUtils.arrayDepth(descriptor);
Class<?> clazz = lookup.findClass(internalToBinary(descriptor.substring(depth + 1, descriptor.length() - 1)));
for (int i = 0; i < depth; i++)
clazz = clazz.arrayType();
return clazz;
}
return lookup.findClass(internalToBinary(internalName()));
}
/**
* Whether the descriptor is one of a primitive array, given this is
* already a valid reference type descriptor.
*/
private boolean isPrimitiveArray() {
// All L-type descriptors must end with a semicolon; same for reference
// arrays, leaving primitive arrays the only ones without a final semicolon
return descriptor.charAt(descriptor.length() - 1) != ';';
}
/**
* Returns {@code true} if this {@linkplain ReferenceClassDescImpl} is
* equal to another {@linkplain ReferenceClassDescImpl}. Equality is
* determined by the two class descriptors having equal class descriptor
* strings.
*
* @param o the {@code ClassDesc} to compare to this
* {@code ClassDesc}
* @return {@code true} if the specified {@code ClassDesc}
* is equal to this {@code ClassDesc}.
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof ReferenceClassDescImpl constant) {
return descriptor.equals(constant.descriptor);
}
return false;
}
@Override
public int hashCode() {
return descriptor.hashCode();
}
@Override
public String toString() {
return String.format("ClassDesc[%s]", displayName());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, 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
@ -40,9 +40,9 @@ import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
/**
/*
* @test
* @bug 8215510 8283075
* @bug 8215510 8283075 8338544
* @compile ClassDescTest.java
* @run testng ClassDescTest
* @summary unit tests for java.lang.constant.ClassDesc
@ -68,7 +68,30 @@ public class ClassDescTest extends SymbolicDescTest {
assertEquals(r, r.componentType().arrayType());
assertEquals(r, r.resolveConstantDesc(LOOKUP).getComponentType().describeConstable().orElseThrow().arrayType());
assertEquals(r, Array.newInstance(r.componentType().resolveConstantDesc(LOOKUP), 0).getClass().describeConstable().orElseThrow());
} else {
assertNull(r.componentType());
}
if (!r.isClassOrInterface()) {
assertEquals(r.packageName(), "");
}
}
private static String classDisplayName(Class<?> c) {
int arrayLevel = 0;
while (c.isArray()) {
arrayLevel++;
c = c.componentType();
}
String name = c.getName();
String simpleClassName;
if (c.isPrimitive()) {
simpleClassName = name;
} else {
int lastDot = name.lastIndexOf('.');
simpleClassName = lastDot == -1 ? name : name.substring(lastDot + 1);
}
return simpleClassName + "[]".repeat(arrayLevel);
}
private void testClassDesc(ClassDesc r, Class<?> c) throws ReflectiveOperationException {
@ -77,6 +100,13 @@ public class ClassDescTest extends SymbolicDescTest {
assertEquals(r.resolveConstantDesc(LOOKUP), c);
assertEquals(c.describeConstable().orElseThrow(), r);
assertEquals(ClassDesc.ofDescriptor(c.descriptorString()), r);
if (r.isArray()) {
testClassDesc(r.componentType(), c.componentType());
}
if (r.isClassOrInterface()) {
assertEquals(r.packageName(), c.getPackageName());
}
assertEquals(r.displayName(), classDisplayName(c));
}
public void testSymbolicDescsConstants() throws ReflectiveOperationException {
@ -143,7 +173,8 @@ public class ClassDescTest extends SymbolicDescTest {
assertFalse(r.isPrimitive());
assertEquals("Ljava/lang/String;", r.descriptorString());
assertEquals("String", r.displayName());
assertEquals(r.arrayType().resolveConstantDesc(LOOKUP), String[].class);
testClassDesc(r.arrayType(), String[].class);
testClassDesc(r.arrayType(3), String[][][].class);
stringClassDescs.forEach(rr -> assertEquals(r, rr));
}