8199471: Enable generation of callSiteForms at link time

Reviewed-by: psandoz, mchung
This commit is contained in:
Claes Redestad 2018-03-14 17:14:02 +01:00
parent 562b3c4393
commit b66ffad152
6 changed files with 77 additions and 24 deletions

View File

@ -133,7 +133,7 @@ class GenerateJLIClassesHelper {
}
static byte[] generateInvokersHolderClassBytes(String className,
MethodType[] methodTypes) {
MethodType[] invokerMethodTypes, MethodType[] callSiteMethodTypes) {
HashSet<MethodType> dedupSet = new HashSet<>();
ArrayList<LambdaForm> forms = new ArrayList<>();
@ -144,17 +144,33 @@ class GenerateJLIClassesHelper {
MethodTypeForm.LF_GEN_LINKER,
MethodTypeForm.LF_GEN_INVOKER
};
for (int i = 0; i < methodTypes.length; i++) {
for (int i = 0; i < invokerMethodTypes.length; i++) {
// generate methods representing invokers of the specified type
if (dedupSet.add(methodTypes[i])) {
if (dedupSet.add(invokerMethodTypes[i])) {
for (int type : types) {
LambdaForm invokerForm = Invokers.invokeHandleForm(methodTypes[i],
LambdaForm invokerForm = Invokers.invokeHandleForm(invokerMethodTypes[i],
/*customized*/false, type);
forms.add(invokerForm);
names.add(invokerForm.kind.defaultLambdaName);
}
}
}
dedupSet = new HashSet<>();
for (int i = 0; i < callSiteMethodTypes.length; i++) {
// generate methods representing invokers of the specified type
if (dedupSet.add(callSiteMethodTypes[i])) {
LambdaForm callSiteForm = Invokers.callSiteForm(callSiteMethodTypes[i], true);
forms.add(callSiteForm);
names.add(callSiteForm.kind.defaultLambdaName);
LambdaForm methodHandleForm = Invokers.callSiteForm(callSiteMethodTypes[i], false);
forms.add(methodHandleForm);
names.add(methodHandleForm.kind.defaultLambdaName);
}
}
return generateCodeBytesForLFs(className,
names.toArray(new String[0]),
forms.toArray(new LambdaForm[0]));

View File

@ -649,6 +649,8 @@ class InvokerBytecodeGenerator {
}
case EXACT_INVOKER: // fall-through
case EXACT_LINKER: // fall-through
case LINK_TO_CALL_SITE: // fall-through
case LINK_TO_TARGET_METHOD: // fall-through
case GENERIC_INVOKER: // fall-through
case GENERIC_LINKER: return resolveFrom(name, invokerType.basicType(), Invokers.Holder.class);
case GET_OBJECT: // fall-through

View File

@ -523,7 +523,7 @@ class Invokers {
}
// skipCallSite is true if we are optimizing a ConstantCallSite
private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) {
mtype = mtype.basicType(); // normalize Z to I, String to Object, etc.
final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER);
LambdaForm lform = mtype.form().cachedLambdaForm(which);

View File

@ -1841,10 +1841,13 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
@Override
public byte[] generateInvokersHolderClassBytes(final String className,
MethodType[] methodTypes) {
MethodType[] invokerMethodTypes,
MethodType[] callSiteMethodTypes) {
return GenerateJLIClassesHelper
.generateInvokersHolderClassBytes(className, methodTypes);
.generateInvokersHolderClassBytes(className,
invokerMethodTypes, callSiteMethodTypes);
}
});
}

View File

@ -84,7 +84,7 @@ public interface JavaLangInvokeAccess {
/**
* Returns a {@code byte[]} representation of {@code BoundMethodHandle}
* species class implementing the signature defined by {@code types}. Used
* by GenerateBMHClassesPlugin to enable generation of such classes during
* by GenerateJLIClassesPlugin to enable generation of such classes during
* the jlink phase. Should do some added validation since this string may be
* user provided.
*/
@ -99,8 +99,11 @@ public interface JavaLangInvokeAccess {
/**
* Returns a {@code byte[]} representation of a class implementing
* the invoker forms for the set of supplied {@code methodTypes}.
* the invoker forms for the set of supplied {@code invokerMethodTypes}
* and {@code callSiteMethodTypes}.
*/
byte[] generateInvokersHolderClassBytes(String className,
MethodType[] methodTypes);
MethodType[] invokerMethodTypes,
MethodType[] callSiteMethodTypes);
}

View File

