# HG changeset patch # User redestad # Date 1472472418 -7200 # Mon Aug 29 14:06:58 2016 +0200 # Node ID f1b1268bd622cb3283f2633ad2d7a2fdadb6367d # Parent f65a2005b5d770bd93283d0cfe80aa8d772035cc 8164858: Enable build-time use of java.lang.invoke resolve tracing Reviewed-by: erikj diff --git a/make/GenerateClasslist.gmk b/make/GenerateClasslist.gmk --- a/make/GenerateClasslist.gmk +++ b/make/GenerateClasslist.gmk @@ -50,6 +50,8 @@ 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 @@ $(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 \ + $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@ \ + -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \ -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 + build.tools.classlist.HelloClasslist \ + $(LOG_DEBUG) 2>&1 > $(JLI_TRACE_FILE) TARGETS += $(CLASSLIST_FILE) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java @@ -29,12 +29,12 @@ 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 @@ private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess(); - List speciesTypes; + Set speciesTypes; - List invokerTypes; + Set invokerTypes; - Map> dmhMethods; + Map> dmhMethods; public GenerateJLIClassesPlugin() { } @@ -110,8 +110,8 @@ * 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 defaultSpecies() { - return List.of("LL", "L3", "L4", "L5", "L6", "L7", "L7I", + public static Set 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 @@ /** * @return the default invoker forms to generate. */ - private static List defaultInvokers() { - return List.of("LL_L", "LL_I", "LILL_I", "L6_L"); + private static Set defaultInvokers() { + return Set.of("LL_L", "LL_I", "LILL_I", "L6_L"); } /** * @return the list of default DirectMethodHandle methods to generate. */ - private static Map> defaultDMHMethods() { + private static Map> 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 void configure(Map 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 defaultBMHSpecies = defaultSpecies(); + // Expand BMH species signatures + defaultBMHSpecies = defaultBMHSpecies.stream() + .map(type -> expandSignature(type)) + .collect(Collectors.toSet()); + + Set defaultInvokerTypes = defaultInvokers(); + validateMethodTypes(defaultInvokerTypes); + + Map> defaultDmhMethods = defaultDMHMethods(); + for (Set 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 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> 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 @@ } }); } - } else { - List bmhSpecies = defaultSpecies(); - // Expand BMH species signatures - speciesTypes = bmhSpecies.stream() - .map(type -> expandSignature(type)) - .collect(Collectors.toList()); - - invokerTypes = defaultInvokers(); - validateMethodTypes(invokerTypes); - - dmhMethods = defaultDMHMethods(); - for (List dmhMethodTypes : dmhMethods.values()) { - validateMethodTypes(dmhMethodTypes); - } } } private void addDMHMethodType(String dmh, String methodType) { validateMethodType(methodType); - List methodTypes = dmhMethods.get(dmh); + Set methodTypes = dmhMethods.get(dmh); if (methodTypes == null) { - methodTypes = new ArrayList<>(); + methodTypes = new TreeSet<>(); dmhMethods.put(dmh, methodTypes); } methodTypes.add(methodType); @@ -226,7 +245,7 @@ } } - private void validateMethodTypes(List dmhMethodTypes) { + private void validateMethodTypes(Set dmhMethodTypes) { for (String type : dmhMethodTypes) { validateMethodType(type); } @@ -291,13 +310,13 @@ private void generateHolderClasses(ResourcePoolBuilder out) { int count = 0; - for (List entry : dmhMethods.values()) { + for (Set entry : dmhMethods.values()) { count += entry.size(); } MethodType[] directMethodTypes = new MethodType[count]; int[] dmhTypes = new int[count]; int index = 0; - for (Map.Entry> entry : dmhMethods.entrySet()) { + for (Map.Entry> 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 @@ } } 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 @@ } mt = mt.dropParameterTypes(lastParam, lastParam + 1); invokerMethodTypes[i] = mt.dropParameterTypes(0, 1); + i++; } try { byte[] bytes = JLIA.generateDirectMethodHandleHolderClassBytes( diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -68,12 +68,12 @@ exclude-resources.description=\ Specify resources to exclude. e.g.: **.jcov,glob:**/META-INF/** -generate-jli-classes.argument=<@filename> +generate-jli-classes.argument= 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)