< 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 >