diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 4573a6dc690..4bc7ccab834 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -70,6 +70,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import jdk.internal.constant.ConstantUtils; import jdk.internal.javac.PreviewFeature; import jdk.internal.loader.BootLoader; import jdk.internal.loader.BuiltinClassLoader; @@ -4709,7 +4710,7 @@ public final class Class implements java.io.Serializable, public Optional describeConstable() { Class c = isArray() ? elementType() : this; return c.isHidden() ? Optional.empty() - : Optional.of(ClassDesc.ofDescriptor(descriptorString())); + : Optional.of(ConstantUtils.classDesc(this)); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java index eb93a8c6a31..1997ffb487c 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -45,6 +45,7 @@ import java.lang.classfile.attribute.LocalVariableTypeInfo; import java.lang.classfile.instruction.ExceptionCatch; import java.util.List; import static java.util.Objects.requireNonNull; +import static jdk.internal.constant.ConstantUtils.CD_module_info; import jdk.internal.javac.PreviewFeature; /** @@ -392,7 +393,7 @@ public sealed interface ClassFile */ default byte[] buildModule(ModuleAttribute moduleAttribute, Consumer handler) { - return build(ClassDesc.of("module-info"), clb -> { + return build(CD_module_info, clb -> { clb.withFlags(AccessFlag.MODULE); clb.with(moduleAttribute); handler.accept(clb); 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 130a81420b6..370d2eee507 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -36,7 +36,6 @@ 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; @@ -165,7 +164,7 @@ public sealed interface ClassDesc static ClassDesc ofDescriptor(String descriptor) { // implicit null-check return (descriptor.length() == 1) - ? Wrapper.forPrimitiveType(descriptor.charAt(0)).classDescriptor() + ? Wrapper.forPrimitiveType(descriptor.charAt(0)).basicClassDescriptor() // will throw IAE on descriptor.length == 0 or if array dimensions too long : ReferenceClassDescImpl.of(descriptor); } @@ -315,7 +314,7 @@ public sealed interface ClassDesc if (isArray()) { String desc = descriptorString(); if (desc.length() == 2) { - return Wrapper.forBasicType(desc.charAt(1)).classDescriptor(); + return Wrapper.forBasicType(desc.charAt(1)).basicClassDescriptor(); } else { return ReferenceClassDescImpl.ofValidated(desc.substring(1)); } diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java index 5ca45e3fe52..8f0f355a980 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleProxies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -52,6 +52,8 @@ import java.lang.classfile.ClassHierarchyResolver; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; import java.lang.classfile.TypeKind; + +import jdk.internal.constant.ConstantUtils; import jdk.internal.module.Modules; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -63,6 +65,7 @@ import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodType.methodType; import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC; import static java.lang.classfile.ClassFile.*; +import static jdk.internal.constant.ConstantUtils.*; /** * This class consists exclusively of static methods that help adapt @@ -249,14 +252,14 @@ public class MethodHandleProxies { // the field name holding the method handle for this method String fieldName = "m" + count++; - var mt = methodType(m.getReturnType(), JLRA.getExecutableSharedParameterTypes(m), true); + var md = methodTypeDesc(m.getReturnType(), JLRA.getExecutableSharedParameterTypes(m)); var thrown = JLRA.getExecutableSharedExceptionTypes(m); var exceptionTypeDescs = thrown.length == 0 ? DEFAULT_RETHROWS : Stream.concat(DEFAULT_RETHROWS.stream(), - Arrays.stream(thrown).map(MethodHandleProxies::desc)) + Arrays.stream(thrown).map(ConstantUtils::referenceClassDesc)) .distinct().toList(); - methods.add(new MethodInfo(desc(mt), exceptionTypeDescs, fieldName)); + methods.add(new MethodInfo(md, exceptionTypeDescs, fieldName)); // find the types referenced by this method addElementType(referencedTypes, m.getReturnType()); @@ -279,7 +282,8 @@ public class MethodHandleProxies { int i = intfcName.lastIndexOf('.'); // jdk.MHProxy#.Interface String className = packageName + "." + (i > 0 ? intfcName.substring(i + 1) : intfcName); - byte[] template = createTemplate(loader, ClassDesc.of(className), desc(intfc), uniqueName, methods); + byte[] template = createTemplate(loader, binaryNameToDesc(className), + referenceClassDesc(intfc), uniqueName, methods); // define the dynamic module to the class loader of the interface var definer = new Lookup(intfc).makeHiddenClassDefiner(className, template, Set.of(), DUMPER); @@ -335,17 +339,17 @@ public class MethodHandleProxies { } } - private static final List DEFAULT_RETHROWS = List.of(desc(RuntimeException.class), desc(Error.class)); - private static final ClassDesc CD_UndeclaredThrowableException = desc(UndeclaredThrowableException.class); - private static final ClassDesc CD_IllegalAccessException = desc(IllegalAccessException.class); + private static final List DEFAULT_RETHROWS = List.of(referenceClassDesc(RuntimeException.class), referenceClassDesc(Error.class)); + private static final ClassDesc CD_UndeclaredThrowableException = referenceClassDesc(UndeclaredThrowableException.class); + private static final ClassDesc CD_IllegalAccessException = referenceClassDesc(IllegalAccessException.class); private static final MethodTypeDesc MTD_void_Throwable = MethodTypeDesc.of(CD_void, CD_Throwable); private static final MethodType MT_void_Lookup_MethodHandle_MethodHandle = methodType(void.class, Lookup.class, MethodHandle.class, MethodHandle.class); private static final MethodType MT_Object_Lookup_MethodHandle_MethodHandle = MT_void_Lookup_MethodHandle_MethodHandle.changeReturnType(Object.class); private static final MethodType MT_MethodHandle_Object = methodType(MethodHandle.class, Object.class); - private static final MethodTypeDesc MTD_void_Lookup_MethodHandle_MethodHandle = - desc(MT_void_Lookup_MethodHandle_MethodHandle); + private static final MethodTypeDesc MTD_void_Lookup_MethodHandle_MethodHandle + = methodTypeDesc(MT_void_Lookup_MethodHandle_MethodHandle); private static final MethodTypeDesc MTD_void_Lookup = MethodTypeDesc.of(CD_void, CD_MethodHandles_Lookup); private static final MethodTypeDesc MTD_MethodHandle_MethodType = MethodTypeDesc.of(CD_MethodHandle, CD_MethodType); private static final MethodTypeDesc MTD_Class = MethodTypeDesc.of(CD_Class); @@ -531,16 +535,6 @@ public class MethodHandleProxies { } } - private static ClassDesc desc(Class cl) { - return cl.describeConstable().orElseThrow(() -> newInternalError("Cannot convert class " - + cl.getName() + " to a constant")); - } - - private static MethodTypeDesc desc(MethodType mt) { - return mt.describeConstable().orElseThrow(() -> newInternalError("Cannot convert method type " - + mt + " to a constant")); - } - private static final JavaLangReflectAccess JLRA = SharedSecrets.getJavaLangReflectAccess(); private static final AtomicInteger counter = new AtomicInteger(); diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 3499fd83525..29896fd8f93 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -27,6 +27,7 @@ package java.lang.invoke; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.constant.ConstantUtils; import jdk.internal.misc.VM; import jdk.internal.util.ClassFileDumper; import jdk.internal.vm.annotation.Stable; @@ -1090,13 +1091,13 @@ public final class StringConcatFactory { private static MethodHandle generate(Lookup lookup, MethodType args, String[] constants) throws Exception { String className = getClassName(lookup.lookupClass()); - byte[] classBytes = ClassFile.of().build(ClassDesc.of(className), + byte[] classBytes = ClassFile.of().build(ConstantUtils.binaryNameToDesc(className), new Consumer() { @Override public void accept(ClassBuilder clb) { clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC) .withMethodBody(METHOD_NAME, - MethodTypeDesc.ofDescriptor(args.toMethodDescriptorString()), + ConstantUtils.methodTypeDesc(args), ClassFile.ACC_FINAL | ClassFile.ACC_PRIVATE | ClassFile.ACC_STATIC, generateMethod(constants, args)); }}); diff --git a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java index 776f5df4e5a..a484c191206 100644 --- a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java +++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java @@ -49,6 +49,8 @@ import java.lang.classfile.attribute.StackMapFrameInfo; import java.lang.classfile.attribute.StackMapTableAttribute; import java.lang.constant.ConstantDescs; import static java.lang.constant.ConstantDescs.*; +import static jdk.internal.constant.ConstantUtils.*; + import java.lang.constant.DirectMethodHandleDesc; import java.lang.constant.DynamicConstantDesc; @@ -134,7 +136,7 @@ final class ProxyGenerator { /** * Name of proxy class */ - private ClassEntry classEntry; + private final ClassEntry classEntry; /** * Proxy interfaces @@ -160,10 +162,10 @@ final class ProxyGenerator { * A ProxyGenerator object contains the state for the ongoing * generation of a particular proxy class. */ - private ProxyGenerator(ClassLoader loader, String className, List> interfaces, + private ProxyGenerator(String className, List> interfaces, int accessFlags) { this.cp = ConstantPoolBuilder.of(); - this.classEntry = cp.classEntry(ReferenceClassDescImpl.ofValidatedBinaryName(className)); + this.classEntry = cp.classEntry(ConstantUtils.binaryNameToDesc(className)); this.interfaces = interfaces; this.accessFlags = accessFlags; this.throwableStack = List.of(StackMapFrameInfo.ObjectVerificationTypeInfo.of(cp.classEntry(CD_Throwable))); @@ -190,7 +192,7 @@ final class ProxyGenerator { List> interfaces, int accessFlags) { Objects.requireNonNull(interfaces); - ProxyGenerator gen = new ProxyGenerator(loader, name, interfaces, accessFlags); + ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags); final byte[] classFile = gen.generateClassFile(); if (SAVE_GENERATED_FILES) { @@ -227,18 +229,10 @@ final class ProxyGenerator { private static List toClassEntries(ConstantPoolBuilder cp, List> types) { var ces = new ArrayList(types.size()); for (var t : types) - ces.add(cp.classEntry(ReferenceClassDescImpl.ofValidatedBinaryName(t.getName()))); + ces.add(cp.classEntry(ConstantUtils.binaryNameToDesc(t.getName()))); return ces; } - /** - * {@return the {@code ClassDesc} of the given type} - * @param type the {@code Class} object - */ - private static ClassDesc toClassDesc(Class type) { - return ClassDesc.ofDescriptor(type.descriptorString()); - } - /** * For a given set of proxy methods with the same signature, check * that their return types are compatible according to the Proxy @@ -325,7 +319,7 @@ final class ProxyGenerator { * not assignable from any of the others. */ if (uncoveredReturnTypes.size() > 1) { - ProxyMethod pm = methods.get(0); + ProxyMethod pm = methods.getFirst(); throw new IllegalArgumentException( "methods with same signature " + pm.shortSignature + @@ -501,7 +495,7 @@ final class ProxyGenerator { String sig = m.toShortSignature(); List sigmethods = proxyMethods.computeIfAbsent(sig, - (f) -> new ArrayList<>(3)); + _ -> new ArrayList<>(3)); for (ProxyMethod pm : sigmethods) { if (returnType == pm.returnType) { /* @@ -531,7 +525,7 @@ final class ProxyGenerator { private void addProxyMethod(ProxyMethod pm) { String sig = pm.shortSignature; List sigmethods = proxyMethods.computeIfAbsent(sig, - (f) -> new ArrayList<>(3)); + _ -> new ArrayList<>(3)); sigmethods.add(pm); } @@ -637,7 +631,6 @@ final class ProxyGenerator { * Create a new specific ProxyMethod with a specific field name * * @param method The method for which to create a proxy - * @param methodFieldName the fieldName to generate */ private ProxyMethod(Method method) { this(method, method.toShortSignature(), @@ -650,11 +643,7 @@ final class ProxyGenerator { */ private void generateMethod(ProxyGenerator pg, ClassBuilder clb) { var cp = pg.cp; - var pTypes = new ClassDesc[parameterTypes.length]; - for (int i = 0; i < pTypes.length; i++) { - pTypes[i] = toClassDesc(parameterTypes[i]); - } - MethodTypeDesc desc = MethodTypeDescImpl.ofTrusted(toClassDesc(returnType), pTypes); + var desc = methodTypeDesc(returnType, parameterTypes); int accessFlags = (method.isVarArgs()) ? ACC_VARARGS | ACC_PUBLIC | ACC_FINAL : ACC_PUBLIC | ACC_FINAL; var catchList = computeUniqueCatchList(exceptionTypes); @@ -665,7 +654,7 @@ final class ProxyGenerator { .getfield(pg.handlerField) .aload(0) .ldc(DynamicConstantDesc.of(pg.bsm, - toClassDesc(fromClass), + referenceClassDesc(fromClass), method.getName(), desc)); if (parameterTypes.length > 0) { @@ -693,7 +682,7 @@ final class ProxyGenerator { if (!catchList.isEmpty()) { var c1 = cob.newBoundLabel(); for (var exc : catchList) { - cob.exceptionCatch(cob.startLabel(), c1, c1, toClassDesc(exc)); + cob.exceptionCatch(cob.startLabel(), c1, c1, referenceClassDesc(exc)); } cob.athrow(); // just rethrow the exception var c2 = cob.newBoundLabel(); @@ -739,7 +728,7 @@ final class ProxyGenerator { .invokevirtual(prim.unwrapMethodRef(cob.constantPool())) .return_(TypeKind.from(type).asLoadable()); } else { - cob.checkcast(toClassDesc(type)) + cob.checkcast(referenceClassDesc(type)) .areturn(); } } diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index c564b7b69f6..3eecd2ab42f 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -26,7 +26,6 @@ package java.lang.runtime; import java.lang.Enum.EnumDesc; -import java.lang.classfile.ClassBuilder; import java.lang.classfile.CodeBuilder; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; @@ -50,6 +49,7 @@ import java.lang.classfile.ClassFile; import java.lang.classfile.Label; import java.lang.classfile.instruction.SwitchCase; +import jdk.internal.constant.ConstantUtils; import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.misc.PreviewFeatures; import jdk.internal.vm.annotation.Stable; @@ -59,6 +59,9 @@ import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; import java.util.HashMap; import java.util.Map; import static java.util.Objects.requireNonNull; +import static jdk.internal.constant.ConstantUtils.classDesc; +import static jdk.internal.constant.ConstantUtils.referenceClassDesc; + import sun.invoke.util.Wrapper; /** @@ -321,7 +324,7 @@ public class SwitchBootstraps { } return label; } else if (labelClass == String.class) { - return EnumDesc.of(enumClassTemplate.describeConstable().orElseThrow(), (String) label); + return EnumDesc.of(referenceClassDesc(enumClassTemplate), (String) label); } else { throw new IllegalArgumentException("label with illegal type found: " + labelClass + ", expected label of type either String or Class"); @@ -464,10 +467,7 @@ public class SwitchBootstraps { // Object o = ... // o instanceof Wrapped(float) cb.aload(SELECTOR_OBJ); - cb.instanceOf(Wrapper.forBasicType(classLabel) - .wrapperType() - .describeConstable() - .orElseThrow()); + cb.instanceOf(Wrapper.forBasicType(classLabel).wrapperClassDescriptor()); cb.ifeq(next); } else if (!unconditionalExactnessCheck(Wrapper.asPrimitiveType(selectorType), classLabel)) { // Integer i = ... or int i = ... @@ -515,9 +515,9 @@ public class SwitchBootstraps { TypePairs typePair = TypePairs.of(Wrapper.asPrimitiveType(selectorType), classLabel); String methodName = TypePairs.typePairToName.get(typePair); - cb.invokestatic(ExactConversionsSupport.class.describeConstable().orElseThrow(), + cb.invokestatic(referenceClassDesc(ExactConversionsSupport.class), methodName, - MethodTypeDesc.of(ConstantDescs.CD_boolean, typePair.from.describeConstable().orElseThrow())); + MethodTypeDesc.of(ConstantDescs.CD_boolean, classDesc(typePair.from))); cb.ifeq(next); } } else { @@ -553,7 +553,7 @@ public class SwitchBootstraps { MethodTypeDesc.of(ConstantDescs.CD_Integer, ConstantDescs.CD_int)); cb.aload(SELECTOR_OBJ); - cb.invokeinterface(BiPredicate.class.describeConstable().orElseThrow(), + cb.invokeinterface(referenceClassDesc(BiPredicate.class), "test", MethodTypeDesc.of(ConstantDescs.CD_boolean, ConstantDescs.CD_Object, @@ -601,10 +601,11 @@ public class SwitchBootstraps { } else { cb.loadConstant((ConstantDesc) element.caseLabel()); } - cb.invokestatic(element.caseLabel().getClass().describeConstable().orElseThrow(), + var caseLabelWrapper = Wrapper.forWrapperType(element.caseLabel().getClass()); + cb.invokestatic(caseLabelWrapper.wrapperClassDescriptor(), "valueOf", - MethodTypeDesc.of(element.caseLabel().getClass().describeConstable().orElseThrow(), - Wrapper.asPrimitiveType(element.caseLabel().getClass()).describeConstable().orElseThrow())); + MethodTypeDesc.of(caseLabelWrapper.wrapperClassDescriptor(), + caseLabelWrapper.basicClassDescriptor())); cb.aload(SELECTOR_OBJ); cb.invokevirtual(ConstantDescs.CD_Object, "equals", @@ -631,7 +632,7 @@ public class SwitchBootstraps { List> enumDescs = new ArrayList<>(); List> extraClassLabels = new ArrayList<>(); - byte[] classBytes = ClassFile.of().build(ReferenceClassDescImpl.ofValidatedBinaryName(typeSwitchClassName(caller.lookupClass())), + byte[] classBytes = ClassFile.of().build(ConstantUtils.binaryNameToDesc(typeSwitchClassName(caller.lookupClass())), clb -> { clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC) .withMethodBody("typeSwitch", diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java index 1154b038dee..6765bdee3bd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -41,6 +41,7 @@ import java.lang.classfile.ClassHierarchyResolver; import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.classfile.ClassFile.*; import static java.util.Objects.requireNonNull; +import static jdk.internal.constant.ConstantUtils.referenceClassDesc; /** * Class hierarchy resolution framework is answering questions about classes assignability, common classes ancestor and whether the class represents an interface. @@ -245,7 +246,7 @@ public final class ClassHierarchyImpl { } return cl.isInterface() ? ClassHierarchyInfo.ofInterface() - : ClassHierarchyInfo.ofClass(cl.getSuperclass().describeConstable().orElseThrow()); + : ClassHierarchyInfo.ofClass(referenceClassDesc(cl.getSuperclass())); } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index ba032c7b0c2..ddb14b2d26a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -26,14 +26,12 @@ package jdk.internal.classfile.impl; import java.lang.classfile.constantpool.InvokeDynamicEntry; -import java.lang.classfile.constantpool.NameAndTypeEntry; import java.lang.constant.ClassDesc; import static java.lang.constant.ConstantDescs.*; import java.lang.constant.MethodTypeDesc; import java.lang.classfile.ClassFile; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantDynamicEntry; -import java.lang.classfile.constantpool.DynamicConstantPoolEntry; import java.lang.classfile.constantpool.MemberRefEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.nio.ByteBuffer; @@ -46,6 +44,8 @@ import java.util.stream.Collectors; import java.lang.classfile.Attribute; import static java.lang.classfile.ClassFile.*; +import static jdk.internal.constant.ConstantUtils.binaryNameToDesc; + import java.lang.classfile.BufWriter; import java.lang.classfile.Label; import java.lang.classfile.attribute.StackMapTableAttribute; @@ -1321,8 +1321,8 @@ public final class StackMapGenerator { } } - private static final ClassDesc CD_Cloneable = ClassDesc.of("java.lang.Cloneable"); - private static final ClassDesc CD_Serializable = ClassDesc.of("java.io.Serializable"); + private static final ClassDesc CD_Cloneable = binaryNameToDesc("java.lang.Cloneable"); + private static final ClassDesc CD_Serializable = binaryNameToDesc("java.io.Serializable"); private Type mergeReferenceFrom(Type from, ClassHierarchyImpl context) { if (from == NULL_TYPE) { diff --git a/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java index 7c676a44b99..da90f373eb5 100644 --- a/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java +++ b/src/java.base/share/classes/jdk/internal/constant/ConstantUtils.java @@ -29,6 +29,8 @@ import sun.invoke.util.Wrapper; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; +import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -41,12 +43,85 @@ public final class ConstantUtils { public static final ConstantDesc[] EMPTY_CONSTANTDESC = new ConstantDesc[0]; public static final ClassDesc[] EMPTY_CLASSDESC = new ClassDesc[0]; public static final int MAX_ARRAY_TYPE_DESC_DIMENSIONS = 255; + public static final ClassDesc CD_module_info = binaryNameToDesc("module-info"); private static final Set pointyNames = Set.of(ConstantDescs.INIT_NAME, ConstantDescs.CLASS_INIT_NAME); /** No instantiation */ private ConstantUtils() {} + // Note: + // Non-JDK users should create their own utilities that wrap + // {@code .describeConstable().orElseThrow()} calls; + // these xxDesc methods has undefined and unsafe exceptional + // behavior, so they are not suitable as public APIs. + + /** + * Creates a {@linkplain ClassDesc} from a pre-validated binary name + * for a class or interface type. Validated version of {@link + * ClassDesc#of(String)}. + * + * @param binaryName a binary name + */ + public static ClassDesc binaryNameToDesc(String binaryName) { + return ReferenceClassDescImpl.ofValidated("L" + binaryToInternal(binaryName) + ";"); + } + + /** + * Creates a ClassDesc from a Class object, requires that this class + * can always be described nominally, i.e. this class is not a + * hidden class or interface or an array with a hidden component + * type. + */ + public static ClassDesc classDesc(Class type) { + if (type.isPrimitive()) { + return Wrapper.forPrimitiveType(type).basicClassDescriptor(); + } + return referenceClassDesc(type); + } + + /** + * Creates a ClassDesc from a Class object representing a non-hidden + * class or interface or an array type with a non-hidden component type. + */ + public static ClassDesc referenceClassDesc(Class type) { + return ReferenceClassDescImpl.ofValidated(type.descriptorString()); + } + + /** + * Creates a MethodTypeDesc from a MethodType object, requires that + * the type can be described nominally, i.e. all of its return + * type and parameter types can be described nominally. + */ + public static MethodTypeDesc methodTypeDesc(MethodType type) { + var returnDesc = classDesc(type.returnType()); + if (type.parameterCount() == 0) { + return MethodTypeDescImpl.ofValidated(returnDesc, EMPTY_CLASSDESC); + } + var paramDescs = new ClassDesc[type.parameterCount()]; + for (int i = 0; i < type.parameterCount(); i++) { + paramDescs[i] = classDesc(type.parameterType(i)); + } + return MethodTypeDescImpl.ofValidated(returnDesc, paramDescs); + } + + /** + * Creates a MethodTypeDesc from return class and parameter + * class objects, requires that all of them can be described nominally. + * This version is mainly useful for working with Method objects. + */ + public static MethodTypeDesc methodTypeDesc(Class returnType, Class[] parameterTypes) { + var returnDesc = classDesc(returnType); + if (parameterTypes.length == 0) { + return MethodTypeDescImpl.ofValidated(returnDesc, EMPTY_CLASSDESC); + } + var paramDescs = new ClassDesc[parameterTypes.length]; + for (int i = 0; i < parameterTypes.length; i++) { + paramDescs[i] = classDesc(parameterTypes[i]); + } + return MethodTypeDescImpl.ofValidated(returnDesc, paramDescs); + } + /** * Validates the correctness of a binary class name. In particular checks for the presence of * invalid characters in the name. @@ -231,7 +306,7 @@ public final class ConstantUtils { private static ClassDesc resolveClassDesc(String descriptor, int start, int len) { if (len == 1) { - return Wrapper.forPrimitiveType(descriptor.charAt(start)).classDescriptor(); + return Wrapper.forPrimitiveType(descriptor.charAt(start)).basicClassDescriptor(); } // Pre-verified in parseMethodDescriptor; avoid redundant verification return ReferenceClassDescImpl.ofValidated(descriptor.substring(start, start + len)); diff --git a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java index b4ec9c13de5..71473b87e18 100644 --- a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java +++ b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java @@ -66,20 +66,11 @@ public final class ReferenceClassDescImpl implements ClassDesc { * @jvms 4.3.2 Field Descriptors */ public static ReferenceClassDescImpl ofValidated(String descriptor) { + assert ConstantUtils.skipOverFieldSignature(descriptor, 0, descriptor.length(), false) + == descriptor.length() : 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 ClassDesc ofValidatedBinaryName(String typeSwitchClassName) { - return ofValidated("L" + binaryToInternal(typeSwitchClassName) + ";"); - } - @Override public String descriptorString() { return descriptor; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java index 7f5ef54bdca..6109f59f2d8 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -29,6 +29,7 @@ import java.lang.classfile.CodeBuilder; import java.lang.classfile.Label; import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; + import jdk.internal.foreign.AbstractMemorySegmentImpl; import jdk.internal.foreign.MemorySessionImpl; import jdk.internal.foreign.Utils; @@ -50,7 +51,6 @@ import sun.security.action.GetPropertyAction; import java.io.IOException; import java.lang.constant.ClassDesc; -import java.lang.constant.Constable; import java.lang.constant.ConstantDesc; import java.lang.constant.DynamicConstantDesc; import java.lang.constant.MethodTypeDesc; @@ -70,6 +70,7 @@ import java.util.List; import static java.lang.constant.ConstantDescs.*; import static java.lang.classfile.ClassFile.*; import static java.lang.classfile.TypeKind.*; +import static jdk.internal.constant.ConstantUtils.*; public class BindingSpecializer { private static final String DUMP_CLASSES_DIR @@ -80,24 +81,24 @@ public class BindingSpecializer { // Bunch of helper constants private static final int CLASSFILE_VERSION = ClassFileFormatVersion.latest().major(); - private static final ClassDesc CD_Arena = desc(Arena.class); - private static final ClassDesc CD_MemorySegment = desc(MemorySegment.class); - private static final ClassDesc CD_MemorySegment_Scope = desc(MemorySegment.Scope.class); - private static final ClassDesc CD_SharedUtils = desc(SharedUtils.class); - private static final ClassDesc CD_AbstractMemorySegmentImpl = desc(AbstractMemorySegmentImpl.class); - private static final ClassDesc CD_MemorySessionImpl = desc(MemorySessionImpl.class); - private static final ClassDesc CD_Utils = desc(Utils.class); - private static final ClassDesc CD_SegmentAllocator = desc(SegmentAllocator.class); - private static final ClassDesc CD_ValueLayout = desc(ValueLayout.class); - private static final ClassDesc CD_ValueLayout_OfBoolean = desc(ValueLayout.OfBoolean.class); - private static final ClassDesc CD_ValueLayout_OfByte = desc(ValueLayout.OfByte.class); - private static final ClassDesc CD_ValueLayout_OfShort = desc(ValueLayout.OfShort.class); - private static final ClassDesc CD_ValueLayout_OfChar = desc(ValueLayout.OfChar.class); - private static final ClassDesc CD_ValueLayout_OfInt = desc(ValueLayout.OfInt.class); - private static final ClassDesc CD_ValueLayout_OfLong = desc(ValueLayout.OfLong.class); - private static final ClassDesc CD_ValueLayout_OfFloat = desc(ValueLayout.OfFloat.class); - private static final ClassDesc CD_ValueLayout_OfDouble = desc(ValueLayout.OfDouble.class); - private static final ClassDesc CD_AddressLayout = desc(AddressLayout.class); + private static final ClassDesc CD_Arena = referenceClassDesc(Arena.class); + private static final ClassDesc CD_MemorySegment = referenceClassDesc(MemorySegment.class); + private static final ClassDesc CD_MemorySegment_Scope = referenceClassDesc(MemorySegment.Scope.class); + private static final ClassDesc CD_SharedUtils = referenceClassDesc(SharedUtils.class); + private static final ClassDesc CD_AbstractMemorySegmentImpl = referenceClassDesc(AbstractMemorySegmentImpl.class); + private static final ClassDesc CD_MemorySessionImpl = referenceClassDesc(MemorySessionImpl.class); + private static final ClassDesc CD_Utils = referenceClassDesc(Utils.class); + private static final ClassDesc CD_SegmentAllocator = referenceClassDesc(SegmentAllocator.class); + private static final ClassDesc CD_ValueLayout = referenceClassDesc(ValueLayout.class); + private static final ClassDesc CD_ValueLayout_OfBoolean = referenceClassDesc(ValueLayout.OfBoolean.class); + private static final ClassDesc CD_ValueLayout_OfByte = referenceClassDesc(ValueLayout.OfByte.class); + private static final ClassDesc CD_ValueLayout_OfShort = referenceClassDesc(ValueLayout.OfShort.class); + private static final ClassDesc CD_ValueLayout_OfChar = referenceClassDesc(ValueLayout.OfChar.class); + private static final ClassDesc CD_ValueLayout_OfInt = referenceClassDesc(ValueLayout.OfInt.class); + private static final ClassDesc CD_ValueLayout_OfLong = referenceClassDesc(ValueLayout.OfLong.class); + private static final ClassDesc CD_ValueLayout_OfFloat = referenceClassDesc(ValueLayout.OfFloat.class); + private static final ClassDesc CD_ValueLayout_OfDouble = referenceClassDesc(ValueLayout.OfDouble.class); + private static final ClassDesc CD_AddressLayout = referenceClassDesc(AddressLayout.class); private static final MethodTypeDesc MTD_NEW_BOUNDED_ARENA = MethodTypeDesc.of(CD_Arena, CD_long); private static final MethodTypeDesc MTD_NEW_EMPTY_ARENA = MethodTypeDesc.of(CD_Arena); @@ -196,7 +197,7 @@ public class BindingSpecializer { clb.withSuperclass(CD_Object); clb.withVersion(CLASSFILE_VERSION, 0); - clb.withMethodBody(METHOD_NAME, desc(callerMethodType), ACC_PUBLIC | ACC_STATIC, + clb.withMethodBody(METHOD_NAME, methodTypeDesc(callerMethodType), ACC_PUBLIC | ACC_STATIC, cb -> new BindingSpecializer(cb, callerMethodType, callingSequence, abi, leafType).specialize()); }); @@ -362,7 +363,7 @@ public class BindingSpecializer { cb.loadLocal(TypeKind.from(leafArgTypes.get(i)), leafArgSlots[i]); } // call leaf MH - cb.invokevirtual(CD_MethodHandle, "invokeExact", desc(leafType)); + cb.invokevirtual(CD_MethodHandle, "invokeExact", methodTypeDesc(leafType)); // for downcalls, store the result of the leaf handle call away, until // it is requested by a VM_LOAD in the return recipe. @@ -466,9 +467,9 @@ public class BindingSpecializer { case Copy copy -> emitCopyBuffer(copy); case Allocate allocate -> emitAllocBuffer(allocate); case BoxAddress boxAddress -> emitBoxAddress(boxAddress); - case SegmentBase unused -> emitSegmentBase(); + case SegmentBase _ -> emitSegmentBase(); case SegmentOffset segmentOffset -> emitSegmentOffset(segmentOffset); - case Dup unused -> emitDupBinding(); + case Dup _ -> emitDupBinding(); case ShiftLeft shiftLeft -> emitShiftLeft(shiftLeft); case ShiftRight shiftRight -> emitShiftRight(shiftRight); case Cast cast -> emitCast(cast); @@ -608,7 +609,7 @@ public class BindingSpecializer { ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType); cb.loadConstant(offset); cb.loadLocal(storeTypeKind, valueIdx); - MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, desc(storeType)); + MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType)); cb.invokeinterface(CD_MemorySegment, "set", descriptor); } else { // long longValue = ((Number) value).longValue(); @@ -666,7 +667,7 @@ public class BindingSpecializer { long writeOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize); cb.loadConstant(writeOffset); cb.loadLocal(chunkStoreTypeKind, chunkIdx); - MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, desc(chunkStoreType)); + MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(chunkStoreType)); cb.invokeinterface(CD_MemorySegment, "set", descriptor); remaining -= chunkSize; @@ -697,7 +698,7 @@ public class BindingSpecializer { ClassDesc valueLayoutType = emitLoadLayoutConstant(storeType); cb.loadConstant(retBufOffset); cb.loadLocal(storeTypeKind, valueIdx); - MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, desc(storeType)); + MethodTypeDesc descriptor = MethodTypeDesc.of(CD_void, valueLayoutType, CD_long, classDesc(storeType)); cb.invokeinterface(CD_MemorySegment, "set", descriptor); retBufOffset += abi.arch.typeSize(vmStore.storage().type()); } @@ -716,7 +717,7 @@ public class BindingSpecializer { cb.loadLocal(ReferenceType, returnBufferIdx); ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType); cb.loadConstant(retBufOffset); - MethodTypeDesc descriptor = MethodTypeDesc.of(desc(loadType), valueLayoutType, CD_long); + MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long); cb.invokeinterface(CD_MemorySegment, "get", descriptor); retBufOffset += abi.arch.typeSize(vmLoad.storage().type()); pushType(loadType); @@ -809,7 +810,7 @@ public class BindingSpecializer { if (SharedUtils.isPowerOfTwo(byteWidth)) { ClassDesc valueLayoutType = emitLoadLayoutConstant(loadType); cb.loadConstant(offset); - MethodTypeDesc descriptor = MethodTypeDesc.of(desc(loadType), valueLayoutType, CD_long); + MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(loadType), valueLayoutType, CD_long); cb.invokeinterface(CD_MemorySegment, "get", descriptor); } else { // chunked @@ -849,7 +850,7 @@ public class BindingSpecializer { // read from segment cb.loadLocal(ReferenceType, readAddrIdx); ClassDesc valueLayoutType = emitLoadLayoutConstant(chunkType); - MethodTypeDesc descriptor = MethodTypeDesc.of(desc(chunkType), valueLayoutType, CD_long); + MethodTypeDesc descriptor = MethodTypeDesc.of(classDesc(chunkType), valueLayoutType, CD_long); long readOffset = offset + SharedUtils.pickChunkOffset(chunkOffset, byteWidth, chunkSize); cb.loadConstant(readOffset); cb.invokeinterface(CD_MemorySegment, "get", descriptor); @@ -988,9 +989,4 @@ public class BindingSpecializer { case ReferenceType -> cb.aconst_null(); } } - - @SuppressWarnings("unchecked") - private static T desc(Constable c) { - return (T) c.describeConstable().orElseThrow(); - } } diff --git a/src/java.base/share/classes/sun/invoke/util/Wrapper.java b/src/java.base/share/classes/sun/invoke/util/Wrapper.java index 5f2e9ba2841..5d0849cd93d 100644 --- a/src/java.base/share/classes/sun/invoke/util/Wrapper.java +++ b/src/java.base/share/classes/sun/invoke/util/Wrapper.java @@ -32,20 +32,31 @@ import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; public enum Wrapper { - // wrapperType simple primitiveType simple char emptyArray format numericClass superClass classDescriptor - BOOLEAN( Boolean.class, "Boolean", boolean.class, "boolean", 'Z', new boolean[0], Format.unsigned( 1), 0, 0, ConstantDescs.CD_boolean), + // wrapperType simple primitiveType simple char emptyArray format numericClass superClass + // basicClassDescriptor wrapperClassDescriptor + BOOLEAN( Boolean.class, "Boolean", boolean.class, "boolean", 'Z', new boolean[0], Format.unsigned( 1), 0, 0, + ConstantDescs.CD_boolean, ConstantDescs.CD_Boolean), // These must be in the order defined for widening primitive conversions in JLS 5.1.2 // Avoid boxing integral types here to defer initialization of internal caches - BYTE ( Byte.class, "Byte", byte.class, "byte", 'B', new byte[0], Format.signed( 8), BYTE_CLASS, BYTE_SUPERCLASSES, ConstantDescs.CD_byte), - SHORT ( Short.class, "Short", short.class, "short", 'S', new short[0], Format.signed( 16), SHORT_CLASS, SHORT_SUPERCLASSES, ConstantDescs.CD_short), - CHAR (Character.class, "Character", char.class, "char", 'C', new char[0], Format.unsigned(16), CHAR_CLASS, CHAR_SUPERCLASSES, ConstantDescs.CD_char), - INT ( Integer.class, "Integer", int.class, "int", 'I', new int[0], Format.signed( 32), INT_CLASS, INT_SUPERCLASSES, ConstantDescs.CD_int), - LONG ( Long.class, "Long", long.class, "long", 'J', new long[0], Format.signed( 64), LONG_CLASS, LONG_SUPERCLASSES, ConstantDescs.CD_long), - FLOAT ( Float.class, "Float", float.class, "float", 'F', new float[0], Format.floating(32), FLOAT_CLASS, FLOAT_SUPERCLASSES, ConstantDescs.CD_float), - DOUBLE ( Double.class, "Double", double.class, "double", 'D', new double[0], Format.floating(64), DOUBLE_CLASS, DOUBLE_CLASS, ConstantDescs.CD_double), - OBJECT ( Object.class, "Object", Object.class, "Object", 'L', new Object[0], Format.other( 1), 0, 0, ConstantDescs.CD_Object), + BYTE ( Byte.class, "Byte", byte.class, "byte", 'B', new byte[0], Format.signed( 8), BYTE_CLASS, BYTE_SUPERCLASSES, + ConstantDescs.CD_byte, ConstantDescs.CD_Byte), + SHORT ( Short.class, "Short", short.class, "short", 'S', new short[0], Format.signed( 16), SHORT_CLASS, SHORT_SUPERCLASSES, + ConstantDescs.CD_short, ConstantDescs.CD_Short), + CHAR (Character.class, "Character", char.class, "char", 'C', new char[0], Format.unsigned(16), CHAR_CLASS, CHAR_SUPERCLASSES, + ConstantDescs.CD_char, ConstantDescs.CD_Character), + INT ( Integer.class, "Integer", int.class, "int", 'I', new int[0], Format.signed( 32), INT_CLASS, INT_SUPERCLASSES, + ConstantDescs.CD_int, ConstantDescs.CD_Integer), + LONG ( Long.class, "Long", long.class, "long", 'J', new long[0], Format.signed( 64), LONG_CLASS, LONG_SUPERCLASSES, + ConstantDescs.CD_long, ConstantDescs.CD_Long), + FLOAT ( Float.class, "Float", float.class, "float", 'F', new float[0], Format.floating(32), FLOAT_CLASS, FLOAT_SUPERCLASSES, + ConstantDescs.CD_float, ConstantDescs.CD_Float), + DOUBLE ( Double.class, "Double", double.class, "double", 'D', new double[0], Format.floating(64), DOUBLE_CLASS, DOUBLE_CLASS, + ConstantDescs.CD_double, ConstantDescs.CD_Double), + OBJECT ( Object.class, "Object", Object.class, "Object", 'L', new Object[0], Format.other( 1), 0, 0, + ConstantDescs.CD_Object, ConstantDescs.CD_Object), // VOID must be the last type, since it is "assignable" from any other type: - VOID ( Void.class, "Void", void.class, "void", 'V', null, Format.other( 0), 0, 0, ConstantDescs.CD_void), + VOID ( Void.class, "Void", void.class, "void", 'V', null, Format.other( 0), 0, 0, + ConstantDescs.CD_void, ConstantDescs.CD_Void), ; public static final int COUNT = 10; @@ -60,18 +71,20 @@ public enum Wrapper { private final int superClasses; private final String wrapperSimpleName; private final String primitiveSimpleName; - private final ClassDesc classDesc; + private final ClassDesc basicClassDesc; + private final ClassDesc wrapperClassDesc; - private Wrapper(Class wtype, - String wtypeName, - Class ptype, - String ptypeName, - char tchar, - Object emptyArray, - int format, - int numericClass, - int superClasses, - ClassDesc classDesc) { + Wrapper(Class wtype, + String wtypeName, + Class ptype, + String ptypeName, + char tchar, + Object emptyArray, + int format, + int numericClass, + int superClasses, + ClassDesc basicClassDesc, + ClassDesc wrapperClassDesc) { this.wrapperType = wtype; this.primitiveType = ptype; this.basicTypeChar = tchar; @@ -82,7 +95,8 @@ public enum Wrapper { this.superClasses = superClasses; this.wrapperSimpleName = wtypeName; this.primitiveSimpleName = ptypeName; - this.classDesc = classDesc; + this.basicClassDesc = basicClassDesc; + this.wrapperClassDesc = wrapperClassDesc; } /** For debugging, give the details of this wrapper. */ @@ -390,7 +404,10 @@ public enum Wrapper { } /** A nominal descriptor of the wrapped type */ - public ClassDesc classDescriptor() { return classDesc; } + public ClassDesc basicClassDescriptor() { return basicClassDesc; } + + /** A nominal descriptor of the wrapper type */ + public ClassDesc wrapperClassDescriptor() { return wrapperClassDesc; } /** What is the primitive type wrapped by this wrapper? */ public Class primitiveType() { return primitiveType; }