From 0b5d48b9e6f347af9abd3aaf145ae93d512509ff Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 10 Feb 2020 12:39:19 +0100 Subject: [PATCH] 8230301: Re-examine hardcoded defaults in GenerateJLIClassesPlugin Reviewed-by: mchung --- make/GenerateLinkOptData.gmk | 1 + .../build/tools/classlist/HelloClasslist.java | 44 ++++++++-- .../plugins/GenerateJLIClassesPlugin.java | 83 ++++--------------- .../plugins/GenerateJLIClassesPluginTest.java | 22 +---- 4 files changed, 59 insertions(+), 91 deletions(-) diff --git a/make/GenerateLinkOptData.gmk b/make/GenerateLinkOptData.gmk index 9339218b5d1..87ad6c35754 100644 --- a/make/GenerateLinkOptData.gmk +++ b/make/GenerateLinkOptData.gmk @@ -75,6 +75,7 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR) $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw \ -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \ -Duser.language=en -Duser.country=US \ + --module-path $(SUPPORT_OUTPUTDIR)/classlist.jar \ -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \ build.tools.classlist.HelloClasslist \ 2> $(LINK_OPT_DIR)/stderr > $(JLI_TRACE_FILE) \ diff --git a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java index d2913e306a5..8e5dbe73d41 100644 --- a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java +++ b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java @@ -31,6 +31,9 @@ */ package build.tools.classlist; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.net.InetAddress; import java.nio.file.FileSystems; import java.time.LocalDateTime; @@ -55,19 +58,20 @@ public class HelloClasslist { private static final Logger LOGGER = Logger.getLogger("Hello"); - public static void main(String ... args) { + public static void main(String ... args) throws Throwable { FileSystems.getDefault(); List strings = Arrays.asList("Hello", "World!", "From: ", - InetAddress.getLoopbackAddress().toString()); + InetAddress.getLoopbackAddress().toString()); String helloWorld = strings.parallelStream() - .map(s -> s.toLowerCase(Locale.ROOT)) - .collect(joining(",")); + .map(s -> s.toLowerCase(Locale.ROOT)) + .collect(joining(",")); - Stream.of(helloWorld.split(",")) - .forEach(System.out::println); + Stream.of(helloWorld.split("([,x-z]{1,3})([\\s]*)")) + .map(String::toString) + .forEach(System.out::println); // Common concatenation patterns String SS = String.valueOf(args.length) + String.valueOf(args.length); @@ -83,6 +87,10 @@ public class HelloClasslist { String SCSCS = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length); String CI = "string" + args.length; String IC = args.length + "string"; + String SI = String.valueOf(args.length) + args.length; + String IS = args.length + String.valueOf(args.length); + String CIS = "string" + args.length + String.valueOf(args.length); + String CSCI = "string" + String.valueOf(args.length) + "string" + args.length; String CIC = "string" + args.length + "string"; String CICI = "string" + args.length + "string" + args.length; String CJ = "string" + System.currentTimeMillis(); @@ -99,7 +107,31 @@ public class HelloClasslist { DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.ROOT) .format(new Date())); + // A selection of trivial and relatively common MH operations + invoke(MethodHandles.identity(double.class), 1.0); + invoke(MethodHandles.identity(int.class), 1); + invoke(MethodHandles.identity(String.class), "x"); + + invoke(handle("staticMethod_V", MethodType.methodType(void.class))); + LOGGER.log(Level.FINE, "New Date: " + newDate + " - old: " + oldDate); } + public static void staticMethod_V() {} + + private static MethodHandle handle(String name, MethodType type) throws Throwable { + return MethodHandles.lookup().findStatic(HelloClasslist.class, name, type); + } + + private static Object invoke(MethodHandle mh, Object ... args) throws Throwable { + try { + for (Object o : args) { + mh = MethodHandles.insertArguments(mh, 0, o); + } + return mh.invoke(); + } catch (Throwable t) { + LOGGER.warning("Failed to find, link and/or invoke " + mh.toString() + ": " + t.getMessage()); + throw t; + } + } } 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 index b9d6011000b..2d01497da9d 100644 --- 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 @@ -47,6 +47,21 @@ import jdk.tools.jlink.plugin.Plugin; /** * Plugin to generate java.lang.invoke classes. + * + * The plugin reads in a file generated by running any application with + * {@code -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true}. This is done + * automatically during build, see make/GenerateLinkOptData.gmk. See + * build/tools/classlist/HelloClasslist.java for the training application. + * + * HelloClasslist tries to reflect common use of java.lang.invoke during early + * startup and warmup in various applications. To ensure a good default + * trade-off between static footprint and startup the application should be + * relatively conservative. + * + * When using jlink to build a custom application runtime, generating a trace + * file using {@code -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true} and + * feeding that into jlink using {@code --generate-jli-classes=@trace_file} can + * help improve startup time. */ public final class GenerateJLIClassesPlugin implements Plugin { @@ -112,59 +127,6 @@ public final class GenerateJLIClassesPlugin implements Plugin { return PluginsResourceBundle.getArgument(NAME); } - /** - * @return the default Species forms to generate. - * - * This list was derived from running a small startup benchmark. - * 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 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"); - } - - /** - * @return the default invoker forms to generate. - */ - private static Set defaultInvokers() { - return Set.of("LL_L", "LL_I", "LLLL_L", "LLLL_I", "LLIL_L", "LLIL_I", - "L6_L"); - } - - /** - * @return the default call site forms to generate (linkToTargetMethod). - */ - private static Set defaultCallSiteTypes() { - return Set.of("L5_L", "LIL3_L", "ILL_L"); - } - - /** - * @return the list of default DirectMethodHandle methods to generate. - */ - private static Map> defaultDMHMethods() { - return Map.of( - DMH_INVOKE_INTERFACE, Set.of("LL_L", "L3_I", "L3_V"), - DMH_INVOKE_VIRTUAL, Set.of("LL_L", "LLI_I", "L3_V"), - DMH_INVOKE_SPECIAL, Set.of("LL_I", "LL_L", "LLF_L", "LLD_L", - "L3_I", "L3_L", "L4_L", "L5_L", "L6_L", "L7_L", "L8_L", - "LLI_I", "LLI_L", "LLIL_I", "LLIL_L", "LLII_I", "LLII_L", - "L3I_L", "L3I_I", "L3ILL_L", "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, 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_I", "LLILL_L", "LLIL3_L", "LL_V", "LL_L", "L3_I", "L3_L", - "L3_V", "L4_I", "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"), - DMH_NEW_INVOKE_SPECIAL, Set.of("L_L", "LL_L"), - DMH_INVOKE_SPECIAL_IFC, Set.of("L5_I") - ); - } - private static int DMH_INVOKE_VIRTUAL_TYPE = 0; private static int DMH_INVOKE_INTERFACE_TYPE = 4; @@ -201,19 +163,8 @@ public final class GenerateJLIClassesPlugin implements Plugin { } public void initialize(ResourcePool in) { - // Start with the default configuration - defaultSpecies().stream().forEach(this::addSpeciesType); - - defaultInvokers().stream().forEach(this::validateMethodType); - - defaultCallSiteTypes().stream().forEach(this::addCallSiteType); - - defaultDMHMethods().entrySet().stream().forEach(e -> { - e.getValue().stream().forEach(type -> addDMHMethodType(e.getKey(), type)); - }); - - // Extend the default configuration with the contents in the supplied - // input file - if none was supplied we look for the default file + // Load configuration from the contents in the supplied input file + // - if none was supplied we look for the default file if (mainArgument == null || !mainArgument.startsWith("@")) { try (InputStream traceFile = this.getClass().getResourceAsStream(DEFAULT_TRACE_FILE)) { diff --git a/test/jdk/tools/jlink/plugins/GenerateJLIClassesPluginTest.java b/test/jdk/tools/jlink/plugins/GenerateJLIClassesPluginTest.java index 7bb3d34f5ea..6f403a63536 100644 --- a/test/jdk/tools/jlink/plugins/GenerateJLIClassesPluginTest.java +++ b/test/jdk/tools/jlink/plugins/GenerateJLIClassesPluginTest.java @@ -29,8 +29,6 @@ import java.util.Collection; import java.util.List; import java.util.stream.Collectors; -import jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin; - import tests.Helper; import tests.JImageGenerator; import tests.JImageValidator; @@ -62,32 +60,19 @@ public class GenerateJLIClassesPluginTest { helper.generateDefaultModules(); - // Test that generate-jli is enabled by default - Result result = JImageGenerator.getJLinkTask() - .modulePath(helper.defaultModulePath()) - .output(helper.createNewImageDir("generate-jli")) - .addMods("java.base") - .call(); - - Path image = result.assertSuccess(); - - JImageValidator.validate(image.resolve("lib").resolve("modules"), - classFilesForSpecies(GenerateJLIClassesPlugin.defaultSpecies()), - List.of()); - // Check that --generate-jli-classes=@file works as intended Path baseFile = Files.createTempFile("base", "trace"); String species = "LLLLLLLLLLLLLLLLLLL"; String fileString = "[SPECIES_RESOLVE] java.lang.invoke.BoundMethodHandle$Species_" + species + " (salvaged)\n"; Files.write(baseFile, fileString.getBytes(Charset.defaultCharset())); - result = JImageGenerator.getJLinkTask() + Result result = JImageGenerator.getJLinkTask() .modulePath(helper.defaultModulePath()) .output(helper.createNewImageDir("generate-jli-file")) .option("--generate-jli-classes=@" + baseFile.toString()) .addMods("java.base") .call(); - image = result.assertSuccess(); + Path image = result.assertSuccess(); JImageValidator.validate(image.resolve("lib").resolve("modules"), classFilesForSpecies(List.of(species)), // species should be in the image @@ -119,8 +104,7 @@ public class GenerateJLIClassesPluginTest { private static List classFilesForSpecies(Collection species) { return species.stream() - .map(s -> "/java.base/java/lang/invoke/BoundMethodHandle$Species_" - + GenerateJLIClassesPlugin.expandSignature(s) + ".class") + .map(s -> "/java.base/java/lang/invoke/BoundMethodHandle$Species_" + s + ".class") .collect(Collectors.toList()); } }