8164451: Generate all zero and identity forms at link time

Reviewed-by: shade, mhaupt, vlivanov
This commit is contained in:
Claes Redestad 2016-08-19 13:50:03 +02:00
parent 22e95f995a
commit 4316d705f2
6 changed files with 71 additions and 6 deletions

View File

@ -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];

View File

@ -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

View File

@ -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

View File

@ -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);
}
});
}

View File

@ -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);
}

View File

@ -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) {