8339799: Reduce work done in j.l.invoke bytecode generators

Reviewed-by: liach
This commit is contained in:
Claes Redestad 2024-09-10 13:33:19 +00:00
parent 38441b3f2d
commit c246ede163
2 changed files with 25 additions and 21 deletions

View File

@ -97,7 +97,8 @@ import sun.invoke.util.Wrapper;
private final String[] argNames; // Generated names for the constructor arguments private final String[] argNames; // Generated names for the constructor arguments
private final ClassDesc[] argDescs; // Type descriptors for the constructor arguments private final ClassDesc[] argDescs; // Type descriptors for the constructor arguments
private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1"
private final ClassDesc lambdaClassDesc; // Type descriptor for the generated class "X$$Lambda$1" private final ConstantPoolBuilder pool = ConstantPoolBuilder.of();
private final ClassEntry lambdaClassEntry; // Class entry for the generated class "X$$Lambda$1"
private final boolean useImplMethodHandle; // use MethodHandle invocation instead of symbolic bytecode invocation private final boolean useImplMethodHandle; // use MethodHandle invocation instead of symbolic bytecode invocation
/** /**
@ -157,9 +158,8 @@ import sun.invoke.util.Wrapper;
implMethodName = implInfo.getName(); implMethodName = implInfo.getName();
implMethodDesc = methodDesc(implInfo.getMethodType()); implMethodDesc = methodDesc(implInfo.getMethodType());
constructorType = factoryType.changeReturnType(Void.TYPE); constructorType = factoryType.changeReturnType(Void.TYPE);
constructorTypeDesc = methodDesc(constructorType);
lambdaClassName = lambdaClassName(targetClass); lambdaClassName = lambdaClassName(targetClass);
lambdaClassDesc = ClassDesc.ofInternalName(lambdaClassName); lambdaClassEntry = pool.classEntry(ReferenceClassDescImpl.ofValidated(ConstantUtils.concat("L", lambdaClassName, ";")));
// If the target class invokes a protected method inherited from a // If the target class invokes a protected method inherited from a
// superclass in a different package, or does 'invokespecial', the // superclass in a different package, or does 'invokespecial', the
// lambda class has no access to the resolved method, or does // lambda class has no access to the resolved method, or does
@ -183,6 +183,7 @@ import sun.invoke.util.Wrapper;
argNames = EMPTY_STRING_ARRAY; argNames = EMPTY_STRING_ARRAY;
argDescs = EMPTY_CLASSDESC_ARRAY; argDescs = EMPTY_CLASSDESC_ARRAY;
} }
constructorTypeDesc = MethodTypeDescImpl.ofValidated(CD_void, argDescs);
} }
private static String lambdaClassName(Class<?> targetClass) { private static String lambdaClassName(Class<?> targetClass) {
@ -191,7 +192,7 @@ import sun.invoke.util.Wrapper;
// use the original class name // use the original class name
name = name.replace('/', '_'); name = name.replace('/', '_');
} }
return name.replace('.', '/') + "$$Lambda"; return name.replace('.', '/').concat("$$Lambda");
} }
/** /**
@ -221,7 +222,7 @@ import sun.invoke.util.Wrapper;
MethodHandle mh = caller.findConstructor(innerClass, constructorType); MethodHandle mh = caller.findConstructor(innerClass, constructorType);
if (factoryType.parameterCount() == 0) { if (factoryType.parameterCount() == 0) {
// In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance // In the case of a non-capturing lambda, we optimize linkage by pre-computing a single instance
Object inst = mh.asType(methodType(Object.class)).invokeExact(); Object inst = mh.invokeBasic();
return new ConstantCallSite(MethodHandles.constant(interfaceClass, inst)); return new ConstantCallSite(MethodHandles.constant(interfaceClass, inst));
} else { } else {
return new ConstantCallSite(mh.asType(factoryType)); return new ConstantCallSite(mh.asType(factoryType));
@ -303,7 +304,7 @@ import sun.invoke.util.Wrapper;
interfaces = List.copyOf(itfs); interfaces = List.copyOf(itfs);
} }
final boolean finalAccidentallySerializable = accidentallySerializable; final boolean finalAccidentallySerializable = accidentallySerializable;
final byte[] classBytes = ClassFile.of().build(lambdaClassDesc, new Consumer<ClassBuilder>() { final byte[] classBytes = ClassFile.of().build(lambdaClassEntry, pool, new Consumer<ClassBuilder>() {
@Override @Override
public void accept(ClassBuilder clb) { public void accept(ClassBuilder clb) {
clb.withFlags(ACC_SUPER | ACC_FINAL | ACC_SYNTHETIC) clb.withFlags(ACC_SUPER | ACC_FINAL | ACC_SYNTHETIC)
@ -369,10 +370,10 @@ import sun.invoke.util.Wrapper;
@Override @Override
public void accept(CodeBuilder cob) { public void accept(CodeBuilder cob) {
assert factoryType.parameterCount() == 0; assert factoryType.parameterCount() == 0;
cob.new_(lambdaClassDesc) cob.new_(lambdaClassEntry)
.dup() .dup()
.invokespecial(lambdaClassDesc, INIT_NAME, constructorTypeDesc) .invokespecial(pool.methodRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(INIT_NAME, constructorTypeDesc)))
.putstatic(lambdaClassDesc, LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor) .putstatic(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor)))
.return_(); .return_();
} }
}); });
@ -394,7 +395,7 @@ import sun.invoke.util.Wrapper;
cob.aload(0); cob.aload(0);
Class<?> argType = factoryType.parameterType(i); Class<?> argType = factoryType.parameterType(i);
cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i)); cob.loadLocal(TypeKind.from(argType), cob.parameterSlot(i));
cob.putfield(lambdaClassDesc, argNames[i], argDescs[i]); cob.putfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i])));
} }
cob.return_(); cob.return_();
} }
@ -446,7 +447,7 @@ import sun.invoke.util.Wrapper;
cob.dup() cob.dup()
.loadConstant(i) .loadConstant(i)
.aload(0) .aload(0)
.getfield(lambdaClassDesc, argNames[i], argDescs[i]); .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i])));
TypeConvertingMethodAdapter.boxIfTypePrimitive(cob, TypeKind.from(argDescs[i])); TypeConvertingMethodAdapter.boxIfTypePrimitive(cob, TypeKind.from(argDescs[i]));
cob.aastore(); cob.aastore();
} }
@ -505,7 +506,7 @@ import sun.invoke.util.Wrapper;
} }
for (int i = 0; i < argNames.length; i++) { for (int i = 0; i < argNames.length; i++) {
cob.aload(0) cob.aload(0)
.getfield(lambdaClassDesc, argNames[i], argDescs[i]); .getfield(pool.fieldRefEntry(lambdaClassEntry, pool.nameAndTypeEntry(argNames[i], argDescs[i])));
} }
convertArgumentTypes(cob, methodType); convertArgumentTypes(cob, methodType);

View File

@ -32,6 +32,8 @@ import sun.invoke.util.Wrapper;
import java.lang.classfile.*; import java.lang.classfile.*;
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
import java.lang.classfile.attribute.SourceFileAttribute; import java.lang.classfile.attribute.SourceFileAttribute;
import java.lang.classfile.constantpool.ClassEntry;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.FieldRefEntry; import java.lang.classfile.constantpool.FieldRefEntry;
import java.lang.classfile.instruction.SwitchCase; import java.lang.classfile.instruction.SwitchCase;
import java.lang.constant.ClassDesc; import java.lang.constant.ClassDesc;
@ -93,7 +95,8 @@ class InvokerBytecodeGenerator {
/** Name of new class */ /** Name of new class */
private final String name; private final String name;
private final String className; private final String className;
private final ClassDesc classDesc; private final ConstantPoolBuilder pool = ConstantPoolBuilder.of();
private final ClassEntry classEntry;
private final LambdaForm lambdaForm; private final LambdaForm lambdaForm;
private final String invokerName; private final String invokerName;
@ -131,7 +134,7 @@ class InvokerBytecodeGenerator {
this.name = name; this.name = name;
this.className = CLASS_PREFIX.concat(name); this.className = CLASS_PREFIX.concat(name);
validateInternalClassName(name); validateInternalClassName(name);
this.classDesc = ReferenceClassDescImpl.ofValidated(concat("L", className, ";")); this.classEntry = pool.classEntry(ReferenceClassDescImpl.ofValidated(concat("L", className, ";")));
this.lambdaForm = lambdaForm; this.lambdaForm = lambdaForm;
this.invokerName = invokerName; this.invokerName = invokerName;
this.invokerType = invokerType; this.invokerType = invokerType;
@ -212,7 +215,7 @@ class InvokerBytecodeGenerator {
} else { } else {
name = "_D_" + classData.size(); name = "_D_" + classData.size();
} }
var field = cfb.constantPool().fieldRefEntry(classDesc, name, desc); var field = pool.fieldRefEntry(classEntry, pool.nameAndTypeEntry(name, desc));
classData.add(new ClassData(field, arg)); classData.add(new ClassData(field, arg));
return field; return field;
} }
@ -243,7 +246,7 @@ class InvokerBytecodeGenerator {
*/ */
private byte[] classFileSetup(Consumer<? super ClassBuilder> config) { private byte[] classFileSetup(Consumer<? super ClassBuilder> config) {
try { try {
return ClassFile.of().build(classDesc, new Consumer<>() { return ClassFile.of().build(classEntry, pool, new Consumer<>() {
@Override @Override
public void accept(ClassBuilder clb) { public void accept(ClassBuilder clb) {
clb.withFlags(ACC_ABSTRACT | ACC_SUPER) clb.withFlags(ACC_ABSTRACT | ACC_SUPER)
@ -293,14 +296,14 @@ class InvokerBytecodeGenerator {
* <clinit> to initialize the static final fields with the live class data * <clinit> to initialize the static final fields with the live class data
* LambdaForms can't use condy due to bootstrapping issue. * LambdaForms can't use condy due to bootstrapping issue.
*/ */
static void clinit(ClassBuilder clb, ClassDesc classDesc, List<ClassData> classData) { static void clinit(ClassBuilder clb, ClassEntry classEntry, List<ClassData> classData) {
if (classData.isEmpty()) if (classData.isEmpty())
return; return;
clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, new Consumer<>() { clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, new Consumer<>() {
@Override @Override
public void accept(CodeBuilder cob) { public void accept(CodeBuilder cob) {
cob.loadConstant(classDesc) cob.ldc(classEntry)
.invokestatic(CD_MethodHandles, "classData", MTD_Object_Class); .invokestatic(CD_MethodHandles, "classData", MTD_Object_Class);
int size = classData.size(); int size = classData.size();
if (size == 1) { if (size == 1) {
@ -534,7 +537,7 @@ class InvokerBytecodeGenerator {
@Override @Override
public void accept(ClassBuilder clb) { public void accept(ClassBuilder clb) {
addMethod(clb, true); addMethod(clb, true);
clinit(clb, classDesc, classData); clinit(clb, classEntry, classData);
bogusMethod(clb, lambdaForm); bogusMethod(clb, lambdaForm);
} }
}); });
@ -1551,7 +1554,7 @@ class InvokerBytecodeGenerator {
}); });
} }
}); });
clinit(clb, classDesc, classData); clinit(clb, classEntry, classData);
bogusMethod(clb, invokerType); bogusMethod(clb, invokerType);
} }
}); });
@ -1627,7 +1630,7 @@ class InvokerBytecodeGenerator {
}); });
} }
}); });
clinit(clb, classDesc, classData); clinit(clb, classEntry, classData);
bogusMethod(clb, dstType); bogusMethod(clb, dstType);
} }
}); });