8230301: Re-examine hardcoded defaults in GenerateJLIClassesPlugin
Reviewed-by: mchung
This commit is contained in:
parent
6aeb78d3df
commit
0b5d48b9e6
@ -75,6 +75,7 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR)
|
|||||||
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw \
|
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw \
|
||||||
-Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \
|
-Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \
|
||||||
-Duser.language=en -Duser.country=US \
|
-Duser.language=en -Duser.country=US \
|
||||||
|
--module-path $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
||||||
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
||||||
build.tools.classlist.HelloClasslist \
|
build.tools.classlist.HelloClasslist \
|
||||||
2> $(LINK_OPT_DIR)/stderr > $(JLI_TRACE_FILE) \
|
2> $(LINK_OPT_DIR)/stderr > $(JLI_TRACE_FILE) \
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
*/
|
*/
|
||||||
package build.tools.classlist;
|
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.net.InetAddress;
|
||||||
import java.nio.file.FileSystems;
|
import java.nio.file.FileSystems;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -55,7 +58,7 @@ public class HelloClasslist {
|
|||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger("Hello");
|
private static final Logger LOGGER = Logger.getLogger("Hello");
|
||||||
|
|
||||||
public static void main(String ... args) {
|
public static void main(String ... args) throws Throwable {
|
||||||
|
|
||||||
FileSystems.getDefault();
|
FileSystems.getDefault();
|
||||||
|
|
||||||
@ -66,7 +69,8 @@ public class HelloClasslist {
|
|||||||
.map(s -> s.toLowerCase(Locale.ROOT))
|
.map(s -> s.toLowerCase(Locale.ROOT))
|
||||||
.collect(joining(","));
|
.collect(joining(","));
|
||||||
|
|
||||||
Stream.of(helloWorld.split(","))
|
Stream.of(helloWorld.split("([,x-z]{1,3})([\\s]*)"))
|
||||||
|
.map(String::toString)
|
||||||
.forEach(System.out::println);
|
.forEach(System.out::println);
|
||||||
|
|
||||||
// Common concatenation patterns
|
// Common concatenation patterns
|
||||||
@ -83,6 +87,10 @@ public class HelloClasslist {
|
|||||||
String SCSCS = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length);
|
String SCSCS = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length);
|
||||||
String CI = "string" + args.length;
|
String CI = "string" + args.length;
|
||||||
String IC = args.length + "string";
|
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 CIC = "string" + args.length + "string";
|
||||||
String CICI = "string" + args.length + "string" + args.length;
|
String CICI = "string" + args.length + "string" + args.length;
|
||||||
String CJ = "string" + System.currentTimeMillis();
|
String CJ = "string" + System.currentTimeMillis();
|
||||||
@ -99,7 +107,31 @@ public class HelloClasslist {
|
|||||||
DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.ROOT)
|
DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.ROOT)
|
||||||
.format(new Date()));
|
.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);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,21 @@ import jdk.tools.jlink.plugin.Plugin;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin to generate java.lang.invoke classes.
|
* 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 {
|
public final class GenerateJLIClassesPlugin implements Plugin {
|
||||||
|
|
||||||
@ -112,59 +127,6 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
|||||||
return PluginsResourceBundle.getArgument(NAME);
|
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_VIRTUAL_TYPE = 0;
|
||||||
private static int DMH_INVOKE_INTERFACE_TYPE = 4;
|
private static int DMH_INVOKE_INTERFACE_TYPE = 4;
|
||||||
|
|
||||||
@ -201,19 +163,8 @@ public final class GenerateJLIClassesPlugin implements Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(ResourcePool in) {
|
public void initialize(ResourcePool in) {
|
||||||
// Start with the default configuration
|
// Load configuration from the contents in the supplied input file
|
||||||
defaultSpecies().stream().forEach(this::addSpeciesType);
|
// - if none was supplied we look for the default file
|
||||||
|
|
||||||
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
|
|
||||||
if (mainArgument == null || !mainArgument.startsWith("@")) {
|
if (mainArgument == null || !mainArgument.startsWith("@")) {
|
||||||
try (InputStream traceFile =
|
try (InputStream traceFile =
|
||||||
this.getClass().getResourceAsStream(DEFAULT_TRACE_FILE)) {
|
this.getClass().getResourceAsStream(DEFAULT_TRACE_FILE)) {
|
||||||
|
@ -29,8 +29,6 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin;
|
|
||||||
|
|
||||||
import tests.Helper;
|
import tests.Helper;
|
||||||
import tests.JImageGenerator;
|
import tests.JImageGenerator;
|
||||||
import tests.JImageValidator;
|
import tests.JImageValidator;
|
||||||
@ -62,32 +60,19 @@ public class GenerateJLIClassesPluginTest {
|
|||||||
|
|
||||||
helper.generateDefaultModules();
|
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
|
// Check that --generate-jli-classes=@file works as intended
|
||||||
Path baseFile = Files.createTempFile("base", "trace");
|
Path baseFile = Files.createTempFile("base", "trace");
|
||||||
String species = "LLLLLLLLLLLLLLLLLLL";
|
String species = "LLLLLLLLLLLLLLLLLLL";
|
||||||
String fileString = "[SPECIES_RESOLVE] java.lang.invoke.BoundMethodHandle$Species_" + species + " (salvaged)\n";
|
String fileString = "[SPECIES_RESOLVE] java.lang.invoke.BoundMethodHandle$Species_" + species + " (salvaged)\n";
|
||||||
Files.write(baseFile, fileString.getBytes(Charset.defaultCharset()));
|
Files.write(baseFile, fileString.getBytes(Charset.defaultCharset()));
|
||||||
result = JImageGenerator.getJLinkTask()
|
Result result = JImageGenerator.getJLinkTask()
|
||||||
.modulePath(helper.defaultModulePath())
|
.modulePath(helper.defaultModulePath())
|
||||||
.output(helper.createNewImageDir("generate-jli-file"))
|
.output(helper.createNewImageDir("generate-jli-file"))
|
||||||
.option("--generate-jli-classes=@" + baseFile.toString())
|
.option("--generate-jli-classes=@" + baseFile.toString())
|
||||||
.addMods("java.base")
|
.addMods("java.base")
|
||||||
.call();
|
.call();
|
||||||
|
|
||||||
image = result.assertSuccess();
|
Path image = result.assertSuccess();
|
||||||
|
|
||||||
JImageValidator.validate(image.resolve("lib").resolve("modules"),
|
JImageValidator.validate(image.resolve("lib").resolve("modules"),
|
||||||
classFilesForSpecies(List.of(species)), // species should be in the image
|
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) {
|
private static List<String> classFilesForSpecies(Collection<String> species) {
|
||||||
return species.stream()
|
return species.stream()
|
||||||
.map(s -> "/java.base/java/lang/invoke/BoundMethodHandle$Species_"
|
.map(s -> "/java.base/java/lang/invoke/BoundMethodHandle$Species_" + s + ".class")
|
||||||
+ GenerateJLIClassesPlugin.expandSignature(s) + ".class")
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user