8230301: Re-examine hardcoded defaults in GenerateJLIClassesPlugin

Reviewed-by: mchung
This commit is contained in:
Claes Redestad 2020-02-10 12:39:19 +01:00
parent 6aeb78d3df
commit 0b5d48b9e6
4 changed files with 59 additions and 91 deletions

View File

@ -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) \

View File

@ -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<String> 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;
}
}
}

View File

@ -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<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");
}
/**
* @return the default invoker forms to generate.
*/
private static Set<String> 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<String> defaultCallSiteTypes() {
return Set.of("L5_L", "LIL3_L", "ILL_L");
}
/**
* @return the list of default DirectMethodHandle methods to generate.
*/
private static Map<String, Set<String>> 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)) {

View File

@ -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<String> classFilesForSpecies(Collection<String> 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());
}
}