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 89be851dbf5..130a81420b6 100644
--- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java
+++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java
@@ -28,14 +28,19 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.TypeDescriptor;
import java.util.stream.Stream;
+import jdk.internal.constant.PrimitiveClassDescImpl;
+import jdk.internal.constant.ReferenceClassDescImpl;
import sun.invoke.util.Wrapper;
-import static java.lang.constant.ConstantUtils.binaryToInternal;
-import static java.lang.constant.ConstantUtils.dropLastChar;
-import static java.lang.constant.ConstantUtils.internalToBinary;
-import static java.lang.constant.ConstantUtils.validateMemberName;
-import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
+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.dropFirstAndLastChar;
+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;
/**
* A nominal descriptor for a
@@ -77,7 +82,7 @@ public sealed interface ClassDesc
* @see ClassDesc#ofInternalName(String)
*/
static ClassDesc of(String name) {
- ConstantUtils.validateBinaryClassName(requireNonNull(name));
+ validateBinaryClassName(name);
return ClassDesc.ofDescriptor("L" + binaryToInternal(name) + ";");
}
@@ -103,7 +108,7 @@ public sealed interface ClassDesc
* @since 20
*/
static ClassDesc ofInternalName(String name) {
- ConstantUtils.validateInternalClassName(requireNonNull(name));
+ validateInternalClassName(name);
return ClassDesc.ofDescriptor("L" + name + ";");
}
@@ -122,11 +127,11 @@ public sealed interface ClassDesc
* not in the correct format
*/
static ClassDesc of(String packageName, String className) {
- ConstantUtils.validateBinaryClassName(requireNonNull(packageName));
+ validateBinaryClassName(packageName);
if (packageName.isEmpty()) {
return of(className);
}
- validateMemberName(requireNonNull(className), false);
+ validateMemberName(className, false);
return ofDescriptor("L" + binaryToInternal(packageName) +
"/" + className + ";");
}
@@ -162,7 +167,7 @@ public sealed interface ClassDesc
return (descriptor.length() == 1)
? Wrapper.forPrimitiveType(descriptor.charAt(0)).classDescriptor()
// will throw IAE on descriptor.length == 0 or if array dimensions too long
- : new ReferenceClassDescImpl(descriptor);
+ : ReferenceClassDescImpl.of(descriptor);
}
/**
@@ -175,13 +180,18 @@ public sealed interface ClassDesc
* @jvms 4.4.1 The CONSTANT_Class_info Structure
*/
default ClassDesc arrayType() {
- int depth = ConstantUtils.arrayDepth(descriptorString());
- if (depth >= ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
+ 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 " +
- ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS + " dimensions");
+ MAX_ARRAY_TYPE_DESC_DIMENSIONS + " dimensions");
}
- return arrayType(1);
+ 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);
}
/**
@@ -196,22 +206,22 @@ public sealed interface ClassDesc
* @jvms 4.4.1 The CONSTANT_Class_info Structure
*/
default ClassDesc arrayType(int rank) {
- int netRank;
if (rank <= 0) {
throw new IllegalArgumentException("rank " + rank + " is not a positive value");
}
- try {
- int currentDepth = ConstantUtils.arrayDepth(descriptorString());
- netRank = Math.addExact(currentDepth, rank);
- if (netRank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
- throw new IllegalArgumentException("rank: " + netRank +
- " exceeds maximum supported dimension of " +
- ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS);
- }
- } catch (ArithmeticException ae) {
- throw new IllegalArgumentException("Integer overflow in rank computation");
+ 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);
}
- return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString());
+ 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);
}
/**
@@ -235,7 +245,10 @@ public sealed interface ClassDesc
validateMemberName(nestedName, false);
if (!isClassOrInterface())
throw new IllegalStateException("Outer class is not a class or interface type");
- return ClassDesc.ofDescriptor(dropLastChar(descriptorString()) + "$" + nestedName + ";");
+ 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());
}
/**
@@ -255,7 +268,7 @@ public sealed interface ClassDesc
if (!isClassOrInterface())
throw new IllegalStateException("Outer class is not a class or interface type");
validateMemberName(firstNestedName, false);
- requireNonNull(moreNestedNames);
+ // implicit null-check
for (String addNestedNames : moreNestedNames) {
validateMemberName(addNestedNames, false);
}
@@ -299,7 +312,15 @@ public sealed interface ClassDesc
* if this descriptor does not describe an array type
*/
default ClassDesc componentType() {
- return isArray() ? ClassDesc.ofDescriptor(descriptorString().substring(1)) : null;
+ if (isArray()) {
+ String desc = descriptorString();
+ if (desc.length() == 2) {
+ return Wrapper.forBasicType(desc.charAt(1)).classDescriptor();
+ } else {
+ return ReferenceClassDescImpl.ofValidated(desc.substring(1));
+ }
+ }
+ return null;
}
/**
@@ -312,9 +333,9 @@ public sealed interface ClassDesc
default String packageName() {
if (!isClassOrInterface())
return "";
- String className = internalToBinary(ConstantUtils.dropFirstAndLastChar(descriptorString()));
- int index = className.lastIndexOf('.');
- return (index == -1) ? "" : className.substring(0, index);
+ String desc = descriptorString();
+ int index = desc.lastIndexOf('/');
+ return (index == -1) ? "" : internalToBinary(desc.substring(1, index));
}
/**
@@ -332,11 +353,11 @@ public sealed interface ClassDesc
if (isPrimitive())
return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveSimpleName();
else if (isClassOrInterface()) {
- return descriptorString().substring(Math.max(1, descriptorString().lastIndexOf('/') + 1),
- descriptorString().length() - 1);
+ String desc = descriptorString();
+ return desc.substring(Math.max(1, desc.lastIndexOf('/') + 1), desc.length() - 1);
}
else if (isArray()) {
- int depth = ConstantUtils.arrayDepth(descriptorString());
+ int depth = arrayDepth(descriptorString());
ClassDesc c = this;
for (int i=0; inominal descriptor for an
diff --git a/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java b/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java
index 180841cd798..f89e3f361a1 100644
--- a/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java
+++ b/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.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
@@ -39,10 +39,10 @@ import java.util.stream.Stream;
import static java.lang.constant.ConstantDescs.CD_Class;
import static java.lang.constant.ConstantDescs.CD_VarHandle;
import static java.lang.constant.ConstantDescs.DEFAULT_NAME;
-import static java.lang.constant.ConstantUtils.EMPTY_CONSTANTDESC;
-import static java.lang.constant.ConstantUtils.validateMemberName;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
+import static jdk.internal.constant.ConstantUtils.EMPTY_CONSTANTDESC;
+import static jdk.internal.constant.ConstantUtils.validateMemberName;
/**
* A nominal descriptor for a
diff --git a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
index 91d6951153e..616c5b67365 100644
--- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
+++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.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
@@ -28,6 +28,8 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import jdk.internal.constant.DirectMethodHandleDescImpl;
+
import static java.lang.constant.ConstantDescs.CD_void;
import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java
index ff750ccc893..19bce254d49 100644
--- a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java
+++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.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
@@ -31,6 +31,11 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import jdk.internal.constant.ConstantUtils;
+import jdk.internal.constant.MethodTypeDescImpl;
+
+import static java.util.Objects.requireNonNull;
+
/**
* A nominal descriptor for a
* {@linkplain MethodType} constant.
@@ -64,7 +69,7 @@ public sealed interface MethodTypeDesc
* @since 21
*/
static MethodTypeDesc of(ClassDesc returnDesc) {
- return MethodTypeDescImpl.ofTrusted(returnDesc, ConstantUtils.EMPTY_CLASSDESC);
+ return MethodTypeDescImpl.ofValidated(requireNonNull(returnDesc), ConstantUtils.EMPTY_CLASSDESC);
}
/**
diff --git a/src/java.base/share/classes/java/lang/constant/ModuleDesc.java b/src/java.base/share/classes/java/lang/constant/ModuleDesc.java
index fe68d096f1d..b9690b7d0b3 100644
--- a/src/java.base/share/classes/java/lang/constant/ModuleDesc.java
+++ b/src/java.base/share/classes/java/lang/constant/ModuleDesc.java
@@ -24,6 +24,9 @@
*/
package java.lang.constant;
+import jdk.internal.constant.ConstantUtils;
+import jdk.internal.constant.ModuleDescImpl;
+
import static java.util.Objects.requireNonNull;
/**
diff --git a/src/java.base/share/classes/java/lang/constant/PackageDesc.java b/src/java.base/share/classes/java/lang/constant/PackageDesc.java
index 2dc20696a47..c354cafae3c 100644
--- a/src/java.base/share/classes/java/lang/constant/PackageDesc.java
+++ b/src/java.base/share/classes/java/lang/constant/PackageDesc.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 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
@@ -24,6 +24,9 @@
*/
package java.lang.constant;
+import jdk.internal.constant.ConstantUtils;
+import jdk.internal.constant.PackageDescImpl;
+
import static java.util.Objects.requireNonNull;
/**
diff --git a/src/java.base/share/classes/java/lang/constant/ConstantUtils.java b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java
similarity index 84%
rename from src/java.base/share/classes/java/lang/constant/ConstantUtils.java
rename to src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java
index d8a1ccd543b..8d761f4f04e 100644
--- a/src/java.base/share/classes/java/lang/constant/ConstantUtils.java
+++ b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java
@@ -22,28 +22,31 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package java.lang.constant;
+package jdk.internal.constant;
import sun.invoke.util.Wrapper;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.ConstantDescs;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
-import static java.util.Objects.requireNonNull;
-
/**
* Helper methods for the implementation of {@code java.lang.constant}.
*/
-class ConstantUtils {
+public final class ConstantUtils {
/** an empty constant descriptor */
public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0];
- static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0];
- static final Constable[] EMPTY_CONSTABLE = new Constable[0];
- static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255;
+ public static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0];
+ public static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255;
private static final Set pointyNames = Set.of(ConstantDescs.INIT_NAME, ConstantDescs.CLASS_INIT_NAME);
+ /** No instantiation */
+ private ConstantUtils() {}
+
/**
* Validates the correctness of a binary class name. In particular checks for the presence of
* invalid characters in the name.
@@ -51,9 +54,10 @@ class ConstantUtils {
* @param name the class name
* @return the class name passed if valid
* @throws IllegalArgumentException if the class name is invalid
+ * @throws NullPointerException if class name is {@code null}
*/
- static String validateBinaryClassName(String name) {
- for (int i=0; i= 0; i--) {
+ for (int i = name.length() - 1; i >= 0; i--) {
char ch = name.charAt(i);
if ((ch >= '\u0000' && ch <= '\u001F')
|| ((ch == '\\' || ch == ':' || ch =='@') && (i == 0 || name.charAt(--i) != '\\')))
@@ -144,11 +149,13 @@ class ConstantUtils {
* @param name the name of the member
* @return the name passed if valid
* @throws IllegalArgumentException if the member name is invalid
+ * @throws NullPointerException if the member name is {@code null}
*/
public static String validateMemberName(String name, boolean method) {
- if (name.length() == 0)
+ int len = name.length();
+ if (len == 0)
throw new IllegalArgumentException("zero-length member name");
- for (int i=0; i parseMethodDescriptor(String descriptor) {
+ public static List parseMethodDescriptor(String descriptor) {
int cur = 0, end = descriptor.length();
ArrayList ptypes = new ArrayList<>();
ptypes.add(null); // placeholder for return type
@@ -227,7 +230,8 @@ class ConstantUtils {
if (len == 1) {
return Wrapper.forPrimitiveType(descriptor.charAt(start)).classDescriptor();
}
- return ClassDesc.ofDescriptor(descriptor.substring(start, start + len));
+ // Pre-verified in parseMethodDescriptor; avoid redundant verification
+ return ReferenceClassDescImpl.ofValidated(descriptor.substring(start, start + len));
}
private static final char JVM_SIGNATURE_ARRAY = '[';
diff --git a/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/DirectMethodHandleDescImpl.java
similarity index 91%
rename from src/java.base/share/classes/java/lang/constant/DirectMethodHandleDescImpl.java
rename to src/java.base/share/classes/jdk/internal/constant/DirectMethodHandleDescImpl.java
index 47aa3dc36d2..0097ed6b0c2 100644
--- a/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDescImpl.java
+++ b/src/java.base/share/classes/jdk/internal/constant/DirectMethodHandleDescImpl.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
@@ -22,25 +22,28 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package java.lang.constant;
+package jdk.internal.constant;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.DirectMethodHandleDesc;
+import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Objects;
import static java.lang.constant.ConstantDescs.CD_void;
-import static java.lang.constant.ConstantUtils.validateClassOrInterface;
-import static java.lang.constant.ConstantUtils.validateMemberName;
import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
import static java.util.Objects.requireNonNull;
+import static jdk.internal.constant.ConstantUtils.validateClassOrInterface;
+import static jdk.internal.constant.ConstantUtils.validateMemberName;
/**
* A nominal descriptor for a direct
* {@link MethodHandle}. A {@linkplain DirectMethodHandleDescImpl} corresponds to
* a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
*/
-final class DirectMethodHandleDescImpl implements DirectMethodHandleDesc {
+public final class DirectMethodHandleDescImpl implements DirectMethodHandleDesc {
private final Kind kind;
private final ClassDesc owner;
@@ -62,7 +65,7 @@ final class DirectMethodHandleDescImpl implements DirectMethodHandleDesc {
* is not {@code void}
* @jvms 4.2.2 Unqualified Names
*/
- DirectMethodHandleDescImpl(Kind kind, ClassDesc owner, String name, MethodTypeDesc type) {
+ public DirectMethodHandleDescImpl(Kind kind, ClassDesc owner, String name, MethodTypeDesc type) {
if (kind == CONSTRUCTOR)
name = "";
@@ -82,12 +85,11 @@ final class DirectMethodHandleDescImpl implements DirectMethodHandleDesc {
this.kind = kind;
this.owner = owner;
this.name = name;
- if (kind.isVirtualMethod())
- this.invocationType = type.insertParameterTypes(0, owner);
- else if (kind == CONSTRUCTOR)
- this.invocationType = type.changeReturnType(owner);
- else
- this.invocationType = type;
+ this.invocationType = switch (kind) {
+ case VIRTUAL, SPECIAL, INTERFACE_VIRTUAL, INTERFACE_SPECIAL -> type.insertParameterTypes(0, owner);
+ case CONSTRUCTOR -> type.changeReturnType(owner);
+ default -> type;
+ };
}
private static void validateFieldType(MethodTypeDesc type, boolean isSetter, boolean isVirtual) {
diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java
similarity index 80%
rename from src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java
rename to src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java
index 7ee0995439a..d6d622b419c 100644
--- a/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java
+++ b/src/java.base/share/classes/jdk/internal/constant/MethodTypeDescImpl.java
@@ -22,10 +22,12 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package java.lang.constant;
+package jdk.internal.constant;
import jdk.internal.vm.annotation.Stable;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.security.AccessController;
@@ -41,7 +43,7 @@ import static java.util.Objects.requireNonNull;
* {@link MethodType}. A {@linkplain MethodTypeDescImpl} corresponds to a
* {@code Constant_MethodType_info} entry in the constant pool of a classfile.
*/
-final class MethodTypeDescImpl implements MethodTypeDesc {
+public final class MethodTypeDescImpl implements MethodTypeDesc {
private final ClassDesc returnType;
private final @Stable ClassDesc[] argTypes;
private @Stable String cachedDescriptorString;
@@ -65,15 +67,31 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
* @param returnType a {@link ClassDesc} describing the return type
* @param trustedArgTypes {@link ClassDesc}s describing the trusted parameter types
*/
- static MethodTypeDescImpl ofTrusted(ClassDesc returnType, ClassDesc[] trustedArgTypes) {
+ public static MethodTypeDescImpl ofTrusted(ClassDesc returnType, ClassDesc[] trustedArgTypes) {
requireNonNull(returnType);
- if (trustedArgTypes.length == 0) // implicit null check
+ // implicit null checks of trustedArgTypes and all elements
+ for (ClassDesc cd : trustedArgTypes) {
+ validateArgument(cd);
+ }
+ return ofValidated(returnType, trustedArgTypes);
+ }
+
+ private static ClassDesc validateArgument(ClassDesc arg) {
+ if (arg.descriptorString().charAt(0) == 'V') // implicit null check
+ throw new IllegalArgumentException("Void parameters not permitted");
+ return arg;
+ }
+
+ /**
+ * Constructs a {@linkplain MethodTypeDesc} with the specified pre-validated return type
+ * and a pre-validated trusted parameter types array.
+ *
+ * @param returnType a {@link ClassDesc} describing the return type
+ * @param trustedArgTypes {@link ClassDesc}s describing the trusted parameter types
+ */
+ public static MethodTypeDescImpl ofValidated(ClassDesc returnType, ClassDesc[] trustedArgTypes) {
+ if (trustedArgTypes.length == 0)
return new MethodTypeDescImpl(returnType, ConstantUtils.EMPTY_CLASSDESC);
-
- for (ClassDesc cd : trustedArgTypes)
- if (cd.descriptorString().charAt(0) == 'V') // implicit null check
- throw new IllegalArgumentException("Void parameters not permitted");
-
return new MethodTypeDescImpl(returnType, trustedArgTypes);
}
@@ -86,7 +104,7 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
* method descriptor
* @jvms 4.3.3 Method Descriptors
*/
- static MethodTypeDescImpl ofDescriptor(String descriptor) {
+ public static MethodTypeDescImpl ofDescriptor(String descriptor) {
// Implicit null-check of descriptor
List ptypes = ConstantUtils.parseMethodDescriptor(descriptor);
int args = ptypes.size() - 1;
@@ -94,7 +112,7 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
? ptypes.subList(1, args + 1).toArray(ConstantUtils.EMPTY_CLASSDESC)
: ConstantUtils.EMPTY_CLASSDESC;
- MethodTypeDescImpl result = ofTrusted(ptypes.get(0), paramTypes);
+ MethodTypeDescImpl result = ofValidated(ptypes.get(0), paramTypes);
result.cachedDescriptorString = descriptor;
return result;
}
@@ -127,14 +145,14 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
@Override
public MethodTypeDesc changeReturnType(ClassDesc returnType) {
- return new MethodTypeDescImpl(requireNonNull(returnType), argTypes);
+ return ofValidated(requireNonNull(returnType), argTypes);
}
@Override
public MethodTypeDesc changeParameterType(int index, ClassDesc paramType) {
ClassDesc[] newArgs = argTypes.clone();
- newArgs[index] = paramType;
- return ofTrusted(returnType, newArgs);
+ newArgs[index] = validateArgument(paramType);
+ return ofValidated(returnType, newArgs);
}
@Override
@@ -149,7 +167,7 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
if (end < argTypes.length) {
System.arraycopy(argTypes, end, newArgs, start, argTypes.length - end);
}
- return ofTrusted(returnType, newArgs);
+ return ofValidated(returnType, newArgs);
}
@Override
@@ -162,10 +180,16 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
System.arraycopy(argTypes, 0, newArgs, 0, pos);
}
System.arraycopy(paramTypes, 0, newArgs, pos, paramTypes.length);
+ int destPos = pos + paramTypes.length;
if (pos < argTypes.length) {
- System.arraycopy(argTypes, pos, newArgs, pos + paramTypes.length, argTypes.length - pos);
+ System.arraycopy(argTypes, pos, newArgs, destPos, argTypes.length - pos);
}
- return ofTrusted(returnType, newArgs);
+ // Validate after copying to avoid TOCTOU
+ for (int i = pos; i < destPos; i++) {
+ validateArgument(newArgs[i]);
+ }
+
+ return ofValidated(returnType, newArgs);
}
@Override
diff --git a/src/java.base/share/classes/java/lang/constant/ModuleDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ModuleDescImpl.java
similarity index 86%
rename from src/java.base/share/classes/java/lang/constant/ModuleDescImpl.java
rename to src/java.base/share/classes/jdk/internal/constant/ModuleDescImpl.java
index 0a01f5b2b73..89310c1331c 100644
--- a/src/java.base/share/classes/java/lang/constant/ModuleDescImpl.java
+++ b/src/java.base/share/classes/jdk/internal/constant/ModuleDescImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 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
@@ -22,13 +22,15 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package java.lang.constant;
+package jdk.internal.constant;
+
+import java.lang.constant.ModuleDesc;
/*
* Implementation of {@code ModuleDesc}
* @param name must have been validated
*/
-record ModuleDescImpl(String name) implements ModuleDesc {
+public record ModuleDescImpl(String name) implements ModuleDesc {
@Override
public String toString() {
diff --git a/src/java.base/share/classes/java/lang/constant/PackageDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/PackageDescImpl.java
similarity index 85%
rename from src/java.base/share/classes/java/lang/constant/PackageDescImpl.java
rename to src/java.base/share/classes/jdk/internal/constant/PackageDescImpl.java
index 1f0077007b8..3ef65b4e4ea 100644
--- a/src/java.base/share/classes/java/lang/constant/PackageDescImpl.java
+++ b/src/java.base/share/classes/jdk/internal/constant/PackageDescImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 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
@@ -22,13 +22,15 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package java.lang.constant;
+package jdk.internal.constant;
+
+import java.lang.constant.PackageDesc;
/*
* Implementation of {@code PackageDesc}
* @param internalName must have been validated
*/
-record PackageDescImpl(String internalName) implements PackageDesc {
+public record PackageDescImpl(String internalName) implements PackageDesc {
@Override
public String toString() {
diff --git a/src/java.base/share/classes/java/lang/constant/PrimitiveClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java
similarity index 88%
rename from src/java.base/share/classes/java/lang/constant/PrimitiveClassDescImpl.java
rename to src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java
index 0478fbe3bba..123c76a1e9f 100644
--- a/src/java.base/share/classes/java/lang/constant/PrimitiveClassDescImpl.java
+++ b/src/java.base/share/classes/jdk/internal/constant/PrimitiveClassDescImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 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
@@ -22,8 +22,11 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package java.lang.constant;
+package jdk.internal.constant;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DynamicConstantDesc;
import java.lang.invoke.MethodHandles;
import sun.invoke.util.Wrapper;
@@ -34,7 +37,7 @@ import static java.util.Objects.requireNonNull;
* A nominal descriptor for the class
* constant corresponding to a primitive type (e.g., {@code int.class}).
*/
-final class PrimitiveClassDescImpl
+public final class PrimitiveClassDescImpl
extends DynamicConstantDesc> implements ClassDesc {
private final String descriptor;
@@ -49,7 +52,7 @@ final class PrimitiveClassDescImpl
* describe a valid primitive type
* @jvms 4.3 Descriptors
*/
- PrimitiveClassDescImpl(String descriptor) {
+ public PrimitiveClassDescImpl(String descriptor) {
super(ConstantDescs.BSM_PRIMITIVE_CLASS, requireNonNull(descriptor), ConstantDescs.CD_Class);
if (descriptor.length() != 1
|| "VIJCSBFDZ".indexOf(descriptor.charAt(0)) < 0)
diff --git a/src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java
similarity index 83%
rename from src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java
rename to src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java
index 5e2aaa98442..e8d73b08097 100644
--- a/src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java
+++ b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.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
@@ -22,21 +22,25 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package java.lang.constant;
+package jdk.internal.constant;
+import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles;
-import static java.lang.constant.ConstantUtils.*;
-import static java.util.Objects.requireNonNull;
+import static jdk.internal.constant.ConstantUtils.*;
/**
* A nominal descriptor 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.
*/
-final class ReferenceClassDescImpl implements ClassDesc {
+public final class ReferenceClassDescImpl implements ClassDesc {
private final String descriptor;
+ 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.
@@ -46,12 +50,23 @@ final class ReferenceClassDescImpl implements ClassDesc {
* field descriptor string, or does not describe a class or interface type
* @jvms 4.3.2 Field Descriptors
*/
- ReferenceClassDescImpl(String descriptor) {
+ public static ReferenceClassDescImpl of(String descriptor) {
int dLen = descriptor.length();
int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen, false);
if (len <= 1 || len != dLen)
throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor));
- this.descriptor = 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) {
+ return new ReferenceClassDescImpl(descriptor);
}
@Override
diff --git a/test/jdk/java/lang/constant/ClassDescTest.java b/test/jdk/java/lang/constant/ClassDescTest.java
index 4c9493721d9..4d98e1283f0 100644
--- a/test/jdk/java/lang/constant/ClassDescTest.java
+++ b/test/jdk/java/lang/constant/ClassDescTest.java
@@ -237,6 +237,12 @@ public class ClassDescTest extends SymbolicDescTest {
testBadArrayRank(ClassDesc.of("Bar"));
testArrayRankOverflow();
}
+ try {
+ ConstantDescs.CD_void.arrayType();
+ fail("Should throw IAE");
+ } catch (IllegalArgumentException iae) {
+ // Expected
+ }
}
public void testBadClassDescs() {
diff --git a/test/jdk/java/lang/constant/boottest/java.base/java/lang/constant/ConstantUtilsTest.java b/test/jdk/java/lang/constant/boottest/java.base/jdk/internal/constant/ConstantUtilsTest.java
similarity index 94%
rename from test/jdk/java/lang/constant/boottest/java.base/java/lang/constant/ConstantUtilsTest.java
rename to test/jdk/java/lang/constant/boottest/java.base/jdk/internal/constant/ConstantUtilsTest.java
index 12ef29273dc..f3e9619a0e1 100644
--- a/test/jdk/java/lang/constant/boottest/java.base/java/lang/constant/ConstantUtilsTest.java
+++ b/test/jdk/java/lang/constant/boottest/java.base/jdk/internal/constant/ConstantUtilsTest.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
@@ -21,9 +21,8 @@
* questions.
*/
-package java.lang.constant;
+package jdk.internal.constant;
-import java.lang.invoke.*;
import java.lang.constant.*;
import java.util.*;
@@ -35,6 +34,7 @@ import static org.testng.Assert.*;
* @test
* @bug 8303930
* @compile ConstantUtilsTest.java
+ * @modules java.base/jdk.internal.constant
* @run testng ConstantUtilsTest
* @summary unit tests for methods of java.lang.constant.ConstantUtils that are not covered by other unit tests
*/
diff --git a/test/micro/org/openjdk/bench/java/lang/constant/ClassDescFactories.java b/test/micro/org/openjdk/bench/java/lang/constant/ClassDescFactories.java
index c74271995d5..c9ce4a6c100 100644
--- a/test/micro/org/openjdk/bench/java/lang/constant/ClassDescFactories.java
+++ b/test/micro/org/openjdk/bench/java/lang/constant/ClassDescFactories.java
@@ -35,6 +35,7 @@ import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDescs;
import java.util.concurrent.TimeUnit;
/**
@@ -60,4 +61,19 @@ public class ClassDescFactories {
public ClassDesc ofDescriptor() {
return ClassDesc.ofDescriptor(descString);
}
+
+ @BenchmarkMode(Mode.AverageTime)
+ @OutputTimeUnit(TimeUnit.NANOSECONDS)
+ @Warmup(iterations = 3, time = 2)
+ @Measurement(iterations = 6, time = 1)
+ @Fork(1)
+ @State(Scope.Thread)
+ public static class ReferenceOnly {
+ public ClassDesc desc = ConstantDescs.CD_Object;
+ @Benchmark
+ public ClassDesc ofNested() {
+ return desc.nested("Foo");
+ }
+
+ }
}
diff --git a/test/micro/org/openjdk/bench/java/lang/constant/ClassDescMethods.java b/test/micro/org/openjdk/bench/java/lang/constant/ClassDescMethods.java
new file mode 100644
index 00000000000..8d9f686b013
--- /dev/null
+++ b/test/micro/org/openjdk/bench/java/lang/constant/ClassDescMethods.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * 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 org.openjdk.bench.java.lang.constant;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.infra.Blackhole;
+
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDescs;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test various operations on
+ */
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@Warmup(iterations = 3, time = 2)
+@Measurement(iterations = 5, time = 1)
+@Fork(3)
+@State(Scope.Thread)
+public class ClassDescMethods {
+
+ @Benchmark
+ public String packageName() {
+ return ConstantDescs.CD_Object.packageName();
+ }
+
+ @Benchmark
+ public String displayName() {
+ return ConstantDescs.CD_Object.displayName();
+ }
+
+ @Benchmark
+ public void arrayType(Blackhole bh) {
+ bh.consume(ConstantDescs.CD_Object.arrayType());
+ bh.consume(ConstantDescs.CD_boolean.arrayType());
+ }
+
+ @Benchmark
+ public void arrayType1(Blackhole bh) {
+ bh.consume(ConstantDescs.CD_Object.arrayType(1));
+ bh.consume(ConstantDescs.CD_boolean.arrayType(1));
+ }
+
+ @Benchmark
+ public void arrayType2(Blackhole bh) {
+ bh.consume(ConstantDescs.CD_Object.arrayType(2));
+ bh.consume(ConstantDescs.CD_boolean.arrayType(2));
+ }
+}