8339683: Simplify class data generation in InvokerBytecodeGenerator
Reviewed-by: redestad
This commit is contained in:
parent
7c0f013d92
commit
a9bb04331d
@ -563,7 +563,7 @@ class GenerateJLIClassesHelper {
|
||||
.withSuperclass(InvokerBytecodeGenerator.INVOKER_SUPER_DESC)
|
||||
.with(SourceFileAttribute.of(className.substring(className.lastIndexOf('/') + 1)));
|
||||
for (int i = 0; i < forms.length; i++) {
|
||||
new InvokerBytecodeGenerator(className, names[i], forms[i], forms[i].methodType()).addMethod(clb);
|
||||
new InvokerBytecodeGenerator(className, names[i], forms[i], forms[i].methodType()).addMethod(clb, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import sun.invoke.util.Wrapper;
|
||||
import java.lang.classfile.*;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import java.lang.classfile.attribute.SourceFileAttribute;
|
||||
import java.lang.classfile.constantpool.FieldRefEntry;
|
||||
import java.lang.classfile.instruction.SwitchCase;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
@ -196,35 +197,9 @@ class InvokerBytecodeGenerator {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
static class ClassData {
|
||||
final String name;
|
||||
final ClassDesc desc;
|
||||
final Object value;
|
||||
|
||||
ClassData(String name, ClassDesc desc, Object value) {
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String name() { return name; }
|
||||
public String toString() {
|
||||
return name + ",value="+value;
|
||||
}
|
||||
}
|
||||
|
||||
String classData(Object arg) {
|
||||
ClassDesc desc;
|
||||
if (arg instanceof Class) {
|
||||
desc = CD_Class;
|
||||
} else if (arg instanceof MethodHandle) {
|
||||
desc = CD_MethodHandle;
|
||||
} else if (arg instanceof LambdaForm) {
|
||||
desc = CD_LambdaForm;
|
||||
} else {
|
||||
desc = CD_Object;
|
||||
}
|
||||
record ClassData(FieldRefEntry field, Object value) {}
|
||||
|
||||
FieldRefEntry classData(ClassFileBuilder<?, ?> cfb, Object arg, ClassDesc desc) {
|
||||
// unique static variable name
|
||||
String name;
|
||||
List<ClassData> classData = this.classData;
|
||||
@ -237,8 +212,9 @@ class InvokerBytecodeGenerator {
|
||||
} else {
|
||||
name = "_D_" + classData.size();
|
||||
}
|
||||
classData.add(new ClassData(name, desc, arg));
|
||||
return name;
|
||||
var field = cfb.constantPool().fieldRefEntry(classDesc, name, desc);
|
||||
classData.add(new ClassData(field, arg));
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -328,27 +304,31 @@ class InvokerBytecodeGenerator {
|
||||
.invokestatic(CD_MethodHandles, "classData", MTD_Object_Class);
|
||||
int size = classData.size();
|
||||
if (size == 1) {
|
||||
ClassData p = classData.get(0);
|
||||
var field = classData.getFirst().field;
|
||||
// add the static field
|
||||
clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL);
|
||||
clb.withField(field.name(), field.type(), ACC_STATIC | ACC_FINAL);
|
||||
|
||||
cob.checkcast(p.desc)
|
||||
.putstatic(classDesc, p.name, p.desc);
|
||||
var ft = field.typeSymbol();
|
||||
if (ft != CD_Object)
|
||||
cob.checkcast(ft);
|
||||
cob.putstatic(field);
|
||||
} else {
|
||||
cob.checkcast(CD_List)
|
||||
.astore(0);
|
||||
int index = 0;
|
||||
var listGet = cob.constantPool().interfaceMethodRefEntry(CD_List, "get", MTD_Object_int);
|
||||
for (int i = 0; i < size; i++) {
|
||||
ClassData p = classData.get(i);
|
||||
var field = classData.get(i).field;
|
||||
// add the static field
|
||||
clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL);
|
||||
clb.withField(field.name(), field.type(), ACC_STATIC | ACC_FINAL);
|
||||
// initialize the static field
|
||||
cob.aload(0)
|
||||
.loadConstant(index++)
|
||||
.invokeinterface(listGet)
|
||||
.checkcast(p.desc)
|
||||
.putstatic(classDesc, p.name, p.desc);
|
||||
.invokeinterface(listGet);
|
||||
var ft = field.typeSymbol();
|
||||
if (ft != CD_Object)
|
||||
cob.checkcast(ft);
|
||||
cob.putstatic(field);
|
||||
}
|
||||
}
|
||||
cob.return_();
|
||||
@ -366,8 +346,6 @@ class InvokerBytecodeGenerator {
|
||||
|
||||
/**
|
||||
* Emit a boxing call.
|
||||
*
|
||||
* @param wrapper primitive type class to box.
|
||||
*/
|
||||
private void emitBoxing(CodeBuilder cob, TypeKind tk) {
|
||||
TypeConvertingMethodAdapter.box(cob, tk);
|
||||
@ -375,8 +353,6 @@ class InvokerBytecodeGenerator {
|
||||
|
||||
/**
|
||||
* Emit an unboxing call (plus preceding checkcast).
|
||||
*
|
||||
* @param wrapper wrapper type class to unbox.
|
||||
*/
|
||||
private void emitUnboxing(CodeBuilder cob, TypeKind target) {
|
||||
switch (target) {
|
||||
@ -445,7 +421,7 @@ class InvokerBytecodeGenerator {
|
||||
ClassDesc sig = classDesc(cls);
|
||||
cob.checkcast(sig);
|
||||
} else {
|
||||
cob.getstatic(classDesc, classData(cls), CD_Class)
|
||||
cob.getstatic(classData(cob, cls, CD_Class))
|
||||
.swap()
|
||||
.invokevirtual(CD_Class, "cast", MTD_Object_Object);
|
||||
if (Object[].class.isAssignableFrom(cls))
|
||||
@ -554,10 +530,10 @@ class InvokerBytecodeGenerator {
|
||||
* Generate an invoker method for the passed {@link LambdaForm}.
|
||||
*/
|
||||
private byte[] generateCustomizedCodeBytes() {
|
||||
final byte[] classFile = classFileSetup(new Consumer<ClassBuilder>() {
|
||||
final byte[] classFile = classFileSetup(new Consumer<>() {
|
||||
@Override
|
||||
public void accept(ClassBuilder clb) {
|
||||
addMethod(clb);
|
||||
addMethod(clb, true);
|
||||
clinit(clb, classDesc, classData);
|
||||
bogusMethod(clb, lambdaForm);
|
||||
}
|
||||
@ -565,8 +541,8 @@ class InvokerBytecodeGenerator {
|
||||
return classFile;
|
||||
}
|
||||
|
||||
void addMethod(ClassBuilder clb) {
|
||||
methodSetup(clb, new Consumer<MethodBuilder>() {
|
||||
void addMethod(ClassBuilder clb, boolean alive) {
|
||||
methodSetup(clb, new Consumer<>() {
|
||||
@Override
|
||||
public void accept(MethodBuilder mb) {
|
||||
|
||||
@ -576,9 +552,11 @@ class InvokerBytecodeGenerator {
|
||||
mb.accept(LF_DONTINLINE_ANNOTATIONS);
|
||||
}
|
||||
|
||||
classData(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled.
|
||||
if (alive) {
|
||||
classData(mb, lambdaForm, CD_LambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled.
|
||||
}
|
||||
|
||||
mb.withCode(new Consumer<CodeBuilder>() {
|
||||
mb.withCode(new Consumer<>() {
|
||||
@Override
|
||||
public void accept(CodeBuilder cob) {
|
||||
if (lambdaForm.customized != null) {
|
||||
@ -586,8 +564,7 @@ class InvokerBytecodeGenerator {
|
||||
// receiver MethodHandle (at slot #0) with an embedded constant and use it instead.
|
||||
// It enables more efficient code generation in some situations, since embedded constants
|
||||
// are compile-time constants for JIT compiler.
|
||||
cob.getstatic(classDesc, classData(lambdaForm.customized), CD_MethodHandle)
|
||||
.checkcast(CD_MethodHandle);
|
||||
cob.getstatic(classData(cob, lambdaForm.customized, CD_MethodHandle));
|
||||
assert(checkActualReceiver(cob)); // expects MethodHandle on top of the stack
|
||||
cob.astore(0);
|
||||
}
|
||||
@ -720,7 +697,7 @@ class InvokerBytecodeGenerator {
|
||||
// push receiver
|
||||
MethodHandle target = name.function.resolvedHandle();
|
||||
assert(target != null) : name.exprString();
|
||||
cob.getstatic(classDesc, classData(target), CD_MethodHandle);
|
||||
cob.getstatic(classData(cob, target, CD_MethodHandle));
|
||||
emitReferenceCast(cob, MethodHandle.class, target);
|
||||
} else {
|
||||
// load receiver
|
||||
@ -1445,7 +1422,7 @@ class InvokerBytecodeGenerator {
|
||||
if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
|
||||
cob.loadConstant((ConstantDesc)arg);
|
||||
} else {
|
||||
cob.getstatic(classDesc, classData(arg), CD_Object);
|
||||
cob.getstatic(classData(cob, arg, CD_Object));
|
||||
emitImplicitConversion(cob, L_TYPE, ptype, arg);
|
||||
}
|
||||
}
|
||||
@ -1524,10 +1501,10 @@ class InvokerBytecodeGenerator {
|
||||
}
|
||||
|
||||
private byte[] generateLambdaFormInterpreterEntryPointBytes() {
|
||||
final byte[] classFile = classFileSetup(new Consumer<ClassBuilder>() {
|
||||
final byte[] classFile = classFileSetup(new Consumer<>() {
|
||||
@Override
|
||||
public void accept(ClassBuilder clb) {
|
||||
methodSetup(clb, new Consumer<MethodBuilder>() {
|
||||
methodSetup(clb, new Consumer<>() {
|
||||
@Override
|
||||
public void accept(MethodBuilder mb) {
|
||||
|
||||
@ -1536,7 +1513,7 @@ class InvokerBytecodeGenerator {
|
||||
DONTINLINE // Don't inline the interpreter entry.
|
||||
)));
|
||||
|
||||
mb.withCode(new Consumer<CodeBuilder>() {
|
||||
mb.withCode(new Consumer<>() {
|
||||
@Override
|
||||
public void accept(CodeBuilder cob) {
|
||||
// create parameter array
|
||||
@ -1593,10 +1570,10 @@ class InvokerBytecodeGenerator {
|
||||
|
||||
private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
|
||||
MethodType dstType = typeForm.erasedType();
|
||||
final byte[] classFile = classFileSetup(new Consumer<ClassBuilder>() {
|
||||
final byte[] classFile = classFileSetup(new Consumer<>() {
|
||||
@Override
|
||||
public void accept(ClassBuilder clb) {
|
||||
methodSetup(clb, new Consumer<MethodBuilder>() {
|
||||
methodSetup(clb, new Consumer<>() {
|
||||
@Override
|
||||
public void accept(MethodBuilder mb) {
|
||||
|
||||
@ -1605,7 +1582,7 @@ class InvokerBytecodeGenerator {
|
||||
FORCEINLINE // Force inlining of this invoker method.
|
||||
)));
|
||||
|
||||
mb.withCode(new Consumer<CodeBuilder>() {
|
||||
mb.withCode(new Consumer<>() {
|
||||
@Override
|
||||
public void accept(CodeBuilder cob) {
|
||||
// Load receiver
|
||||
|
Loading…
Reference in New Issue
Block a user