8199471: Enable generation of callSiteForms at link time
Reviewed-by: psandoz, mchung
This commit is contained in:
parent
562b3c4393
commit
b66ffad152
@ -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]));
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user