8333749: Consolidate ConstantDesc conversion in java.base

Co-authored-by: Claes Redestad <redestad@openjdk.org>
Reviewed-by: redestad, jvernee
This commit is contained in:
Chen Liang 2024-06-08 13:05:36 +00:00 committed by Claes Redestad
parent a6fc2f839a
commit 8d2f9e57c3
13 changed files with 208 additions and 142 deletions

View file

@ -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<T> implements java.io.Serializable,
public Optional<ClassDesc> describeConstable() {
Class<?> c = isArray() ? elementType() : this;
return c.isHidden() ? Optional.empty()
: Optional.of(ClassDesc.ofDescriptor(descriptorString()));
: Optional.of(ConstantUtils.classDesc(this));
}
/**

View file

@ -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<? super ClassBuilder> handler) {
return build(ClassDesc.of("module-info"), clb -> {
return build(CD_module_info, clb -> {
clb.withFlags(AccessFlag.MODULE);
clb.with(moduleAttribute);
handler.accept(clb);

View file

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

View file

@ -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<ClassDesc> 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<ClassDesc> 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();

View file

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

View file

@ -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<Class<?>> interfaces,
private ProxyGenerator(String className, List<Class<?>> 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<Class<?>> 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<ClassEntry> toClassEntries(ConstantPoolBuilder cp, List<Class<?>> types) {
var ces = new ArrayList<ClassEntry>(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<ProxyMethod> 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<ProxyMethod> 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();
}
}

View file

@ -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<EnumDesc<?>> enumDescs = new ArrayList<>();
List<Class<?>> 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",