mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-15 04:45:25 +00:00
8163371: Enable tracing which JLI classes can be pre-generated
Reviewed-by: vlivanov
This commit is contained in:
parent
f78a742b53
commit
1a404080ee
@ -497,6 +497,10 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
String shortTypes = LambdaForm.shortenSignature(types);
|
||||
String className = SPECIES_CLASS_PREFIX + shortTypes;
|
||||
Class<?> c = BootLoader.loadClassOrNull(className);
|
||||
if (TRACE_RESOLVE) {
|
||||
System.out.println("[BMH_RESOLVE] " + shortTypes +
|
||||
(c != null ? " (success)" : " (fail)") );
|
||||
}
|
||||
if (c != null) {
|
||||
return c.asSubclass(BoundMethodHandle.class);
|
||||
} else {
|
||||
|
||||
@ -607,7 +607,10 @@ class InvokerBytecodeGenerator {
|
||||
private static MemberName resolveFrom(String name, MethodType type, Class<?> holder) {
|
||||
MemberName member = new MemberName(holder, name, type, REF_invokeStatic);
|
||||
MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, holder);
|
||||
|
||||
if (TRACE_RESOLVE) {
|
||||
System.out.println("[LF_RESOLVE] " + holder.getName() + " " + name + " " +
|
||||
shortenSignature(basicTypeSignature(type)) + (resolvedMember != null ? " (success)" : " (fail)") );
|
||||
}
|
||||
return resolvedMember;
|
||||
}
|
||||
|
||||
|
||||
@ -46,6 +46,7 @@ import java.util.Properties;
|
||||
static final boolean DUMP_CLASS_FILES;
|
||||
static final boolean TRACE_INTERPRETER;
|
||||
static final boolean TRACE_METHOD_LINKAGE;
|
||||
static final boolean TRACE_RESOLVE;
|
||||
static final int COMPILE_THRESHOLD;
|
||||
static final boolean LOG_LF_COMPILATION_FAILURE;
|
||||
static final int DONT_INLINE_THRESHOLD;
|
||||
@ -65,6 +66,8 @@ import java.util.Properties;
|
||||
props.getProperty("java.lang.invoke.MethodHandle.TRACE_INTERPRETER"));
|
||||
TRACE_METHOD_LINKAGE = Boolean.parseBoolean(
|
||||
props.getProperty("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE"));
|
||||
TRACE_RESOLVE = Boolean.parseBoolean(
|
||||
props.getProperty("java.lang.invoke.MethodHandle.TRACE_RESOLVE"));
|
||||
COMPILE_THRESHOLD = Integer.parseInt(
|
||||
props.getProperty("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", "0"));
|
||||
LOG_LF_COMPILATION_FAILURE = Boolean.parseBoolean(
|
||||
|
||||
@ -24,7 +24,11 @@
|
||||
*/
|
||||
package jdk.tools.jlink.internal.plugins;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
@ -32,6 +36,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.JavaLangInvokeAccess;
|
||||
import jdk.tools.jlink.plugin.ResourcePoolEntry;
|
||||
@ -47,12 +52,8 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
|
||||
private static final String NAME = "generate-jli-classes";
|
||||
|
||||
private static final String BMH_PARAM = "bmh";
|
||||
private static final String BMH_SPECIES_PARAM = "bmh-species";
|
||||
|
||||
private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
|
||||
|
||||
private static final String DMH_PARAM = "dmh";
|
||||
private static final String DIRECT_HOLDER = "java/lang/invoke/DirectMethodHandle$Holder";
|
||||
private static final String DMH_INVOKE_VIRTUAL = "invokeVirtual";
|
||||
private static final String DMH_INVOKE_STATIC = "invokeStatic";
|
||||
@ -61,8 +62,6 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
private static final String DMH_INVOKE_INTERFACE = "invokeInterface";
|
||||
private static final String DMH_INVOKE_STATIC_INIT = "invokeStaticInit";
|
||||
|
||||
private static final String INVOKERS_PARAM = "invokers";
|
||||
|
||||
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";
|
||||
@ -76,7 +75,6 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
|
||||
Map<String, List<String>> dmhMethods;
|
||||
|
||||
|
||||
public GenerateJLIClassesPlugin() {
|
||||
}
|
||||
|
||||
@ -112,7 +110,7 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
* A better long-term solution is to define and run a set of quick
|
||||
* generators and extracting this list as a step in the build process.
|
||||
*/
|
||||
public static List<String> defaultSpecies() {
|
||||
private static List<String> defaultSpecies() {
|
||||
return List.of("LL", "L3", "L4", "L5", "L6", "L7", "L7I",
|
||||
"L7II", "L7IIL", "L8", "L9", "L10", "L10I", "L10II", "L10IIL",
|
||||
"L11", "L12", "L13", "LI", "D", "L3I", "LIL", "LLI", "LLIL",
|
||||
@ -122,26 +120,27 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
/**
|
||||
* @return the default invoker forms to generate.
|
||||
*/
|
||||
public static List<String> defaultInvokers() {
|
||||
return List.of("_L", "_I", "I_I", "LI_I", "ILL_I", "LIL_I", "L_L", "LL_V", "LLLL_L");
|
||||
private static List<String> defaultInvokers() {
|
||||
return List.of("LL_L", "LL_I", "LILL_I", "L6_L");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of default DirectMethodHandle methods to generate.
|
||||
*/
|
||||
public static Map<String, List<String>> defaultDMHMethods() {
|
||||
private static Map<String, List<String>> defaultDMHMethods() {
|
||||
return Map.of(
|
||||
DMH_INVOKE_VIRTUAL, List.of("_L", "L_L", "LI_I", "LL_V"),
|
||||
DMH_INVOKE_SPECIAL, List.of("L_I", "L_L", "LF_L", "LD_L", "LL_L",
|
||||
"L3_L", "L4_L", "L5_L", "L6_L", "L7_L", "LI_I", "LI_L", "LIL_I",
|
||||
"LII_I", "LII_L", "LLI_L", "LLI_I", "LILI_I", "LIIL_L",
|
||||
"LIILL_L", "LIILL_I", "LIIL_I", "LILIL_I", "LILILL_I",
|
||||
"LILII_I", "LI3_I", "LI3L_I", "LI3LL_I", "LI3_L", "LI4_I"),
|
||||
DMH_INVOKE_STATIC, List.of("II_I", "IL_I", "ILIL_I", "ILII_I",
|
||||
"_I", "_L", "_V", "D_L", "F_L", "I_I", "II_L", "LI_L",
|
||||
"L_V", "L_L", "LL_L", "L3_L", "L4_L", "L5_L", "L6_L",
|
||||
"L7_L", "L8_L", "L9_L", "L9I_L", "L9II_L", "L9IIL_L",
|
||||
"L10_L", "L11_L", "L12_L", "L13_L", "L13I_L", "L13II_L")
|
||||
DMH_INVOKE_VIRTUAL, List.of("L_L", "LL_L", "LLI_I", "L3_V"),
|
||||
DMH_INVOKE_SPECIAL, List.of("LL_I", "LL_L", "LLF_L", "LLD_L", "L3_L",
|
||||
"L4_L", "L5_L", "L6_L", "L7_L", "L8_L", "LLI_I", "LLI_L",
|
||||
"LLIL_I", "LLII_I", "LLII_L", "L3I_L", "L3I_I", "LLILI_I",
|
||||
"LLIIL_L", "LLIILL_L", "LLIILL_I", "LLIIL_I", "LLILIL_I",
|
||||
"LLILILL_I", "LLILII_I", "LLI3_I", "LLI3L_I", "LLI3LL_I",
|
||||
"LLI3_L", "LLI4_I"),
|
||||
DMH_INVOKE_STATIC, List.of("LII_I", "LIL_I", "LILIL_I", "LILII_I",
|
||||
"L_I", "L_L", "L_V", "LD_L", "LF_L", "LI_I", "LII_L", "LLI_L",
|
||||
"LL_V", "LL_L", "L3_L", "L4_L", "L5_L", "L6_L", "L7_L",
|
||||
"L8_L", "L9_L", "L10_L", "L10I_L", "L10II_L", "L10IIL_L",
|
||||
"L11_L", "L12_L", "L13_L", "L14_L", "L14I_L", "L14II_L")
|
||||
);
|
||||
}
|
||||
|
||||
@ -160,92 +159,89 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
public void configure(Map<String, String> config) {
|
||||
String mainArgument = config.get(NAME);
|
||||
|
||||
// Enable by default
|
||||
boolean bmhEnabled = true;
|
||||
boolean dmhEnabled = true;
|
||||
boolean invokersEnabled = true;
|
||||
if (mainArgument != null) {
|
||||
List<String> args = Arrays.asList(mainArgument.split(","));
|
||||
if (!args.contains(BMH_PARAM)) {
|
||||
bmhEnabled = false;
|
||||
}
|
||||
if (!args.contains(DMH_PARAM)) {
|
||||
dmhEnabled = false;
|
||||
}
|
||||
if (!args.contains(INVOKERS_PARAM)) {
|
||||
dmhEnabled = false;
|
||||
}
|
||||
}
|
||||
if (mainArgument != null && mainArgument.startsWith("@")) {
|
||||
File file = new File(mainArgument.substring(1));
|
||||
if (file.exists()) {
|
||||
speciesTypes = new ArrayList<>();
|
||||
invokerTypes = new ArrayList<>();
|
||||
dmhMethods = new HashMap<>();
|
||||
Stream<String> lines = fileLines(file);
|
||||
|
||||
if (!bmhEnabled) {
|
||||
speciesTypes = List.of();
|
||||
lines.map(line -> line.split(" "))
|
||||
.forEach(parts -> {
|
||||
switch (parts[0]) {
|
||||
case "[BMH_RESOLVE]":
|
||||
speciesTypes.add(expandSignature(parts[1]));
|
||||
break;
|
||||
case "[LF_RESOLVE]":
|
||||
String methodType = parts[3];
|
||||
validateMethodType(methodType);
|
||||
if (parts[1].contains("Invokers")) {
|
||||
invokerTypes.add(methodType);
|
||||
} else if (parts[1].contains("DirectMethodHandle")) {
|
||||
String dmh = parts[2];
|
||||
// ignore getObject etc for now (generated
|
||||
// by default)
|
||||
if (DMH_METHOD_TYPE_MAP.containsKey(dmh)) {
|
||||
addDMHMethodType(dmh, methodType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break; // ignore
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
String args = config.get(BMH_SPECIES_PARAM);
|
||||
List<String> bmhSpecies;
|
||||
if (args != null && !args.isEmpty()) {
|
||||
bmhSpecies = Arrays.stream(args.split(","))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
bmhSpecies = defaultSpecies();
|
||||
}
|
||||
|
||||
List<String> bmhSpecies = defaultSpecies();
|
||||
// Expand BMH species signatures
|
||||
speciesTypes = bmhSpecies.stream()
|
||||
.map(type -> expandSignature(type))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
if (!invokersEnabled) {
|
||||
invokerTypes = List.of();
|
||||
} else {
|
||||
String args = config.get(INVOKERS_PARAM);
|
||||
if (args != null && !args.isEmpty()) {
|
||||
invokerTypes = Arrays.stream(args.split(","))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
validateMethodTypes(invokerTypes);
|
||||
} else {
|
||||
invokerTypes = defaultInvokers();
|
||||
}
|
||||
invokerTypes = defaultInvokers();
|
||||
validateMethodTypes(invokerTypes);
|
||||
|
||||
}
|
||||
// DirectMethodHandles
|
||||
if (!dmhEnabled) {
|
||||
dmhMethods = Map.of();
|
||||
} else {
|
||||
dmhMethods = new HashMap<>();
|
||||
for (String dmhParam : DMH_METHOD_TYPE_MAP.keySet()) {
|
||||
String args = config.get(dmhParam);
|
||||
if (args != null && !args.isEmpty()) {
|
||||
List<String> dmhMethodTypes = Arrays.stream(args.split(","))
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
dmhMethods.put(dmhParam, dmhMethodTypes);
|
||||
validateMethodTypes(dmhMethodTypes);
|
||||
}
|
||||
}
|
||||
if (dmhMethods.isEmpty()) {
|
||||
dmhMethods = defaultDMHMethods();
|
||||
dmhMethods = defaultDMHMethods();
|
||||
for (List<String> dmhMethodTypes : dmhMethods.values()) {
|
||||
validateMethodTypes(dmhMethodTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void validateMethodTypes(List<String> dmhMethodTypes) {
|
||||
for (String type : dmhMethodTypes) {
|
||||
String[] typeParts = type.split("_");
|
||||
// check return type (second part)
|
||||
if (typeParts.length != 2 || typeParts[1].length() != 1
|
||||
|| "LJIFDV".indexOf(typeParts[1].charAt(0)) == -1) {
|
||||
throw new PluginException(
|
||||
"Method type signature must be of form [LJIFD]*_[LJIFDV]");
|
||||
}
|
||||
// expand and check arguments (first part)
|
||||
expandSignature(typeParts[0]);
|
||||
private void addDMHMethodType(String dmh, String methodType) {
|
||||
validateMethodType(methodType);
|
||||
List<String> methodTypes = dmhMethods.get(dmh);
|
||||
if (methodTypes == null) {
|
||||
methodTypes = new ArrayList<>();
|
||||
dmhMethods.put(dmh, methodTypes);
|
||||
}
|
||||
methodTypes.add(methodType);
|
||||
}
|
||||
|
||||
private Stream<String> fileLines(File file) {
|
||||
try {
|
||||
return Files.lines(file.toPath());
|
||||
} catch (IOException io) {
|
||||
throw new PluginException("Couldn't read file");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMethodTypes(List<String> dmhMethodTypes) {
|
||||
for (String type : dmhMethodTypes) {
|
||||
validateMethodType(type);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateMethodType(String type) {
|
||||
String[] typeParts = type.split("_");
|
||||
// check return type (second part)
|
||||
if (typeParts.length != 2 || typeParts[1].length() != 1
|
||||
|| "LJIFDV".indexOf(typeParts[1].charAt(0)) == -1) {
|
||||
throw new PluginException(
|
||||
"Method type signature must be of form [LJIFD]*_[LJIFDV]");
|
||||
}
|
||||
// expand and check arguments (first part)
|
||||
expandSignature(typeParts[0]);
|
||||
}
|
||||
|
||||
private static void requireBasicType(char c) {
|
||||
@ -304,14 +300,33 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
||||
for (Map.Entry<String, List<String>> entry : dmhMethods.entrySet()) {
|
||||
String dmhType = entry.getKey();
|
||||
for (String type : entry.getValue()) {
|
||||
directMethodTypes[index] = asMethodType(type);
|
||||
// The DMH type to actually ask for is retrieved by removing
|
||||
// the first argument, which needs to be of Object.class
|
||||
MethodType mt = asMethodType(type);
|
||||
if (mt.parameterCount() < 1 ||
|
||||
mt.parameterType(0) != Object.class) {
|
||||
throw new PluginException(
|
||||
"DMH type parameter must start with L");
|
||||
}
|
||||
directMethodTypes[index] = mt.dropParameterTypes(0, 1);
|
||||
dmhTypes[index] = DMH_METHOD_TYPE_MAP.get(dmhType);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
MethodType[] invokerMethodTypes = new MethodType[this.invokerTypes.size()];
|
||||
for (int i = 0; i < invokerTypes.size(); i++) {
|
||||
invokerMethodTypes[i] = asMethodType(invokerTypes.get(i));
|
||||
// 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(invokerTypes.get(i));
|
||||
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");
|
||||
}
|
||||
mt = mt.dropParameterTypes(lastParam, lastParam + 1);
|
||||
invokerMethodTypes[i] = mt.dropParameterTypes(0, 1);
|
||||
}
|
||||
try {
|
||||
byte[] bytes = JLIA.generateDirectMethodHandleHolderClassBytes(
|
||||
|
||||
@ -68,10 +68,12 @@ exclude-resources.argument=<pattern-list> resources to exclude
|
||||
exclude-resources.description=\
|
||||
Specify resources to exclude. e.g.: **.jcov,glob:**/META-INF/**
|
||||
|
||||
generate-jli-classes.argument=<bmh[:bmh-species=LL,L3,...]>
|
||||
generate-jli-classes.argument=<@filename>
|
||||
|
||||
generate-jli-classes.description=\
|
||||
Concrete java.lang.invoke classes to generate
|
||||
Takes a file hinting to jlink what java.lang.invoke classes to pre-generate. If\n\
|
||||
this flag is not specified a default set of classes will be generated, so to \n\
|
||||
disable pre-generation supply the name of an empty or non-existing file
|
||||
|
||||
installed-modules.description=Fast loading of module descriptors (always enabled)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user