8338545: Functional interface implementations for common pre-boot ClassFile operations

Reviewed-by: asotona
This commit is contained in:
Chen Liang 2024-08-21 11:58:21 +00:00
parent 7458952ded
commit 80adea8e0a
11 changed files with 76 additions and 106 deletions

View file

@ -165,7 +165,7 @@ public sealed interface ClassBuilder
default ClassBuilder withField(Utf8Entry name,
Utf8Entry descriptor,
int flags) {
return withField(name, descriptor, fb -> fb.withFlags(flags));
return withField(name, descriptor, Util.buildingFlags(flags));
}
/**
@ -194,7 +194,7 @@ public sealed interface ClassBuilder
default ClassBuilder withField(String name,
ClassDesc descriptor,
int flags) {
return withField(name, descriptor, fb -> fb.withFlags(flags));
return withField(name, descriptor, Util.buildingFlags(flags));
}
/**
@ -241,7 +241,7 @@ public sealed interface ClassBuilder
Utf8Entry descriptor,
int methodFlags,
Consumer<? super CodeBuilder> handler) {
return withMethod(name, descriptor, methodFlags, mb -> mb.withCode(handler));
return withMethod(name, descriptor, methodFlags, Util.buildingCode(handler));
}
/**
@ -276,7 +276,7 @@ public sealed interface ClassBuilder
MethodTypeDesc descriptor,
int methodFlags,
Consumer<? super CodeBuilder> handler) {
return withMethod(name, descriptor, methodFlags, mb -> mb.withCode(handler));
return withMethod(name, descriptor, methodFlags, Util.buildingCode(handler));
}
/**

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -31,7 +31,6 @@ import java.lang.classfile.attribute.SourceFileAttribute;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.LambdaForm.BasicType;
import java.lang.invoke.InnerClassLambdaMetafactory.MethodBody;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@ -68,8 +67,6 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
private static final ClassDesc CD_LambdaForm = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/LambdaForm;");
private static final ClassDesc CD_BoundMethodHandle = ReferenceClassDescImpl.ofValidated("Ljava/lang/invoke/BoundMethodHandle;");
private static final Consumer<FieldBuilder> STATIC_FIELD_FLAGS = new InnerClassLambdaMetafactory.FieldFlags(ACC_STATIC);
private static final Consumer<FieldBuilder> FINAL_FIELD_FLAGS = new InnerClassLambdaMetafactory.FieldFlags(ACC_FINAL);
private final Class<T> topClass;
private final Class<K> keyType;
@ -625,7 +622,7 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
.with(SourceFileAttribute.of(classDesc.displayName()))
// emit static types and BMH_SPECIES fields
.withField(sdFieldName, CD_SPECIES_DATA, STATIC_FIELD_FLAGS);
.withField(sdFieldName, CD_SPECIES_DATA, ACC_STATIC);
// handy holder for dealing with groups of typed values (ctor arguments and fields)
class Var {
@ -709,26 +706,26 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
// emit bound argument fields
for (Var field : fields) {
clb.withField(field.name, field.desc, FINAL_FIELD_FLAGS);
clb.withField(field.name, field.desc, ACC_FINAL);
}
// emit implementation of speciesData()
clb.withMethod(SPECIES_DATA_NAME, MTD_SPECIES_DATA, (SPECIES_DATA_MODS & ACC_PPP) | ACC_FINAL,
new MethodBody(new Consumer<CodeBuilder>() {
clb.withMethodBody(SPECIES_DATA_NAME, MTD_SPECIES_DATA, (SPECIES_DATA_MODS & ACC_PPP) | ACC_FINAL,
new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
cob.getstatic(classDesc, sdFieldName, CD_SPECIES_DATA)
.areturn();
}
}));
});
// figure out the constructor arguments
MethodType superCtorType = ClassSpecializer.this.baseConstructorType();
MethodType thisCtorType = superCtorType.appendParameterTypes(fieldTypes);
// emit constructor
clb.withMethod(INIT_NAME, methodDesc(thisCtorType), ACC_PRIVATE,
new MethodBody(new Consumer<CodeBuilder>() {
clb.withMethodBody(INIT_NAME, methodDesc(thisCtorType), ACC_PRIVATE,
new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
cob.aload(0); // this
@ -753,12 +750,12 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
cob.return_();
}
}));
});
// emit make() ...factory method wrapping constructor
MethodType ftryType = thisCtorType.changeReturnType(topClass());
clb.withMethod("make", methodDesc(ftryType), ACC_STATIC,
new MethodBody(new Consumer<CodeBuilder>() {
clb.withMethodBody("make", methodDesc(ftryType), ACC_STATIC,
new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
// make instance
@ -773,7 +770,7 @@ abstract class ClassSpecializer<T,K,S extends ClassSpecializer<T,K,S>.SpeciesDat
cob.invokespecial(classDesc, INIT_NAME, methodDesc(thisCtorType))
.areturn();
}
}));
});
// For each transform, emit the customized override of the transform method.
// This method mixes together some incoming arguments (from the transform's

View file

@ -72,20 +72,6 @@ import sun.invoke.util.Wrapper;
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final ClassDesc[] EMPTY_CLASSDESC_ARRAY = ConstantUtils.EMPTY_CLASSDESC;
// Static builders to avoid lambdas
record FieldFlags(int flags) implements Consumer<FieldBuilder> {
@Override
public void accept(FieldBuilder fb) {
fb.withFlags(flags);
}
};
record MethodBody(Consumer<CodeBuilder> code) implements Consumer<MethodBuilder> {
@Override
public void accept(MethodBuilder mb) {
mb.withCode(code);
}
};
// For dumping generated classes to disk, for debugging purposes
private static final ClassFileDumper lambdaProxyClassFileDumper;
@ -324,7 +310,7 @@ import sun.invoke.util.Wrapper;
.withInterfaceSymbols(interfaces);
// Generate final fields to be filled in by constructor
for (int i = 0; i < argDescs.length; i++) {
clb.withField(argNames[i], argDescs[i], new FieldFlags(ACC_PRIVATE | ACC_FINAL));
clb.withField(argNames[i], argDescs[i], ACC_PRIVATE | ACC_FINAL);
}
generateConstructor(clb);
@ -334,7 +320,7 @@ import sun.invoke.util.Wrapper;
}
// Forward the SAM method
clb.withMethod(interfaceMethodName,
clb.withMethodBody(interfaceMethodName,
methodDesc(interfaceMethodType),
ACC_PUBLIC,
forwardingMethod(interfaceMethodType));
@ -342,7 +328,7 @@ import sun.invoke.util.Wrapper;
// Forward the bridges
if (altMethods != null) {
for (MethodType mt : altMethods) {
clb.withMethod(interfaceMethodName,
clb.withMethodBody(interfaceMethodName,
methodDesc(mt),
ACC_PUBLIC | ACC_BRIDGE,
forwardingMethod(mt));
@ -376,10 +362,10 @@ import sun.invoke.util.Wrapper;
ClassDesc lambdaTypeDescriptor = classDesc(factoryType.returnType());
// Generate the static final field that holds the lambda singleton
clb.withField(LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor, new FieldFlags(ACC_PRIVATE | ACC_STATIC | ACC_FINAL));
clb.withField(LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor, ACC_PRIVATE | ACC_STATIC | ACC_FINAL);
// Instantiate the lambda and store it to the static final field
clb.withMethod(CLASS_INIT_NAME, MTD_void, ACC_STATIC, new MethodBody(new Consumer<CodeBuilder>() {
clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
assert factoryType.parameterCount() == 0;
@ -389,7 +375,7 @@ import sun.invoke.util.Wrapper;
.putstatic(lambdaClassDesc, LAMBDA_INSTANCE_FIELD, lambdaTypeDescriptor)
.return_();
}
}));
});
}
/**
@ -397,8 +383,8 @@ import sun.invoke.util.Wrapper;
*/
private void generateConstructor(ClassBuilder clb) {
// Generate constructor
clb.withMethod(INIT_NAME, constructorTypeDesc, ACC_PRIVATE,
new MethodBody(new Consumer<CodeBuilder>() {
clb.withMethodBody(INIT_NAME, constructorTypeDesc, ACC_PRIVATE,
new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
cob.aload(0)
@ -412,7 +398,7 @@ import sun.invoke.util.Wrapper;
}
cob.return_();
}
}));
});
}
private static class SerializationSupport {
@ -439,8 +425,8 @@ import sun.invoke.util.Wrapper;
* Generate a writeReplace method that supports serialization
*/
private void generateSerializationFriendlyMethods(ClassBuilder clb) {
clb.withMethod(SerializationSupport.NAME_METHOD_WRITE_REPLACE, SerializationSupport.MTD_Object, ACC_PRIVATE | ACC_FINAL,
new MethodBody(new Consumer<CodeBuilder>() {
clb.withMethodBody(SerializationSupport.NAME_METHOD_WRITE_REPLACE, SerializationSupport.MTD_Object, ACC_PRIVATE | ACC_FINAL,
new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
cob.new_(SerializationSupport.CD_SerializedLambda)
@ -468,7 +454,7 @@ import sun.invoke.util.Wrapper;
SerializationSupport.MTD_CTOR_SERIALIZED_LAMBDA)
.areturn();
}
}));
});
}
/**
@ -504,8 +490,8 @@ import sun.invoke.util.Wrapper;
* This method generates a method body which calls the lambda implementation
* method, converting arguments, as needed.
*/
Consumer<MethodBuilder> forwardingMethod(MethodType methodType) {
return new MethodBody(new Consumer<CodeBuilder>() {
Consumer<CodeBuilder> forwardingMethod(MethodType methodType) {
return new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
if (implKind == MethodHandleInfo.REF_newInvokeSpecial) {
@ -542,7 +528,7 @@ import sun.invoke.util.Wrapper;
TypeConvertingMethodAdapter.convertType(cob, implReturnClass, samReturnClass, samReturnClass);
cob.return_(TypeKind.from(samReturnClass));
}
});
};
}
private void convertArgumentTypes(CodeBuilder cob, MethodType samType) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@ -83,21 +83,6 @@ class InvokerBytecodeGenerator {
private static final String CLASS_PREFIX = "java/lang/invoke/LambdaForm$";
private static final String SOURCE_PREFIX = "LambdaForm$";
// Static builders to avoid lambdas
private static final Consumer<FieldBuilder> STATIC_FINAL_FIELD = new Consumer<FieldBuilder>() {
@Override
public void accept(FieldBuilder fb) {
fb.withFlags(ACC_STATIC | ACC_FINAL);
}
};
record MethodBody(Consumer<CodeBuilder> code) implements Consumer<MethodBuilder> {
@Override
public void accept(MethodBuilder mb) {
mb.withCode(code);
}
};
/** Name of its super class*/
static final ClassDesc INVOKER_SUPER_DESC = CD_Object;
@ -328,10 +313,10 @@ class InvokerBytecodeGenerator {
for (ClassData p : classData) {
// add the static field
clb.withField(p.name, p.desc, STATIC_FINAL_FIELD);
clb.withField(p.name, p.desc, ACC_STATIC | ACC_FINAL);
}
clb.withMethod(CLASS_INIT_NAME, MTD_void, ACC_STATIC, new MethodBody(new Consumer<CodeBuilder>() {
clb.withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
cob.loadConstant(classDesc)
@ -356,7 +341,7 @@ class InvokerBytecodeGenerator {
}
cob.return_();
}
}));
});
}
private void emitLoadInsn(CodeBuilder cob, TypeKind type, int index) {
@ -1671,14 +1656,14 @@ class InvokerBytecodeGenerator {
*/
private void bogusMethod(ClassBuilder clb, Object os) {
if (dumper().isEnabled()) {
clb.withMethod("dummy", MTD_void, ACC_STATIC, new MethodBody(new Consumer<CodeBuilder>() {
clb.withMethodBody("dummy", MTD_void, ACC_STATIC, new Consumer<>() {
@Override
public void accept(CodeBuilder cob) {
cob.loadConstant(os.toString());
cob.pop();
cob.return_();
}
}));
});
}
}