8199471: Enable generation of callSiteForms at link time
Reviewed-by: psandoz, mchung
--- a/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Wed Mar 14 11:23:16 2018 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java Wed Mar 14 17:14:02 2018 +0100
@@ -133,7 +133,7 @@
}
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 @@
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]));
--- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Mar 14 11:23:16 2018 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Mar 14 17:14:02 2018 +0100
@@ -649,6 +649,8 @@
}
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
--- a/src/java.base/share/classes/java/lang/invoke/Invokers.java Wed Mar 14 11:23:16 2018 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java Wed Mar 14 17:14:02 2018 +0100
@@ -523,7 +523,7 @@
}
// 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);
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Mar 14 11:23:16 2018 +0100
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Mar 14 17:14:02 2018 +0100
@@ -1841,10 +1841,13 @@
@Override
public byte[] generateInvokersHolderClassBytes(final String className,
- MethodType[] methodTypes) {
+ MethodType[] invokerMethodTypes,
+ MethodType[] callSiteMethodTypes) {
return GenerateJLIClassesHelper
- .generateInvokersHolderClassBytes(className, methodTypes);
+ .generateInvokersHolderClassBytes(className,
+ invokerMethodTypes, callSiteMethodTypes);
}
+
});
}
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java Wed Mar 14 11:23:16 2018 +0100
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java Wed Mar 14 17:14:02 2018 +0100
@@ -84,7 +84,7 @@
/**
* 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 @@
/**
* 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);
+
}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Wed Mar 14 11:23:16 2018 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java Wed Mar 14 17:14:02 2018 +0100
@@ -69,7 +69,9 @@
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 @@
Set<String> invokerTypes = Set.of();
+ Set<String> callSiteTypes = Set.of();
+
Map<String, Set<String>> dmhMethods = Map.of();
String mainArgument;
@@ -128,7 +132,7 @@
* @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 @@
// 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 @@
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 @@
// 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 @@
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 @@
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 @@
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) {