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