changeset 59985:ff30bca14dc9

8237878: Improve ModuleLoaderMap datastructures Reviewed-by: alanb, forax
author redestad
date Mon, 10 Feb 2020 13:58:12 +0100
parents 6a82085fc61d
children d954bf9df7f6
files src/java.base/share/classes/java/lang/Module.java src/java.base/share/classes/java/lang/module/ResolvedModule.java src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java
diffstat 5 files changed, 104 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/Module.java	Mon Feb 10 12:57:31 2020 +0000
+++ b/src/java.base/share/classes/java/lang/Module.java	Mon Feb 10 13:58:12 2020 +0100
@@ -1094,13 +1094,14 @@
 
         // map each module to a class loader
         ClassLoader pcl = ClassLoaders.platformClassLoader();
+        boolean isModuleLoaderMapper = ModuleLoaderMap.isBuiltinMapper(clf);
 
         for (int index = 0; index < numModules; index++) {
             String name = resolvedModules[index].name();
             ClassLoader loader = clf.apply(name);
 
             if (loader == null || loader == pcl) {
-                if (!(clf instanceof ModuleLoaderMap.Mapper)) {
+                if (!isModuleLoaderMapper) {
                     throw new IllegalArgumentException("loader can't be 'null'"
                             + " or the platform class loader");
                 }
--- a/src/java.base/share/classes/java/lang/module/ResolvedModule.java	Mon Feb 10 12:57:31 2020 +0000
+++ b/src/java.base/share/classes/java/lang/module/ResolvedModule.java	Mon Feb 10 13:58:12 2020 +0100
@@ -79,7 +79,7 @@
      * @return The module descriptor
      */
     ModuleDescriptor descriptor() {
-        return reference().descriptor();
+        return mref.descriptor();
     }
 
     /**
@@ -93,7 +93,7 @@
      * @return The module name
      */
     public String name() {
-        return reference().descriptor().name();
+        return mref.descriptor().name();
     }
 
     /**
--- a/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java	Mon Feb 10 12:57:31 2020 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ArchivedModuleGraph.java	Mon Feb 10 13:58:12 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,8 +28,8 @@
 import java.lang.module.Configuration;
 import java.lang.module.ModuleFinder;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
+import java.util.function.Function;
 
 import jdk.internal.misc.VM;
 
@@ -39,26 +39,26 @@
 final class ArchivedModuleGraph {
     private static ArchivedModuleGraph archivedModuleGraph;
 
-    private final String mainModule;
     private final boolean hasSplitPackages;
     private final boolean hasIncubatorModules;
     private final ModuleFinder finder;
     private final Configuration configuration;
+    private final Function<String, ClassLoader> classLoaderFunction;
     private final Map<String, Set<String>> concealedPackagesToOpen;
     private final Map<String, Set<String>> exportedPackagesToOpen;
 
-    private ArchivedModuleGraph(String mainModule,
-                                boolean hasSplitPackages,
-                                boolean hasIncubatorModules,
-                                ModuleFinder finder,
-                                Configuration configuration,
-                                Map<String, Set<String>> concealedPackagesToOpen,
-                                Map<String, Set<String>> exportedPackagesToOpen) {
-        this.mainModule = mainModule;
+    public ArchivedModuleGraph(boolean hasSplitPackages,
+                               boolean hasIncubatorModules,
+                               ModuleFinder finder,
+                               Configuration configuration,
+                               Function<String, ClassLoader> classLoaderFunction,
+                               Map<String, Set<String>> concealedPackagesToOpen,
+                               Map<String, Set<String>> exportedPackagesToOpen) {
         this.hasSplitPackages = hasSplitPackages;
         this.hasIncubatorModules = hasIncubatorModules;
         this.finder = finder;
         this.configuration = configuration;
+        this.classLoaderFunction = classLoaderFunction;
         this.concealedPackagesToOpen = concealedPackagesToOpen;
         this.exportedPackagesToOpen = exportedPackagesToOpen;
     }
@@ -71,6 +71,10 @@
         return configuration;
     }
 
+    Function<String, ClassLoader> classLoaderFunction() {
+        return classLoaderFunction;
+    }
+
     Map<String, Set<String>> concealedPackagesToOpen() {
         return concealedPackagesToOpen;
     }
@@ -92,7 +96,8 @@
      */
     static ArchivedModuleGraph get(String mainModule) {
         ArchivedModuleGraph graph = archivedModuleGraph;
-        if (graph != null && Objects.equals(mainModule, graph.mainModule)) {
+        // We only allow the unnamed module (default) case for now
+        if (mainModule == null) {
             return graph;
         } else {
             return null;
@@ -102,23 +107,8 @@
     /**
      * Archive the module graph for the given initial module.
      */
-    static void archive(String mainModule,
-                        boolean hasSplitPackages,
-                        boolean hasIncubatorModules,
-                        ModuleFinder finder,
-                        Configuration configuration,
-                        Map<String, Set<String>> concealedPackagesToOpen,
-                        Map<String, Set<String>> exportedPackagesToOpen) {
-        if (mainModule != null) {
-            throw new UnsupportedOperationException();
-        }
-        archivedModuleGraph = new ArchivedModuleGraph(mainModule,
-                                                      hasSplitPackages,
-                                                      hasIncubatorModules,
-                                                      finder,
-                                                      configuration,
-                                                      concealedPackagesToOpen,
-                                                      exportedPackagesToOpen);
+    static void archive(ArchivedModuleGraph graph) {
+        archivedModuleGraph = graph;
     }
 
     static {
--- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Mon Feb 10 12:57:31 2020 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Mon Feb 10 13:58:12 2020 +0100
@@ -370,7 +370,12 @@
         // loader.
 
         // mapping of modules to class loaders
-        Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
+        Function<String, ClassLoader> clf;
+        if (archivedModuleGraph != null) {
+            clf = archivedModuleGraph.classLoaderFunction();
+        } else {
+            clf = ModuleLoaderMap.mappingFunction(cf);
+        }
 
         // check that all modules to be mapped to the boot loader will be
         // loaded from the runtime image
@@ -440,13 +445,14 @@
         // Module graph can be archived at CDS dump time. Only allow the
         // unnamed module case for now.
         if (canArchive && (mainModule == null)) {
-            ArchivedModuleGraph.archive(mainModule,
-                                        hasSplitPackages,
-                                        hasIncubatorModules,
-                                        systemModuleFinder,
-                                        cf,
-                                        concealedPackagesToOpen,
-                                        exportedPackagesToOpen);
+            ArchivedModuleGraph.archive(
+                    new ArchivedModuleGraph(hasSplitPackages,
+                                            hasIncubatorModules,
+                                            systemModuleFinder,
+                                            cf,
+                                            clf,
+                                            concealedPackagesToOpen,
+                                            exportedPackagesToOpen));
         }
 
         // total time to initialize
@@ -737,7 +743,6 @@
                         Modules.addExports(m, pn, other);
                     }
                 }
-
             }
         }
     }
--- a/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java	Mon Feb 10 12:57:31 2020 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java	Mon Feb 10 13:58:12 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,14 +28,12 @@
 import java.lang.module.Configuration;
 import java.lang.module.ResolvedModule;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
 
 import jdk.internal.loader.ClassLoaders;
 
-
 /**
  * Supports the mapping of modules to class loaders. The set of modules mapped
  * to the boot and platform class loaders is generated at build time from
@@ -46,16 +44,55 @@
     /**
      * Maps the system modules to the built-in class loaders.
      */
-    public static final class Mapper implements Function<String, ClassLoader> {
-        private final Map<String, ClassLoader> map;
+    private static final class Mapper implements Function<String, ClassLoader> {
 
-        Mapper(Map<String, ClassLoader> map) {
-            this.map = map; // defensive copy not needed
+        private static final ClassLoader PLATFORM_CLASSLOADER =
+                ClassLoaders.platformClassLoader();
+        private static final ClassLoader APP_CLASSLOADER =
+                ClassLoaders.appClassLoader();
+
+        private static final Integer PLATFORM_LOADER_INDEX = 1;
+        private static final Integer APP_LOADER_INDEX      = 2;
+
+        /**
+         * Map from module to a class loader index. The index is resolved to the
+         * actual class loader in {@code apply}.
+         */
+        private final Map<String, Integer> map;
+
+        /**
+         * Creates a Mapper to map module names in the given Configuration to
+         * built-in classloaders.
+         *
+         * As a proxy for the actual classloader, we store an easily archiveable
+         * index value in the internal map. The index is stored as a boxed value
+         * so that we can cheaply do identity comparisons during bootstrap.
+         */
+        Mapper(Configuration cf) {
+            var map = new HashMap<String, Integer>();
+            for (ResolvedModule resolvedModule : cf.modules()) {
+                String mn = resolvedModule.name();
+                if (!Modules.bootModules.contains(mn)) {
+                    if (Modules.platformModules.contains(mn)) {
+                        map.put(mn, PLATFORM_LOADER_INDEX);
+                    } else {
+                        map.put(mn, APP_LOADER_INDEX);
+                    }
+                }
+            }
+            this.map = map;
         }
 
         @Override
         public ClassLoader apply(String name) {
-            return map.get(name);
+            Integer loader = map.get(name);
+            if (loader == APP_LOADER_INDEX) {
+                return APP_CLASSLOADER;
+            } else if (loader == PLATFORM_LOADER_INDEX) {
+                return PLATFORM_CLASSLOADER;
+            } else { // BOOT_LOADER_INDEX
+                return null;
+            }
         }
     }
 
@@ -63,50 +100,40 @@
      * Returns the names of the modules defined to the boot loader.
      */
     public static Set<String> bootModules() {
-        // The list of boot modules generated at build time.
-        String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
-        Set<String> bootModules = new HashSet<>(BOOT_MODULES.length);
-        for (String mn : BOOT_MODULES) {
-            bootModules.add(mn);
-        }
-        return bootModules;
+        return Modules.bootModules;
     }
 
     /**
      * Returns the names of the modules defined to the platform loader.
      */
     public static Set<String> platformModules() {
-        // The list of platform modules generated at build time.
-        String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
-        Set<String> platformModules = new HashSet<>(PLATFORM_MODULES.length);
-        for (String mn : PLATFORM_MODULES) {
-            platformModules.add(mn);
-        }
-        return platformModules;
+        return Modules.platformModules;
+    }
+
+    private static class Modules {
+        // list of boot modules is generated at build time.
+        private static final Set<String> bootModules =
+                Set.of(new String[] { "@@BOOT_MODULE_NAMES@@" });
+
+        // list of platform modules is generated at build time.
+        private static final Set<String> platformModules =
+                Set.of(new String[] { "@@PLATFORM_MODULE_NAMES@@" });
     }
 
     /**
-     * Returns the function to map modules in the given configuration to the
+     * Returns a function to map modules in the given configuration to the
      * built-in class loaders.
      */
     static Function<String, ClassLoader> mappingFunction(Configuration cf) {
-        Set<String> bootModules = bootModules();
-        Set<String> platformModules = platformModules();
+        return new Mapper(cf);
+    }
 
-        ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
-        ClassLoader appClassLoader = ClassLoaders.appClassLoader();
-
-        Map<String, ClassLoader> map = new HashMap<>();
-        for (ResolvedModule resolvedModule : cf.modules()) {
-            String mn = resolvedModule.name();
-            if (!bootModules.contains(mn)) {
-                if (platformModules.contains(mn)) {
-                    map.put(mn, platformClassLoader);
-                } else {
-                    map.put(mn, appClassLoader);
-                }
-            }
-        }
-        return new Mapper(map);
+    /**
+     * When defining modules for a configuration, we only allow defining modules
+     * to the boot or platform classloader if the ClassLoader mapping function
+     * originate from here.
+     */
+    public static boolean isBuiltinMapper(Function<String, ClassLoader> clf) {
+        return clf instanceof Mapper;
     }
 }