8331724: Refactor j.l.constant implementation to internal package

Reviewed-by: liach, asotona
This commit is contained in:
Claes Redestad 2024-05-17 09:49:44 +00:00
parent d84a8fd876
commit 0b0445be28
20 changed files with 364 additions and 192 deletions

View file

@ -28,14 +28,19 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.TypeDescriptor; import java.lang.invoke.TypeDescriptor;
import java.util.stream.Stream; import java.util.stream.Stream;
import jdk.internal.constant.PrimitiveClassDescImpl;
import jdk.internal.constant.ReferenceClassDescImpl;
import sun.invoke.util.Wrapper; 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 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 <a href="package-summary.html#nominal">nominal descriptor</a> for a * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
@ -77,7 +82,7 @@ public sealed interface ClassDesc
* @see ClassDesc#ofInternalName(String) * @see ClassDesc#ofInternalName(String)
*/ */
static ClassDesc of(String name) { static ClassDesc of(String name) {
ConstantUtils.validateBinaryClassName(requireNonNull(name)); validateBinaryClassName(name);
return ClassDesc.ofDescriptor("L" + binaryToInternal(name) + ";"); return ClassDesc.ofDescriptor("L" + binaryToInternal(name) + ";");
} }
@ -103,7 +108,7 @@ public sealed interface ClassDesc
* @since 20 * @since 20
*/ */
static ClassDesc ofInternalName(String name) { static ClassDesc ofInternalName(String name) {
ConstantUtils.validateInternalClassName(requireNonNull(name)); validateInternalClassName(name);
return ClassDesc.ofDescriptor("L" + name + ";"); return ClassDesc.ofDescriptor("L" + name + ";");
} }
@ -122,11 +127,11 @@ public sealed interface ClassDesc
* not in the correct format * not in the correct format
*/ */
static ClassDesc of(String packageName, String className) { static ClassDesc of(String packageName, String className) {
ConstantUtils.validateBinaryClassName(requireNonNull(packageName)); validateBinaryClassName(packageName);
if (packageName.isEmpty()) { if (packageName.isEmpty()) {
return of(className); return of(className);
} }
validateMemberName(requireNonNull(className), false); validateMemberName(className, false);
return ofDescriptor("L" + binaryToInternal(packageName) + return ofDescriptor("L" + binaryToInternal(packageName) +
"/" + className + ";"); "/" + className + ";");
} }
@ -162,7 +167,7 @@ public sealed interface ClassDesc
return (descriptor.length() == 1) return (descriptor.length() == 1)
? Wrapper.forPrimitiveType(descriptor.charAt(0)).classDescriptor() ? Wrapper.forPrimitiveType(descriptor.charAt(0)).classDescriptor()
// will throw IAE on descriptor.length == 0 or if array dimensions too long // 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 * @jvms 4.4.1 The CONSTANT_Class_info Structure
*/ */
default ClassDesc arrayType() { default ClassDesc arrayType() {
int depth = ConstantUtils.arrayDepth(descriptorString()); String desc = descriptorString();
if (depth >= ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) { int depth = arrayDepth(desc);
if (depth >= MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
throw new IllegalStateException( throw new IllegalStateException(
"Cannot create an array type descriptor with more than " + "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 * @jvms 4.4.1 The CONSTANT_Class_info Structure
*/ */
default ClassDesc arrayType(int rank) { default ClassDesc arrayType(int rank) {
int netRank;
if (rank <= 0) { if (rank <= 0) {
throw new IllegalArgumentException("rank " + rank + " is not a positive value"); throw new IllegalArgumentException("rank " + rank + " is not a positive value");
} }
try { String desc = descriptorString();
int currentDepth = ConstantUtils.arrayDepth(descriptorString()); long currentDepth = arrayDepth(desc);
netRank = Math.addExact(currentDepth, rank); long netRank = currentDepth + rank;
if (netRank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) { if (netRank > MAX_ARRAY_TYPE_DESC_DIMENSIONS) {
throw new IllegalArgumentException("rank: " + netRank + throw new IllegalArgumentException("rank: " + netRank +
" exceeds maximum supported dimension of " + " exceeds maximum supported dimension of " +
ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS); MAX_ARRAY_TYPE_DESC_DIMENSIONS);
}
} catch (ArithmeticException ae) {
throw new IllegalArgumentException("Integer overflow in rank computation");
} }
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); validateMemberName(nestedName, false);
if (!isClassOrInterface()) if (!isClassOrInterface())
throw new IllegalStateException("Outer class is not a class or interface type"); 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()) if (!isClassOrInterface())
throw new IllegalStateException("Outer class is not a class or interface type"); throw new IllegalStateException("Outer class is not a class or interface type");
validateMemberName(firstNestedName, false); validateMemberName(firstNestedName, false);
requireNonNull(moreNestedNames); // implicit null-check
for (String addNestedNames : moreNestedNames) { for (String addNestedNames : moreNestedNames) {
validateMemberName(addNestedNames, false); validateMemberName(addNestedNames, false);
} }
@ -299,7 +312,15 @@ public sealed interface ClassDesc
* if this descriptor does not describe an array type * if this descriptor does not describe an array type
*/ */
default ClassDesc componentType() { 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() { default String packageName() {
if (!isClassOrInterface()) if (!isClassOrInterface())
return ""; return "";
String className = internalToBinary(ConstantUtils.dropFirstAndLastChar(descriptorString())); String desc = descriptorString();
int index = className.lastIndexOf('.'); int index = desc.lastIndexOf('/');
return (index == -1) ? "" : className.substring(0, index); return (index == -1) ? "" : internalToBinary(desc.substring(1, index));
} }
/** /**
@ -332,11 +353,11 @@ public sealed interface ClassDesc
if (isPrimitive()) if (isPrimitive())
return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveSimpleName(); return Wrapper.forBasicType(descriptorString().charAt(0)).primitiveSimpleName();
else if (isClassOrInterface()) { else if (isClassOrInterface()) {
return descriptorString().substring(Math.max(1, descriptorString().lastIndexOf('/') + 1), String desc = descriptorString();
descriptorString().length() - 1); return desc.substring(Math.max(1, desc.lastIndexOf('/') + 1), desc.length() - 1);
} }
else if (isArray()) { else if (isArray()) {
int depth = ConstantUtils.arrayDepth(descriptorString()); int depth = arrayDepth(descriptorString());
ClassDesc c = this; ClassDesc c = this;
for (int i=0; i<depth; i++) for (int i=0; i<depth; i++)
c = c.componentType(); c = c.componentType();

View file

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

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -26,9 +26,8 @@ package java.lang.constant;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandleInfo; import java.lang.invoke.MethodHandleInfo;
import java.util.OptionalInt;
import java.util.stream.Stream;
import jdk.internal.constant.DirectMethodHandleDescImpl;
import jdk.internal.vm.annotation.Stable; import jdk.internal.vm.annotation.Stable;
import static java.lang.invoke.MethodHandleInfo.REF_getField; import static java.lang.invoke.MethodHandleInfo.REF_getField;
@ -89,7 +88,7 @@ public sealed interface DirectMethodHandleDesc
*/ */
public final boolean isInterface; public final boolean isInterface;
Kind(int refKind) { Kind(int refKind) {
this(refKind, false); this.refKind = refKind; this.isInterface = false;
} }
Kind(int refKind, boolean isInterface) { this.refKind = refKind; this.isInterface = isInterface; } Kind(int refKind, boolean isInterface) { this.refKind = refKind; this.isInterface = isInterface; }
@ -179,23 +178,6 @@ public sealed interface DirectMethodHandleDesc
} }
} }
} }
/**
* Does this {@code Kind} correspond to a virtual method invocation?
*
* @return if this {@code Kind} corresponds to a virtual method invocation
*/
boolean isVirtualMethod() {
switch (this) {
case VIRTUAL:
case SPECIAL:
case INTERFACE_VIRTUAL:
case INTERFACE_SPECIAL:
return true;
default:
return false;
}
}
} }
/** /**

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -32,10 +32,10 @@ import java.util.Objects;
import java.util.stream.Stream; import java.util.stream.Stream;
import static java.lang.constant.ConstantDescs.CD_String; import static java.lang.constant.ConstantDescs.CD_String;
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.Objects.requireNonNull;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
import static jdk.internal.constant.ConstantUtils.EMPTY_CONSTANTDESC;
import static jdk.internal.constant.ConstantUtils.validateMemberName;
/** /**
* A <a href="package-summary.html#nominal">nominal descriptor</a> for an * A <a href="package-summary.html#nominal">nominal descriptor</a> for an

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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_Class;
import static java.lang.constant.ConstantDescs.CD_VarHandle; import static java.lang.constant.ConstantDescs.CD_VarHandle;
import static java.lang.constant.ConstantDescs.DEFAULT_NAME; 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.Objects.requireNonNull;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
import static jdk.internal.constant.ConstantUtils.EMPTY_CONSTANTDESC;
import static jdk.internal.constant.ConstantUtils.validateMemberName;
/** /**
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a * A <a href="package-summary.html#nominal">nominal descriptor</a> for a

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import jdk.internal.constant.DirectMethodHandleDescImpl;
import static java.lang.constant.ConstantDescs.CD_void; import static java.lang.constant.ConstantDescs.CD_void;
import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR; import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.MethodTypeDescImpl;
import static java.util.Objects.requireNonNull;
/** /**
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
* {@linkplain MethodType} constant. * {@linkplain MethodType} constant.
@ -64,7 +69,7 @@ public sealed interface MethodTypeDesc
* @since 21 * @since 21
*/ */
static MethodTypeDesc of(ClassDesc returnDesc) { static MethodTypeDesc of(ClassDesc returnDesc) {
return MethodTypeDescImpl.ofTrusted(returnDesc, ConstantUtils.EMPTY_CLASSDESC); return MethodTypeDescImpl.ofValidated(requireNonNull(returnDesc), ConstantUtils.EMPTY_CLASSDESC);
} }
/** /**

View file

@ -24,6 +24,9 @@
*/ */
package java.lang.constant; package java.lang.constant;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.ModuleDescImpl;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
/** /**

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,6 +24,9 @@
*/ */
package java.lang.constant; package java.lang.constant;
import jdk.internal.constant.ConstantUtils;
import jdk.internal.constant.PackageDescImpl;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
/** /**

View file

@ -22,28 +22,31 @@
* or visit www.oracle.com if you need additional information or have any * or visit www.oracle.com if you need additional information or have any
* questions. * questions.
*/ */
package java.lang.constant; package jdk.internal.constant;
import sun.invoke.util.Wrapper; 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.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static java.util.Objects.requireNonNull;
/** /**
* Helper methods for the implementation of {@code java.lang.constant}. * Helper methods for the implementation of {@code java.lang.constant}.
*/ */
class ConstantUtils { public final class ConstantUtils {
/** an empty constant descriptor */ /** an empty constant descriptor */
public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0]; public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0];
static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0]; public static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0];
static final Constable[] EMPTY_CONSTABLE = new Constable[0]; public static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255;
static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255;
private static final Set<String> pointyNames = Set.of(ConstantDescs.INIT_NAME, ConstantDescs.CLASS_INIT_NAME); private static final Set<String> 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 * Validates the correctness of a binary class name. In particular checks for the presence of
* invalid characters in the name. * invalid characters in the name.
@ -51,9 +54,10 @@ class ConstantUtils {
* @param name the class name * @param name the class name
* @return the class name passed if valid * @return the class name passed if valid
* @throws IllegalArgumentException if the class name is invalid * @throws IllegalArgumentException if the class name is invalid
* @throws NullPointerException if class name is {@code null}
*/ */
static String validateBinaryClassName(String name) { public static String validateBinaryClassName(String name) {
for (int i=0; i<name.length(); i++) { for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i); char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '/') if (ch == ';' || ch == '[' || ch == '/')
throw new IllegalArgumentException("Invalid class name: " + name); throw new IllegalArgumentException("Invalid class name: " + name);
@ -62,21 +66,22 @@ class ConstantUtils {
} }
/** /**
* Validates the correctness of an internal class name. * Validates the correctness of an internal class name.
* In particular checks for the presence of invalid characters in the name. * In particular checks for the presence of invalid characters in the name.
* *
* @param name the class name * @param name the class name
* @return the class name passed if valid * @return the class name passed if valid
* @throws IllegalArgumentException if the class name is invalid * @throws IllegalArgumentException if the class name is invalid
*/ * @throws NullPointerException if class name is {@code null}
static String validateInternalClassName(String name) { */
for (int i=0; i<name.length(); i++) { public static String validateInternalClassName(String name) {
char ch = name.charAt(i); for (int i = 0; i < name.length(); i++) {
if (ch == ';' || ch == '[' || ch == '.') char ch = name.charAt(i);
throw new IllegalArgumentException("Invalid class name: " + name); if (ch == ';' || ch == '[' || ch == '.')
} throw new IllegalArgumentException("Invalid class name: " + name);
return name; }
} return name;
}
/** /**
* Validates the correctness of a binary package name. * Validates the correctness of a binary package name.
@ -89,7 +94,7 @@ class ConstantUtils {
* @throws NullPointerException if the package name is {@code null} * @throws NullPointerException if the package name is {@code null}
*/ */
public static String validateBinaryPackageName(String name) { public static String validateBinaryPackageName(String name) {
for (int i=0; i<name.length(); i++) { for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i); char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '/') if (ch == ';' || ch == '[' || ch == '/')
throw new IllegalArgumentException("Invalid package name: " + name); throw new IllegalArgumentException("Invalid package name: " + name);
@ -108,7 +113,7 @@ class ConstantUtils {
* @throws NullPointerException if the package name is {@code null} * @throws NullPointerException if the package name is {@code null}
*/ */
public static String validateInternalPackageName(String name) { public static String validateInternalPackageName(String name) {
for (int i=0; i<name.length(); i++) { for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i); char ch = name.charAt(i);
if (ch == ';' || ch == '[' || ch == '.') if (ch == ';' || ch == '[' || ch == '.')
throw new IllegalArgumentException("Invalid package name: " + name); throw new IllegalArgumentException("Invalid package name: " + name);
@ -129,7 +134,7 @@ class ConstantUtils {
* @throws NullPointerException if the module name is {@code null} * @throws NullPointerException if the module name is {@code null}
*/ */
public static String validateModuleName(String name) { public static String validateModuleName(String name) {
for (int i=name.length() - 1; i >= 0; i--) { for (int i = name.length() - 1; i >= 0; i--) {
char ch = name.charAt(i); char ch = name.charAt(i);
if ((ch >= '\u0000' && ch <= '\u001F') if ((ch >= '\u0000' && ch <= '\u001F')
|| ((ch == '\\' || ch == ':' || ch =='@') && (i == 0 || name.charAt(--i) != '\\'))) || ((ch == '\\' || ch == ':' || ch =='@') && (i == 0 || name.charAt(--i) != '\\')))
@ -144,11 +149,13 @@ class ConstantUtils {
* @param name the name of the member * @param name the name of the member
* @return the name passed if valid * @return the name passed if valid
* @throws IllegalArgumentException if the member name is invalid * @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) { 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"); throw new IllegalArgumentException("zero-length member name");
for (int i=0; i<name.length(); i++) { for (int i = 0; i < len; i++) {
char ch = name.charAt(i); char ch = name.charAt(i);
if (ch == '.' || ch == ';' || ch == '[' || ch == '/') if (ch == '.' || ch == ';' || ch == '[' || ch == '/')
throw new IllegalArgumentException("Invalid member name: " + name); throw new IllegalArgumentException("Invalid member name: " + name);
@ -160,31 +167,27 @@ class ConstantUtils {
return name; return name;
} }
static void validateClassOrInterface(ClassDesc classDesc) { public static void validateClassOrInterface(ClassDesc classDesc) {
if (!classDesc.isClassOrInterface()) if (!classDesc.isClassOrInterface())
throw new IllegalArgumentException("not a class or interface type: " + classDesc); throw new IllegalArgumentException("not a class or interface type: " + classDesc);
} }
static int arrayDepth(String descriptorString) { public static int arrayDepth(String descriptorString) {
int depth = 0; int depth = 0;
while (descriptorString.charAt(depth) == '[') while (descriptorString.charAt(depth) == '[')
depth++; depth++;
return depth; return depth;
} }
static String binaryToInternal(String name) { public static String binaryToInternal(String name) {
return name.replace('.', '/'); return name.replace('.', '/');
} }
static String internalToBinary(String name) { public static String internalToBinary(String name) {
return name.replace('/', '.'); return name.replace('/', '.');
} }
static String dropLastChar(String s) { public static String dropFirstAndLastChar(String s) {
return s.substring(0, s.length() - 1);
}
static String dropFirstAndLastChar(String s) {
return s.substring(1, s.length() - 1); return s.substring(1, s.length() - 1);
} }
@ -196,7 +199,7 @@ class ConstantUtils {
* @return the list of types * @return the list of types
* @throws IllegalArgumentException if the descriptor string is not valid * @throws IllegalArgumentException if the descriptor string is not valid
*/ */
static List<ClassDesc> parseMethodDescriptor(String descriptor) { public static List<ClassDesc> parseMethodDescriptor(String descriptor) {
int cur = 0, end = descriptor.length(); int cur = 0, end = descriptor.length();
ArrayList<ClassDesc> ptypes = new ArrayList<>(); ArrayList<ClassDesc> ptypes = new ArrayList<>();
ptypes.add(null); // placeholder for return type ptypes.add(null); // placeholder for return type
@ -227,7 +230,8 @@ class ConstantUtils {
if (len == 1) { if (len == 1) {
return Wrapper.forPrimitiveType(descriptor.charAt(start)).classDescriptor(); 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 = '['; private static final char JVM_SIGNATURE_ARRAY = '[';

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * or visit www.oracle.com if you need additional information or have any
* questions. * 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.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.util.Objects; import java.util.Objects;
import static java.lang.constant.ConstantDescs.CD_void; 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.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static jdk.internal.constant.ConstantUtils.validateClassOrInterface;
import static jdk.internal.constant.ConstantUtils.validateMemberName;
/** /**
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a direct * A <a href="package-summary.html#nominal">nominal descriptor</a> for a direct
* {@link MethodHandle}. A {@linkplain DirectMethodHandleDescImpl} corresponds to * {@link MethodHandle}. A {@linkplain DirectMethodHandleDescImpl} corresponds to
* a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile. * 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 Kind kind;
private final ClassDesc owner; private final ClassDesc owner;
@ -62,7 +65,7 @@ final class DirectMethodHandleDescImpl implements DirectMethodHandleDesc {
* is not {@code void} * is not {@code void}
* @jvms 4.2.2 Unqualified Names * @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) if (kind == CONSTRUCTOR)
name = "<init>"; name = "<init>";
@ -82,12 +85,11 @@ final class DirectMethodHandleDescImpl implements DirectMethodHandleDesc {
this.kind = kind; this.kind = kind;
this.owner = owner; this.owner = owner;
this.name = name; this.name = name;
if (kind.isVirtualMethod()) this.invocationType = switch (kind) {
this.invocationType = type.insertParameterTypes(0, owner); case VIRTUAL, SPECIAL, INTERFACE_VIRTUAL, INTERFACE_SPECIAL -> type.insertParameterTypes(0, owner);
else if (kind == CONSTRUCTOR) case CONSTRUCTOR -> type.changeReturnType(owner);
this.invocationType = type.changeReturnType(owner); default -> type;
else };
this.invocationType = type;
} }
private static void validateFieldType(MethodTypeDesc type, boolean isSetter, boolean isVirtual) { private static void validateFieldType(MethodTypeDesc type, boolean isSetter, boolean isVirtual) {

View file

@ -22,10 +22,12 @@
* or visit www.oracle.com if you need additional information or have any * or visit www.oracle.com if you need additional information or have any
* questions. * questions.
*/ */
package java.lang.constant; package jdk.internal.constant;
import jdk.internal.vm.annotation.Stable; 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.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.security.AccessController; import java.security.AccessController;
@ -41,7 +43,7 @@ import static java.util.Objects.requireNonNull;
* {@link MethodType}. A {@linkplain MethodTypeDescImpl} corresponds to a * {@link MethodType}. A {@linkplain MethodTypeDescImpl} corresponds to a
* {@code Constant_MethodType_info} entry in the constant pool of a classfile. * {@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 ClassDesc returnType;
private final @Stable ClassDesc[] argTypes; private final @Stable ClassDesc[] argTypes;
private @Stable String cachedDescriptorString; private @Stable String cachedDescriptorString;
@ -65,15 +67,31 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
* @param returnType a {@link ClassDesc} describing the return type * @param returnType a {@link ClassDesc} describing the return type
* @param trustedArgTypes {@link ClassDesc}s describing the trusted parameter types * @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); 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); 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); return new MethodTypeDescImpl(returnType, trustedArgTypes);
} }
@ -86,7 +104,7 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
* method descriptor * method descriptor
* @jvms 4.3.3 Method Descriptors * @jvms 4.3.3 Method Descriptors
*/ */
static MethodTypeDescImpl ofDescriptor(String descriptor) { public static MethodTypeDescImpl ofDescriptor(String descriptor) {
// Implicit null-check of descriptor // Implicit null-check of descriptor
List<ClassDesc> ptypes = ConstantUtils.parseMethodDescriptor(descriptor); List<ClassDesc> ptypes = ConstantUtils.parseMethodDescriptor(descriptor);
int args = ptypes.size() - 1; int args = ptypes.size() - 1;
@ -94,7 +112,7 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
? ptypes.subList(1, args + 1).toArray(ConstantUtils.EMPTY_CLASSDESC) ? ptypes.subList(1, args + 1).toArray(ConstantUtils.EMPTY_CLASSDESC)
: ConstantUtils.EMPTY_CLASSDESC; : ConstantUtils.EMPTY_CLASSDESC;
MethodTypeDescImpl result = ofTrusted(ptypes.get(0), paramTypes); MethodTypeDescImpl result = ofValidated(ptypes.get(0), paramTypes);
result.cachedDescriptorString = descriptor; result.cachedDescriptorString = descriptor;
return result; return result;
} }
@ -127,14 +145,14 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
@Override @Override
public MethodTypeDesc changeReturnType(ClassDesc returnType) { public MethodTypeDesc changeReturnType(ClassDesc returnType) {
return new MethodTypeDescImpl(requireNonNull(returnType), argTypes); return ofValidated(requireNonNull(returnType), argTypes);
} }
@Override @Override
public MethodTypeDesc changeParameterType(int index, ClassDesc paramType) { public MethodTypeDesc changeParameterType(int index, ClassDesc paramType) {
ClassDesc[] newArgs = argTypes.clone(); ClassDesc[] newArgs = argTypes.clone();
newArgs[index] = paramType; newArgs[index] = validateArgument(paramType);
return ofTrusted(returnType, newArgs); return ofValidated(returnType, newArgs);
} }
@Override @Override
@ -149,7 +167,7 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
if (end < argTypes.length) { if (end < argTypes.length) {
System.arraycopy(argTypes, end, newArgs, start, argTypes.length - end); System.arraycopy(argTypes, end, newArgs, start, argTypes.length - end);
} }
return ofTrusted(returnType, newArgs); return ofValidated(returnType, newArgs);
} }
@Override @Override
@ -162,10 +180,16 @@ final class MethodTypeDescImpl implements MethodTypeDesc {
System.arraycopy(argTypes, 0, newArgs, 0, pos); System.arraycopy(argTypes, 0, newArgs, 0, pos);
} }
System.arraycopy(paramTypes, 0, newArgs, pos, paramTypes.length); System.arraycopy(paramTypes, 0, newArgs, pos, paramTypes.length);
int destPos = pos + paramTypes.length;
if (pos < argTypes.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 @Override

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * or visit www.oracle.com if you need additional information or have any
* questions. * questions.
*/ */
package java.lang.constant; package jdk.internal.constant;
import java.lang.constant.ModuleDesc;
/* /*
* Implementation of {@code ModuleDesc} * Implementation of {@code ModuleDesc}
* @param name must have been validated * @param name must have been validated
*/ */
record ModuleDescImpl(String name) implements ModuleDesc { public record ModuleDescImpl(String name) implements ModuleDesc {
@Override @Override
public String toString() { public String toString() {

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * or visit www.oracle.com if you need additional information or have any
* questions. * questions.
*/ */
package java.lang.constant; package jdk.internal.constant;
import java.lang.constant.PackageDesc;
/* /*
* Implementation of {@code PackageDesc} * Implementation of {@code PackageDesc}
* @param internalName must have been validated * @param internalName must have been validated
*/ */
record PackageDescImpl(String internalName) implements PackageDesc { public record PackageDescImpl(String internalName) implements PackageDesc {
@Override @Override
public String toString() { public String toString() {

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * or visit www.oracle.com if you need additional information or have any
* questions. * 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 java.lang.invoke.MethodHandles;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
@ -34,7 +37,7 @@ import static java.util.Objects.requireNonNull;
* A <a href="package-summary.html#nominal">nominal descriptor</a> for the class * A <a href="package-summary.html#nominal">nominal descriptor</a> for the class
* constant corresponding to a primitive type (e.g., {@code int.class}). * constant corresponding to a primitive type (e.g., {@code int.class}).
*/ */
final class PrimitiveClassDescImpl public final class PrimitiveClassDescImpl
extends DynamicConstantDesc<Class<?>> implements ClassDesc { extends DynamicConstantDesc<Class<?>> implements ClassDesc {
private final String descriptor; private final String descriptor;
@ -49,7 +52,7 @@ final class PrimitiveClassDescImpl
* describe a valid primitive type * describe a valid primitive type
* @jvms 4.3 Descriptors * @jvms 4.3 Descriptors
*/ */
PrimitiveClassDescImpl(String descriptor) { public PrimitiveClassDescImpl(String descriptor) {
super(ConstantDescs.BSM_PRIMITIVE_CLASS, requireNonNull(descriptor), ConstantDescs.CD_Class); super(ConstantDescs.BSM_PRIMITIVE_CLASS, requireNonNull(descriptor), ConstantDescs.CD_Class);
if (descriptor.length() != 1 if (descriptor.length() != 1
|| "VIJCSBFDZ".indexOf(descriptor.charAt(0)) < 0) || "VIJCSBFDZ".indexOf(descriptor.charAt(0)) < 0)

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * or visit www.oracle.com if you need additional information or have any
* questions. * questions.
*/ */
package java.lang.constant; package jdk.internal.constant;
import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import static java.lang.constant.ConstantUtils.*; import static jdk.internal.constant.ConstantUtils.*;
import static java.util.Objects.requireNonNull;
/** /**
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a class, * A <a href="package-summary.html#nominal">nominal descriptor</a> for a class,
* interface, or array type. A {@linkplain ReferenceClassDescImpl} corresponds to a * interface, or array type. A {@linkplain ReferenceClassDescImpl} corresponds to a
* {@code Constant_Class_info} entry in the constant pool of a classfile. * {@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 final String descriptor;
private ReferenceClassDescImpl(String descriptor) {
this.descriptor = descriptor;
}
/** /**
* Creates a {@linkplain ClassDesc} from a descriptor string for a class or * Creates a {@linkplain ClassDesc} from a descriptor string for a class or
* interface type or an array type. * 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 * field descriptor string, or does not describe a class or interface type
* @jvms 4.3.2 Field Descriptors * @jvms 4.3.2 Field Descriptors
*/ */
ReferenceClassDescImpl(String descriptor) { public static ReferenceClassDescImpl of(String descriptor) {
int dLen = descriptor.length(); int dLen = descriptor.length();
int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen, false); int len = ConstantUtils.skipOverFieldSignature(descriptor, 0, dLen, false);
if (len <= 1 || len != dLen) if (len <= 1 || len != dLen)
throw new IllegalArgumentException(String.format("not a valid reference type descriptor: %s", descriptor)); 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 @Override

View file

@ -237,6 +237,12 @@ public class ClassDescTest extends SymbolicDescTest {
testBadArrayRank(ClassDesc.of("Bar")); testBadArrayRank(ClassDesc.of("Bar"));
testArrayRankOverflow(); testArrayRankOverflow();
} }
try {
ConstantDescs.CD_void.arrayType();
fail("Should throw IAE");
} catch (IllegalArgumentException iae) {
// Expected
}
} }
public void testBadClassDescs() { public void testBadClassDescs() {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -21,9 +21,8 @@
* questions. * questions.
*/ */
package java.lang.constant; package jdk.internal.constant;
import java.lang.invoke.*;
import java.lang.constant.*; import java.lang.constant.*;
import java.util.*; import java.util.*;
@ -35,6 +34,7 @@ import static org.testng.Assert.*;
* @test * @test
* @bug 8303930 * @bug 8303930
* @compile ConstantUtilsTest.java * @compile ConstantUtilsTest.java
* @modules java.base/jdk.internal.constant
* @run testng ConstantUtilsTest * @run testng ConstantUtilsTest
* @summary unit tests for methods of java.lang.constant.ConstantUtils that are not covered by other unit tests * @summary unit tests for methods of java.lang.constant.ConstantUtils that are not covered by other unit tests
*/ */

View file

@ -35,6 +35,7 @@ import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.annotations.Warmup;
import java.lang.constant.ClassDesc; import java.lang.constant.ClassDesc;
import java.lang.constant.ConstantDescs;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@ -60,4 +61,19 @@ public class ClassDescFactories {
public ClassDesc ofDescriptor() { public ClassDesc ofDescriptor() {
return ClassDesc.ofDescriptor(descString); 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");
}
}
} }

View file

@ -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));
}
}