@ -69,7 +69,9 @@ public final class GenerateJLIClassesPlugin implements Plugin {
private static final String DELEGATING_HOLDER = "java/lang/invoke/DelegatingMethodHandle$Holder";
private static final String BASIC_FORMS_HOLDER = "java/lang/invoke/LambdaForm$Holder";
private static final String INVOKERS_HOLDER = "java/lang/invoke/Invokers$Holder";
private static final String INVOKERS_HOLDER_NAME = "java.lang.invoke.Invokers$Holder";
private static final String INVOKERS_HOLDER_INTERNAL_NAME = INVOKERS_HOLDER_NAME.replace('.', '/');
private static final JavaLangInvokeAccess JLIA
= SharedSecrets.getJavaLangInvokeAccess();
@ -78,6 +80,8 @@ public final class GenerateJLIClassesPlugin implements Plugin {
Set<String> invokerTypes = Set.of();
Set<String> callSiteTypes = Set.of();
Map<String, Set<String>> dmhMethods = Map.of();
String mainArgument;
@ -128,7 +132,7 @@ public final class GenerateJLIClassesPlugin implements Plugin {
* @return the default invoker forms to generate.
*/
private static Set<String> defaultInvokers() {
return Set.of("LL_L", "LL_I", "LILL_I", "L6_L");
return Set.of("LL_L", "LL_I", "LLLL_L", "LLLL_I", "LLIL_L", "LLIL_I", "L6_L");
}
/**
@ -209,6 +213,8 @@ public final class GenerateJLIClassesPlugin implements Plugin {
// ease finding methods in the generated code
speciesTypes = new TreeSet<>(speciesTypes);
invokerTypes = new TreeSet<>(invokerTypes);
callSiteTypes = new TreeSet<>(callSiteTypes);
TreeMap<String, Set<String>> newDMHMethods = new TreeMap<>();
for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
newDMHMethods.put(entry.getKey(), new TreeSet<>(entry.getValue()));
@ -229,8 +235,13 @@ public final class GenerateJLIClassesPlugin implements Plugin {
case "[LF_RESOLVE]":
String methodType = parts[3];
validateMethodType(methodType);
if (parts[1].contains("Invokers")) {
invokerTypes.add(methodType);
if (parts[1].equals(INVOKERS_HOLDER_NAME)) {
if ("linkToTargetMethod".equals(parts[2]) ||
"linkToCallSite".equals(parts[2])) {
callSiteTypes.add(methodType);
} else {
invokerTypes.add(methodType);
}
} else if (parts[1].contains("DirectMethodHandle")) {
String dmh = parts[2];
// ignore getObject etc for now (generated
@ -294,10 +305,11 @@ public final class GenerateJLIClassesPlugin implements Plugin {
// Copy all but DMH_ENTRY to out
in.transformAndCopy(entry -> {
// filter out placeholder entries
if (entry.path().equals(DIRECT_METHOD_HOLDER_ENTRY) ||
entry.path().equals(DELEGATING_METHOD_HOLDER_ENTRY) ||
entry.path().equals(INVOKERS_HOLDER_ENTRY) ||
entry.path().equals(BASIC_FORMS_HOLDER_ENTRY)) {
String path = entry.path();
if (path.equals(DIRECT_METHOD_HOLDER_ENTRY) ||
path.equals(DELEGATING_METHOD_HOLDER_ENTRY) ||
path.equals(INVOKERS_HOLDER_ENTRY) ||
path.equals(BASIC_FORMS_HOLDER_ENTRY)) {
return null;
} else {
return entry;
@ -361,23 +373,40 @@ public final class GenerateJLIClassesPlugin implements Plugin {
index++;
}
}
// The invoker type to ask for is retrieved by removing the first
// and the last argument, which needs to be of Object.class
MethodType[] invokerMethodTypes = new MethodType[this.invokerTypes.size()];
int i = 0;
for (String invokerType : invokerTypes) {
// The invoker type to ask for is retrieved by removing the first
// and the last argument, which needs to be of Object.class
MethodType mt = asMethodType(invokerType);
final int lastParam = mt.parameterCount() - 1;
if (mt.parameterCount() < 2 ||
mt.parameterType(0) != Object.class ||
mt.parameterType(lastParam) != Object.class) {
throw new PluginException(
"Invoker type parameter must start and end with L");
"Invoker type parameter must start and end with Object: " + invokerType);
}
mt = mt.dropParameterTypes(lastParam, lastParam + 1);
invokerMethodTypes[i] = mt.dropParameterTypes(0, 1);
i++;
}
// The callSite type to ask for is retrieved by removing the last
// argument, which needs to be of Object.class
MethodType[] callSiteMethodTypes = new MethodType[this.callSiteTypes.size()];
i = 0;
for (String callSiteType : callSiteTypes) {
MethodType mt = asMethodType(callSiteType);
final int lastParam = mt.parameterCount() - 1;
if (mt.parameterCount() < 1 ||
mt.parameterType(lastParam) != Object.class) {
throw new PluginException(
"CallSite type parameter must end with Object: " + callSiteType);
}
callSiteMethodTypes[i] = mt.dropParameterTypes(lastParam, lastParam + 1);
i++;
}
try {
byte[] bytes = JLIA.generateDirectMethodHandleHolderClassBytes(
DIRECT_HOLDER, directMethodTypes, dmhTypes);
@ -390,8 +419,8 @@ public final class GenerateJLIClassesPlugin implements Plugin {
ndata = ResourcePoolEntry.create(DELEGATING_METHOD_HOLDER_ENTRY, bytes);
out.add(ndata);
bytes = JLIA.generateInvokersHolderClassBytes(INVOKERS_HOLDER,
invokerMethodTypes);
bytes = JLIA.generateInvokersHolderClassBytes(INVOKERS_HOLDER_INTERNAL_NAME,
invokerMethodTypes, callSiteMethodTypes);
ndata = ResourcePoolEntry.create(INVOKERS_HOLDER_ENTRY, bytes);
out.add(ndata);
@ -409,7 +438,7 @@ public final class GenerateJLIClassesPlugin implements Plugin {
private static final String BASIC_FORMS_HOLDER_ENTRY =
"/java.base/" + BASIC_FORMS_HOLDER + ".class";
private static final String INVOKERS_HOLDER_ENTRY =
"/java.base/" + INVOKERS_HOLDER + ".class";
"/java.base/" + INVOKERS_HOLDER_INTERNAL_NAME + ".class";
// Convert LL -> LL, L3 -> LLL
public static String expandSignature(String signature) {