8164451: Generate all zero and identity forms at link time
Reviewed-by: shade, mhaupt, vlivanov
This commit is contained in:
parent
22e95f995a
commit
4316d705f2
@ -38,6 +38,34 @@ import java.util.HashSet;
|
||||
*/
|
||||
class GenerateJLIClassesHelper {
|
||||
|
||||
static byte[] generateBasicFormsClassBytes(String className) {
|
||||
ArrayList<LambdaForm> forms = new ArrayList<>();
|
||||
ArrayList<String> names = new ArrayList<>();
|
||||
HashSet<String> dedupSet = new HashSet<>();
|
||||
for (LambdaForm.BasicType type : LambdaForm.BasicType.values()) {
|
||||
LambdaForm zero = LambdaForm.zeroForm(type);
|
||||
String name = zero.kind.defaultLambdaName
|
||||
+ "_" + zero.returnType().basicTypeChar();
|
||||
// since zero is the same as identity for Void, we deduplicate
|
||||
// aggressively to guard against this specifically and not get
|
||||
// caught on future equivalences
|
||||
if (dedupSet.add(name)) {
|
||||
names.add(name);
|
||||
forms.add(zero);
|
||||
}
|
||||
LambdaForm identity = LambdaForm.identityForm(type);
|
||||
name = identity.kind.defaultLambdaName
|
||||
+ "_" + identity.returnType().basicTypeChar();
|
||||
if (dedupSet.add(name)) {
|
||||
names.add(name);
|
||||
forms.add(identity);
|
||||
}
|
||||
}
|
||||
return generateCodeBytesForLFs(className,
|
||||
names.toArray(new String[0]),
|
||||
forms.toArray(new LambdaForm[0]));
|
||||
}
|
||||
|
||||
static byte[] generateDirectMethodHandleHolderClassBytes(String className,
|
||||
MethodType[] methodTypes, int[] types) {
|
||||
LambdaForm[] forms = new LambdaForm[methodTypes.length];
|
||||
|
@ -624,6 +624,11 @@ class InvokerBytecodeGenerator {
|
||||
return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
|
||||
}
|
||||
case DELEGATE: return resolveFrom(name, invokerType, DelegatingMethodHandle.Holder.class);
|
||||
case ZERO: // fall-through
|
||||
case IDENTITY: {
|
||||
name = name + "_" + form.returnType().basicTypeChar();
|
||||
return resolveFrom(name, invokerType, LambdaForm.Holder.class);
|
||||
}
|
||||
case DIRECT_INVOKE_INTERFACE: // fall-through
|
||||
case DIRECT_INVOKE_SPECIAL: // fall-through
|
||||
case DIRECT_INVOKE_STATIC: // fall-through
|
||||
|
@ -270,6 +270,8 @@ class LambdaForm {
|
||||
|
||||
enum Kind {
|
||||
GENERIC(""),
|
||||
ZERO("zero"),
|
||||
IDENTITY("identity"),
|
||||
BOUND_REINVOKER("BMH.reinvoke"),
|
||||
REINVOKER("MH.reinvoke"),
|
||||
DELEGATE("MH.delegate"),
|
||||
@ -1848,7 +1850,7 @@ class LambdaForm {
|
||||
// bootstrap dependency on this method in case we're interpreting LFs
|
||||
if (isVoid) {
|
||||
Name[] idNames = new Name[] { argument(0, L_TYPE) };
|
||||
idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
|
||||
idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT, Kind.IDENTITY);
|
||||
idForm.compileToBytecode();
|
||||
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
|
||||
|
||||
@ -1856,13 +1858,13 @@ class LambdaForm {
|
||||
zeFun = idFun;
|
||||
} else {
|
||||
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
|
||||
idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
|
||||
idForm = new LambdaForm(idMem.getName(), 2, idNames, 1, Kind.IDENTITY);
|
||||
idForm.compileToBytecode();
|
||||
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
|
||||
|
||||
Object zeValue = Wrapper.forBasicType(btChar).zero();
|
||||
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
|
||||
zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
|
||||
zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1, Kind.ZERO);
|
||||
zeForm.compileToBytecode();
|
||||
zeFun = new NamedFunction(zeMem, SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm));
|
||||
}
|
||||
@ -1921,8 +1923,17 @@ class LambdaForm {
|
||||
if (USE_PREDEFINED_INTERPRET_METHODS)
|
||||
computeInitialPreparedForms();
|
||||
NamedFunction.initializeInvokers();
|
||||
|
||||
// The Holder class will contain pre-generated forms resolved
|
||||
// using MemberName.getFactory(). However, that doesn't initialize the
|
||||
// class, which subtly breaks inlining etc. By forcing
|
||||
// initialization of the Holder class we avoid these issues.
|
||||
UNSAFE.ensureClassInitialized(Holder.class);
|
||||
}
|
||||
|
||||
/* Placeholder class for zero and identity forms generated ahead of time */
|
||||
final class Holder {}
|
||||
|
||||
// The following hack is necessary in order to suppress TRACE_INTERPRETER
|
||||
// during execution of the static initializes of this class.
|
||||
// Turning on TRACE_INTERPRETER too early will cause
|
||||
|
@ -1739,6 +1739,12 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
return GenerateJLIClassesHelper
|
||||
.generateConcreteBMHClassBytes(types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generateBasicFormsClassBytes(final String className) {
|
||||
return GenerateJLIClassesHelper
|
||||
.generateBasicFormsClassBytes(className);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -72,4 +72,10 @@ public interface JavaLangInvokeAccess {
|
||||
*/
|
||||
Map.Entry<String, byte[]> generateConcreteBMHClassBytes(
|
||||
final String types);
|
||||
|
||||
/**
|
||||
* Returns a {@code byte[]} containing the bytecode for a class implementing
|
||||
* the zero and identity forms of all {@code LambdaForm.BasicType}s.
|
||||
*/
|
||||
byte[] generateBasicFormsClassBytes(final String className);
|
||||
}
|
||||
|
@ -65,6 +65,8 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
|
||||
private static final String DELEGATING_METHOD_HANDLE = "java/lang/invoke/DelegatingMethodHandle$Holder";
|
||||
|
||||
private static final String BASIC_FORMS_HANDLE = "java/lang/invoke/LambdaForm$Holder";
|
||||
|
||||
private static final JavaLangInvokeAccess JLIA
|
||||
= SharedSecrets.getJavaLangInvokeAccess();
|
||||
|
||||
@ -227,14 +229,15 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
in.transformAndCopy(entry -> {
|
||||
// filter out placeholder entries
|
||||
if (entry.path().equals(DIRECT_METHOD_HANDLE_ENTRY) ||
|
||||
entry.path().equals(DELEGATING_METHOD_HANDLE_ENTRY)) {
|
||||
entry.path().equals(DELEGATING_METHOD_HANDLE_ENTRY) ||
|
||||
entry.path().equals(BASIC_FORMS_HANDLE_ENTRY)) {
|
||||
return null;
|
||||
} else {
|
||||
return entry;
|
||||
}
|
||||
}, out);
|
||||
speciesTypes.forEach(types -> generateBMHClass(types, out));
|
||||
generateDMHClass(out);
|
||||
generateHolderClasses(out);
|
||||
return out.build();
|
||||
}
|
||||
|
||||
@ -257,7 +260,7 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDMHClass(ResourcePoolBuilder out) {
|
||||
private void generateHolderClasses(ResourcePoolBuilder out) {
|
||||
int count = 0;
|
||||
for (List<String> entry : dmhMethods.values()) {
|
||||
count += entry.size();
|
||||
@ -284,6 +287,10 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
DELEGATING_METHOD_HANDLE, methodTypes);
|
||||
ndata = ResourcePoolEntry.create(DELEGATING_METHOD_HANDLE_ENTRY, bytes);
|
||||
out.add(ndata);
|
||||
|
||||
bytes = JLIA.generateBasicFormsClassBytes(BASIC_FORMS_HANDLE);
|
||||
ndata = ResourcePoolEntry.create(BASIC_FORMS_HANDLE_ENTRY, bytes);
|
||||
out.add(ndata);
|
||||
} catch (Exception ex) {
|
||||
throw new PluginException(ex);
|
||||
}
|
||||
@ -292,6 +299,8 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
"/java.base/" + DIRECT_METHOD_HANDLE + ".class";
|
||||
private static final String DELEGATING_METHOD_HANDLE_ENTRY =
|
||||
"/java.base/" + DELEGATING_METHOD_HANDLE + ".class";
|
||||
private static final String BASIC_FORMS_HANDLE_ENTRY =
|
||||
"/java.base/" + BASIC_FORMS_HANDLE + ".class";
|
||||
|
||||
// Convert LL -> LL, L3 -> LLL
|
||||
private static String expandSignature(String signature) {
|
||||
|
Loading…
Reference in New Issue
Block a user