< prev index next >
src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin.java
Print this page
rev 16713 : 8175026: Capture build-time parameters to --generate-jli-classes
Reviewed-by: mchung
*** 22,39 ****
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.tools.jlink.internal.plugins;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodType;
import java.nio.file.Files;
- import java.util.ArrayList;
import java.util.EnumSet;
- 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;
--- 22,43 ----
* 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.lang.module.ModuleFinder;
import java.nio.file.Files;
import java.util.EnumSet;
import java.util.Map;
+ import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
*** 52,61 ****
--- 56,67 ----
private static final String NAME = "generate-jli-classes";
private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
+ 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";
private static final String DMH_NEW_INVOKE_SPECIAL = "newInvokeSpecial";
*** 67,81 ****
private static final String INVOKERS_HOLDER = "java/lang/invoke/Invokers$Holder";
private static final JavaLangInvokeAccess JLIA
= SharedSecrets.getJavaLangInvokeAccess();
! Set<String> speciesTypes;
! Set<String> invokerTypes;
! Map<String, Set<String>> dmhMethods;
public GenerateJLIClassesPlugin() {
}
@Override
--- 73,89 ----
private static final String INVOKERS_HOLDER = "java/lang/invoke/Invokers$Holder";
private static final JavaLangInvokeAccess JLIA
= SharedSecrets.getJavaLangInvokeAccess();
! Set<String> speciesTypes = Set.of();
!
! Set<String> invokerTypes = Set.of();
! Map<String, Set<String>> dmhMethods = Map.of();
! String mainArgument;
public GenerateJLIClassesPlugin() {
}
@Override
*** 155,201 ****
DMH_INVOKE_STATIC_INIT, 5
);
@Override
public void configure(Map<String, String> config) {
! String mainArgument = config.get(NAME);
// Start with the default configuration
! Set<String> defaultBMHSpecies = defaultSpecies();
! // Expand BMH species signatures
! defaultBMHSpecies = defaultBMHSpecies.stream()
.map(type -> expandSignature(type))
.collect(Collectors.toSet());
! Set<String> defaultInvokerTypes = defaultInvokers();
! validateMethodTypes(defaultInvokerTypes);
! Map<String, Set<String>> defaultDmhMethods = defaultDMHMethods();
! for (Set<String> 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()) {
// 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()));
}
! fileLines(file)
! .map(line -> line.split(" "))
.forEach(parts -> {
switch (parts[0]) {
case "[BMH_RESOLVE]":
speciesTypes.add(expandSignature(parts[1]));
break;
--- 163,246 ----
DMH_INVOKE_STATIC_INIT, 5
);
@Override
public void configure(Map<String, String> config) {
! mainArgument = config.get(NAME);
! }
!
! public void initialize(ResourcePool in) {
! ModuleDescriptor.Version baseVersion =
! ModuleFinder.ofSystem()
! .find("java.base")
! .get()
! .descriptor()
! .version()
! .orElse(null);
! ModuleDescriptor.Version linkedVersion =
! in.moduleView()
! .findModule("java.base")
! .get()
! .descriptor()
! .version()
! .orElse(null);
! // When baseVersion is null, we are likely operating on a exploded image
! // during build and can assume the linked version is compatible -
! // otherwise check that the linked version is the same
! if (baseVersion != null && !baseVersion.equals(linkedVersion)) {
! throw new IllegalStateException("WARNING: Pre-generation of JLI "
! + "classes is only supported when linking the same version "
! + "of java.base (" + linkedVersion + ") as the VM tool "
! + "running jlink (" + baseVersion + ")");
! }
// Start with the default configuration
! speciesTypes = defaultSpecies().stream()
.map(type -> expandSignature(type))
.collect(Collectors.toSet());
! invokerTypes = defaultInvokers();
! validateMethodTypes(invokerTypes);
! dmhMethods = defaultDMHMethods();
! for (Set<String> dmhMethodTypes : dmhMethods.values()) {
validateMethodTypes(dmhMethodTypes);
}
// 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("@")) {
! 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 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<>(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()));
}
! dmhMethods = newDMHMethods;
! lines.map(line -> line.split(" "))
.forEach(parts -> {
switch (parts[0]) {
case "[BMH_RESOLVE]":
speciesTypes.add(expandSignature(parts[1]));
break;
*** 215,226 ****
break;
default: break; // ignore
}
});
}
- }
- }
private void addDMHMethodType(String dmh, String methodType) {
validateMethodType(methodType);
Set<String> methodTypes = dmhMethods.get(dmh);
if (methodTypes == null) {
--- 260,269 ----
*** 263,272 ****
--- 306,323 ----
}
}
@Override
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
+ try {
+ initialize(in);
+ } catch (IllegalStateException e) {
+ // The linked images is not compatible, log and shortcut
+ System.out.println(e.getMessage());
+ in.transformAndCopy(entry -> entry, out);
+ return out.build();
+ }
// 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,286 ****
--- 326,347 ----
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 >