< prev index next >
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java
Print this page
rev 16725 : 8175026: Capture build-time parameters to --generate-jli-classes
Reviewed-by: mchung
@@ -22,18 +22,21 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.tools.jlink.internal.plugins;
+import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.lang.invoke.MethodType;
+import java.lang.module.ModuleDescriptor;
import java.nio.file.Files;
-import java.util.ArrayList;
import java.util.EnumSet;
-import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -49,12 +52,17 @@
* Plugin to generate java.lang.invoke classes.
*/
public final class GenerateJLIClassesPlugin implements Plugin {
private static final String NAME = "generate-jli-classes";
+ private static final String IGNORE_VERSION = "ignore-version";
private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
+ private static final String IGNORE_VERSION_WARNING = NAME + ".ignore.version.warn";
+ private static final String VERSION_MISMATCH_WARNING = NAME + ".version.mismatch.warn";
+
+ private static final String DEFAULT_TRACE_FILE = "default_jli_trace.txt";
private static final String DIRECT_HOLDER = "java/lang/invoke/DirectMethodHandle$Holder";
private static final String DMH_INVOKE_VIRTUAL = "invokeVirtual";
private static final String DMH_INVOKE_STATIC = "invokeStatic";
private static final String DMH_INVOKE_SPECIAL = "invokeSpecial";
@@ -67,15 +75,19 @@
private static final String INVOKERS_HOLDER = "java/lang/invoke/Invokers$Holder";
private static final JavaLangInvokeAccess JLIA
= SharedSecrets.getJavaLangInvokeAccess();
- Set<String> speciesTypes;
+ Set<String> speciesTypes = Set.of();
+
+ Set<String> invokerTypes = Set.of();
- Set<String> invokerTypes;
+ Map<String, Set<String>> dmhMethods = Map.of();
- Map<String, Set<String>> dmhMethods;
+ String mainArgument;
+
+ boolean ignoreVersion;
public GenerateJLIClassesPlugin() {
}
@Override
@@ -155,47 +167,81 @@
DMH_INVOKE_STATIC_INIT, 5
);
@Override
public void configure(Map<String, String> config) {
- String mainArgument = config.get(NAME);
+ mainArgument = config.get(NAME);
+ ignoreVersion = Boolean.parseBoolean(config.get(IGNORE_VERSION));
+ }
+ public void initialize(ResourcePool in) {
// Start with the default configuration
- Set<String> defaultBMHSpecies = defaultSpecies();
- // Expand BMH species signatures
- defaultBMHSpecies = defaultBMHSpecies.stream()
+ speciesTypes = defaultSpecies().stream()
.map(type -> expandSignature(type))
.collect(Collectors.toSet());
- Set<String> defaultInvokerTypes = defaultInvokers();
- validateMethodTypes(defaultInvokerTypes);
+ invokerTypes = defaultInvokers();
+ validateMethodTypes(invokerTypes);
- Map<String, Set<String>> defaultDmhMethods = defaultDMHMethods();
- for (Set<String> dmhMethodTypes : defaultDmhMethods.values()) {
+ dmhMethods = defaultDMHMethods();
+ for (Set<String> dmhMethodTypes : dmhMethods.values()) {
validateMethodTypes(dmhMethodTypes);
}
// Extend the default configuration with the contents in the supplied
- // input file
+ // input file - if none was supplied we look for the default file
if (mainArgument == null || !mainArgument.startsWith("@")) {
- speciesTypes = defaultBMHSpecies;
- invokerTypes = defaultInvokerTypes;
- dmhMethods = defaultDmhMethods;
+ try (InputStream traceFile =
+ this.getClass().getResourceAsStream(DEFAULT_TRACE_FILE)) {
+ if (traceFile != null) {
+ readTraceConfig(
+ new BufferedReader(
+ new InputStreamReader(traceFile)).lines());
+ }
+ } catch (Exception e) {
+ throw new PluginException("Couldn't read " + DEFAULT_TRACE_FILE, e);
+ }
} else {
File file = new File(mainArgument.substring(1));
if (file.exists()) {
+ readTraceConfig(fileLines(file));
+ }
+ }
+ }
+
+ private boolean checkVersion(Runtime.Version linkedVersion) {
+ Runtime.Version baseVersion = Runtime.version();
+ if (baseVersion.major() != linkedVersion.major() ||
+ baseVersion.minor() != linkedVersion.minor()) {
+ return false;
+ }
+ return true;
+ }
+
+ private Runtime.Version getLinkedVersion(ResourcePool in) {
+ ModuleDescriptor.Version version = in.moduleView()
+ .findModule("java.base")
+ .get()
+ .descriptor()
+ .version()
+ .orElseThrow(() -> new PluginException("No version defined in "
+ + "the java.base being linked"));
+ return Runtime.Version.parse(version.toString());
+ }
+
+ private void readTraceConfig(Stream<String> lines) {
// 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()));
+ speciesTypes = new TreeSet<>(speciesTypes);
+ invokerTypes = new TreeSet<>(invokerTypes);
+ TreeMap<String, Set<String>> newDMHMethods = new TreeMap<>();
+ for (Map.Entry<String, Set<String>> entry : dmhMethods.entrySet()) {
+ newDMHMethods.put(entry.getKey(), new TreeSet<>(entry.getValue()));
}
- fileLines(file)
- .map(line -> line.split(" "))
+ dmhMethods = newDMHMethods;
+ lines.map(line -> line.split(" "))
.forEach(parts -> {
switch (parts[0]) {
case "[BMH_RESOLVE]":
speciesTypes.add(expandSignature(parts[1]));
break;
@@ -215,12 +261,10 @@
break;
default: break; // ignore
}
});
}
- }
- }
private void addDMHMethodType(String dmh, String methodType) {
validateMethodType(methodType);
Set<String> methodTypes = dmhMethods.get(dmh);
if (methodTypes == null) {
@@ -263,10 +307,29 @@
}
}
@Override
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
+ if (ignoreVersion) {
+ System.out.println(
+ PluginsResourceBundle
+ .getMessage(IGNORE_VERSION_WARNING));
+ } else if (!checkVersion(getLinkedVersion(in))) {
+ // The linked images are not version compatible
+ if (mainArgument != null) {
+ // Log a mismatch warning if an argument was specified
+ System.out.println(
+ PluginsResourceBundle
+ .getMessage(VERSION_MISMATCH_WARNING,
+ getLinkedVersion(in),
+ Runtime.version()));
+ }
+ in.transformAndCopy(entry -> entry, out);
+ return out.build();
+ }
+
+ initialize(in);
// Copy all but DMH_ENTRY to out
in.transformAndCopy(entry -> {
// filter out placeholder entries
if (entry.path().equals(DIRECT_METHOD_HOLDER_ENTRY) ||
entry.path().equals(DELEGATING_METHOD_HOLDER_ENTRY) ||
@@ -275,12 +338,22 @@
return null;
} else {
return entry;
}
}, out);
+
+ // Generate BMH Species classes
speciesTypes.forEach(types -> generateBMHClass(types, out));
+
+ // Generate LambdaForm Holder classes
generateHolderClasses(out);
+
+ // Let it go
+ speciesTypes = null;
+ invokerTypes = null;
+ dmhMethods = null;
+
return out.build();
}
@SuppressWarnings("unchecked")
private void generateBMHClass(String types, ResourcePoolBuilder out) {
< prev index next >