8164858: Enable build-time use of java.lang.invoke resolve tracing

Reviewed-by: erikj, vlivanov
This commit is contained in:
Claes Redestad 2016-08-31 14:20:02 +02:00
parent 3f2262b347
commit 5afec5d3d6
4 changed files with 73 additions and 51 deletions

View File

@ -50,6 +50,8 @@ TARGETS += $(CLASSLIST_JAR)
CLASSLIST_FILE := $(SUPPORT_OUTPUTDIR)/classlist/classlist
JLI_TRACE_FILE := $(SUPPORT_OUTPUTDIR)/classlist/jli_trace.out
# If an external buildjdk has been supplied, we don't build a separate interim
# image, so just use the external build jdk instead.
ifeq ($(EXTERNAL_BUILDJDK), true)
@ -59,13 +61,11 @@ endif
$(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR)
$(call MakeDir, $(@D))
$(call LogInfo, Generating lib/classlist)
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.tmp \
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
build.tools.classlist.HelloClasslist $(LOG_DEBUG) 2>&1
# Filter out generated classes, remove after JDK-8149977
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@ \
-Xshare:dump -XX:SharedClassListFile=$@.tmp $(LOG_DEBUG) 2>&1
$(RM) $@.tmp
-Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
build.tools.classlist.HelloClasslist \
$(LOG_DEBUG) 2>&1 > $(JLI_TRACE_FILE)
TARGETS += $(CLASSLIST_FILE)

View File

