diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index b93d9522352..9f58a4f94da 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -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 diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java index 708dfd8fb15..ceb8e023072 100644 --- a/src/java.base/share/classes/java/lang/constant/ConstantDescs.java +++ b/src/java.base/share/classes/java/lang/constant/ConstantDescs.java @@ -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} diff --git a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java index 94a271780c3..1ed7c422c98 100644 --- a/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java +++ b/src/java.base/share/classes/java/lang/invoke/ClassSpecializer.java @@ -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) { diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 10f282065fd..93784004994 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -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) { diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 5d307a9ff04..ec131d67f2b 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -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) { diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index 992ef387684..fd3e20a524e 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -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", diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 97848e1fcb3..cca16a18580 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -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); diff --git a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java index 83fefe07d51..f372e053260 100644 --- a/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java +++ b/src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java @@ -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()); } } diff --git a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java index abdcaf5ae1f..efbb3919ef5 100644 --- a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java +++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java @@ -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), diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 0c0144b24db..53f1572fa74 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -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); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index f0e0047f57d..0e26a8941e0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -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; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 85ee77b1720..d4bff1bfe80 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -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) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 848d153c24b..1088724d8b4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -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()); } diff --git a/src/java.base/share/classes/jdk/internal/constant/ArrayClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ArrayClassDescImpl.java new file mode 100644 index 00000000000..763975cb76b --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/constant/ArrayClassDescImpl.java @@ -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); + } +} diff --git a/src/java.base/share/classes/jdk/internal/constant/ClassOrInterfaceDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ClassOrInterfaceDescImpl.java new file mode 100644 index 00000000000..dcdb2cff8b5 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/constant/ClassOrInterfaceDescImpl.java @@ -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()); + } +} diff --git a/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java index 5640f849ab6..21791937649 100644 --- a/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java +++ b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java @@ -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) { diff --git a/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java index 6f59c476a6b..826fc095bbd 100644 --- a/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java +++ b/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java @@ -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; } diff --git a/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java index 35aa4007816..31ad92a2736 100644 --- a/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java +++ b/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java @@ -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; diff --git a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java deleted file mode 100644 index 8124abc6b75..00000000000 --- a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java +++ /dev/null @@ -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()); - } -} diff --git a/test/jdk/java/lang/constant/ClassDescTest.java b/test/jdk/java/lang/constant/ClassDescTest.java index 4d98e1283f0..839de27b178 100644 --- a/test/jdk/java/lang/constant/ClassDescTest.java +++ b/test/jdk/java/lang/constant/ClassDescTest.java @@ -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)); }