@ -29,12 +29,12 @@ 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;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.misc.SharedSecrets;
@ -69,11 +69,11 @@ public final class GenerateJLIClassesPlugin implements Plugin {
private static final JavaLangInvokeAccess JLIA
= SharedSecrets.getJavaLangInvokeAccess();
List<String> speciesTypes;
Set<String> speciesTypes;
List<String> invokerTypes;
Set<String> invokerTypes;
Map<String, List<String>> dmhMethods;
Map<String, Set<String>> dmhMethods;
public GenerateJLIClassesPlugin() {
}
@ -110,8 +110,8 @@ 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() {
return List.of("LL", "L3", "L4", "L5", "L6", "L7", "L7I",
public static Set<String> defaultSpecies() {
return Set.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",
"LILL", "I", "LLILL");
@ -120,23 +120,23 @@ public final class GenerateJLIClassesPlugin implements Plugin {
/**
* @return the default invoker forms to generate.
*/
private static List<String> defaultInvokers() {
return List.of("LL_L", "LL_I", "LILL_I", "L6_L");
private static Set<String> defaultInvokers() {
return Set.of("LL_L", "LL_I", "LILL_I", "L6_L");
}
/**
* @return the list of default DirectMethodHandle methods to generate.
*/
private static Map<String, List<String>> defaultDMHMethods() {
private static Map<String, Set<String>> defaultDMHMethods() {
return Map.of(
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",
DMH_INVOKE_VIRTUAL, Set.of("L_L", "LL_L", "LLI_I", "L3_V"),
DMH_INVOKE_SPECIAL, Set.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",
DMH_INVOKE_STATIC, Set.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",
@ -159,15 +159,48 @@ public final class GenerateJLIClassesPlugin implements Plugin {
public void configure(Map<String, String> config) {
String mainArgument = config.get(NAME);
if (mainArgument != null && mainArgument.startsWith("@")) {
if ("none".equals(mainArgument)) {
speciesTypes = Set.of();
invokerTypes = Set.of();
dmhMethods = Map.of();
return;
}
// Start with the default configuration
Set<String> defaultBMHSpecies = defaultSpecies();
// Expand BMH species signatures
defaultBMHSpecies = defaultBMHSpecies.stream()
.map(type -> expandSignature(type))
.collect(Collectors.toSet());
Set<String> defaultInvokerTypes = defaultInvokers();
validateMethodTypes(defaultInvokerTypes);
Map<String, Set<String>> defaultDmhMethods = defaultDMHMethods();
for (Set<String> dmhMethodTypes : defaultDmhMethods.values()) {
validateMethodTypes(dmhMethodTypes);
}
// Extend the default configuration with the contents in the supplied
// input file
if (mainArgument == null || !mainArgument.startsWith("@")) {
speciesTypes = defaultBMHSpecies;
invokerTypes = defaultInvokerTypes;
dmhMethods = defaultDmhMethods;
} else {
File file = new File(mainArgument.substring(1));
if (file.exists()) {
speciesTypes = new ArrayList<>();
invokerTypes = new ArrayList<>();
dmhMethods = new HashMap<>();
Stream<String> lines = fileLines(file);
lines.map(line -> line.split(" "))
// Use TreeSet/TreeMap to keep things sorted in a deterministic
// order to avoid scrambling the layout on small changes and to
// ease finding methods in the generated code
speciesTypes = new TreeSet<>(defaultBMHSpecies);
invokerTypes = new TreeSet<>(defaultInvokerTypes);
dmhMethods = new TreeMap<>();
for (Map.Entry<String, Set<String>> entry : defaultDmhMethods.entrySet()) {
dmhMethods.put(entry.getKey(), new TreeSet<>(entry.getValue()));
}
fileLines(file)
.map(line -> line.split(" "))
.forEach(parts -> {
switch (parts[0]) {
case "[BMH_RESOLVE]":
@ -191,28 +224,14 @@ public final class GenerateJLIClassesPlugin implements Plugin {
}
});
}
} else {
List<String> bmhSpecies = defaultSpecies();
// Expand BMH species signatures
speciesTypes = bmhSpecies.stream()
.map(type -> expandSignature(type))
.collect(Collectors.toList());
invokerTypes = defaultInvokers();
validateMethodTypes(invokerTypes);
dmhMethods = defaultDMHMethods();
for (List<String> dmhMethodTypes : dmhMethods.values()) {
validateMethodTypes(dmhMethodTypes);
}
}
}
private void addDMHMethodType(String dmh, String methodType) {
validateMethodType(methodType);
List<String> methodTypes = dmhMethods.get(dmh);
Set<String> methodTypes = dmhMethods.get(dmh);
if (methodTypes == null) {
methodTypes = new ArrayList<>();
methodTypes = new TreeSet<>();
dmhMethods.put(dmh, methodTypes);
}
methodTypes.add(methodType);
@ -226,7 +245,7 @@ public final class GenerateJLIClassesPlugin implements Plugin {
}
}
private void validateMethodTypes(List<String> dmhMethodTypes) {
private void validateMethodTypes(Set<String> dmhMethodTypes) {
for (String type : dmhMethodTypes) {
validateMethodType(type);
}
@ -291,13 +310,13 @@ public final class GenerateJLIClassesPlugin implements Plugin {
private void generateHolderClasses(ResourcePoolBuilder out) {
int count = 0;
for (List<String> entry : dmhMethods.values()) {
for (Set<String> entry : dmhMethods.values()) {
count += entry.size();
}
MethodType[] directMethodTypes = new MethodType[count];
int[] dmhTypes = new int[count];
int index = 0;
for (Map.Entry<String, List<String>> entry : dmhMethods.entrySet()) {
for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
String dmhType = entry.getKey();
for (String type : entry.getValue()) {
// The DMH type to actually ask for is retrieved by removing
@ -314,10 +333,11 @@ public final class GenerateJLIClassesPlugin implements Plugin {
}
}
MethodType[] invokerMethodTypes = new MethodType[this.invokerTypes.size()];
for (int i = 0; i < invokerTypes.size(); i++) {
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(invokerTypes.get(i));
MethodType mt = asMethodType(invokerType);
final int lastParam = mt.parameterCount() - 1;
if (mt.parameterCount() < 2 ||
mt.parameterType(0) != Object.class ||
@ -327,6 +347,7 @@ public final class GenerateJLIClassesPlugin implements Plugin {
}
mt = mt.dropParameterTypes(lastParam, lastParam + 1);
invokerMethodTypes[i] = mt.dropParameterTypes(0, 1);
i++;
}
try {
byte[] bytes = JLIA.generateDirectMethodHandleHolderClassBytes(

View File

@ -68,12 +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=<@filename>
generate-jli-classes.argument=<none|@filename>
generate-jli-classes.description=\
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
this flag is not specified a default set of classes will be generated. To \n\
disable pre-generation specify none as the argument
installed-modules.description=Fast loading of module descriptors (always enabled)

View File

@ -22,6 +22,7 @@
*/
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@ -75,7 +76,7 @@ public class GenerateJLIClassesPluginTest {
}
private static List<String> classFilesForSpecies(List<String> species) {
private static List<String> classFilesForSpecies(Collection<String> species) {
return species.stream()
.map(s -> "/java.base/java/lang/invoke/BoundMethodHandle$Species_" + s + ".class")
.collect(Collectors.toList());