jdk/src/java.base/share/classes/java/lang/module/Resolver.java
changeset 39050 9de41b79ec7e
parent 37779 7c84df693837
child 42338 a60f280f803c
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Fri Jun 17 10:53:13 2016 +0800
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Fri Jun 17 08:41:39 2016 +0100
@@ -36,7 +36,6 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
@@ -454,17 +453,13 @@
 
 
     /**
-     * Computes and sets the readability graph for the modules in the given
-     * Resolution object.
+     * Computes the readability graph for the modules in the given Configuration.
      *
      * The readability graph is created by propagating "requires" through the
      * "public requires" edges of the module dependence graph. So if the module
      * dependence graph has m1 requires m2 && m2 requires public m3 then the
-     * resulting readability graph will contain m1 reads m2, m1
-     * reads m3, and m2 reads m3.
-     *
-     * TODO: Use a more efficient algorithm, maybe cache the requires public
-     *       in parent configurations.
+     * resulting readability graph will contain m1 reads m2, m1 reads m3, and
+     * m2 reads m3.
      */
     private Map<ResolvedModule, Set<ResolvedModule>> makeGraph(Configuration cf) {
 
@@ -483,16 +478,15 @@
         Configuration p = parent;
         while (p != null) {
             for (ModuleDescriptor descriptor : p.descriptors()) {
-                ResolvedModule x = p.findModule(descriptor.name()).orElse(null);
-                if (x == null)
-                    throw new InternalError();
+                String name = descriptor.name();
+                ResolvedModule m1 = p.findModule(name)
+                    .orElseThrow(() -> new InternalError(name + " not found"));
                 for (ModuleDescriptor.Requires requires : descriptor.requires()) {
                     if (requires.modifiers().contains(Modifier.PUBLIC)) {
                         String dn = requires.name();
-                        ResolvedModule y = p.findModule(dn).orElse(null);
-                        if (y == null)
-                            throw new InternalError(dn + " not found");
-                        g2.computeIfAbsent(x, k -> new HashSet<>()).add(y);
+                        ResolvedModule m2 = p.findModule(dn)
+                            .orElseThrow(() -> new InternalError(dn + " not found"));
+                        g2.computeIfAbsent(m1, k -> new HashSet<>()).add(m2);
                     }
                 }
             }
@@ -501,53 +495,60 @@
         }
 
         // populate g1 and g2 with the dependences from the selected modules
+
+        Map<String, ResolvedModule> nameToResolved = new HashMap<>();
+
         for (ModuleReference mref : nameToReference.values()) {
             ModuleDescriptor descriptor = mref.descriptor();
-            ResolvedModule x = new ResolvedModule(cf, mref);
+            String name = descriptor.name();
+
+            ResolvedModule m1 = computeIfAbsent(nameToResolved, name, cf, mref);
 
             Set<ResolvedModule> reads = new HashSet<>();
-            g1.put(x, reads);
-
             Set<ResolvedModule> requiresPublic = new HashSet<>();
-            g2.put(x, requiresPublic);
 
             for (ModuleDescriptor.Requires requires : descriptor.requires()) {
                 String dn = requires.name();
 
-                ResolvedModule y;
-                ModuleReference other = nameToReference.get(dn);
-                if (other != null) {
-                    y = new ResolvedModule(cf, other);  // cache?
+                ResolvedModule m2;
+                ModuleReference mref2 = nameToReference.get(dn);
+                if (mref2 != null) {
+                    // same configuration
+                    m2 = computeIfAbsent(nameToResolved, dn, cf, mref2);
                 } else {
-                    y = parent.findModule(dn).orElse(null);
-                    if (y == null)
-                        throw new InternalError("unable to find " + dn);
+                    // parent configuration
+                    m2 = parent.findModule(dn).orElse(null);
+                    if (m2 == null) {
+                        continue;
+                    }
                 }
 
-                // m requires other => m reads other
-                reads.add(y);
+                // m1 requires m2 => m1 reads m2
+                reads.add(m2);
 
-                // m requires public other
+                // m1 requires public m2
                 if (requires.modifiers().contains(Modifier.PUBLIC)) {
-                    requiresPublic.add(y);
+                    requiresPublic.add(m2);
                 }
 
             }
 
-            // automatic modules reads all selected modules and all modules
+            // automatic modules read all selected modules and all modules
             // in parent configurations
             if (descriptor.isAutomatic()) {
-                String name = descriptor.name();
 
                 // reads all selected modules
-                // requires public` all selected automatic modules
+                // `requires public` all selected automatic modules
                 for (ModuleReference mref2 : nameToReference.values()) {
                     ModuleDescriptor descriptor2 = mref2.descriptor();
-                    if (!name.equals(descriptor2.name())) {
-                        ResolvedModule m = new ResolvedModule(cf, mref2);
-                        reads.add(m);
+                    String name2 = descriptor2.name();
+
+                    if (!name.equals(name2)) {
+                        ResolvedModule m2
+                            = computeIfAbsent(nameToResolved, name2, cf, mref2);
+                        reads.add(m2);
                         if (descriptor2.isAutomatic())
-                            requiresPublic.add(m);
+                            requiresPublic.add(m2);
                     }
                 }
 
@@ -565,52 +566,56 @@
 
             }
 
+            g1.put(m1, reads);
+            g2.put(m1, requiresPublic);
         }
 
         // Iteratively update g1 until there are no more requires public to propagate
         boolean changed;
-        Map<ResolvedModule, Set<ResolvedModule>> changes = new HashMap<>();
+        Set<ResolvedModule> toAdd = new HashSet<>();
         do {
             changed = false;
-            for (Entry<ResolvedModule, Set<ResolvedModule>> entry : g1.entrySet()) {
-
-                ResolvedModule m1 = entry.getKey();
-                Set<ResolvedModule> m1Reads = entry.getValue();
-
+            for (Set<ResolvedModule> m1Reads : g1.values()) {
                 for (ResolvedModule m2 : m1Reads) {
                     Set<ResolvedModule> m2RequiresPublic = g2.get(m2);
                     if (m2RequiresPublic != null) {
                         for (ResolvedModule m3 : m2RequiresPublic) {
                             if (!m1Reads.contains(m3)) {
-
-                                // computeIfAbsent
-                                Set<ResolvedModule> s = changes.get(m1);
-                                if (s == null) {
-                                    s = new HashSet<>();
-                                    changes.put(m1, s);
-                                }
-                                s.add(m3);
-                                changed = true;
-
+                                // m1 reads m2, m2 requires public m3
+                                // => need to add m1 reads m3
+                                toAdd.add(m3);
                             }
                         }
                     }
                 }
+                if (!toAdd.isEmpty()) {
+                    m1Reads.addAll(toAdd);
+                    toAdd.clear();
+                    changed = true;
+                }
             }
-
-            if (changed) {
-                for (Map.Entry<ResolvedModule, Set<ResolvedModule>> e :
-                        changes.entrySet()) {
-                    ResolvedModule m = e.getKey();
-                    g1.get(m).addAll(e.getValue());
-                }
-                changes.clear();
-            }
-
         } while (changed);
 
+        return g1;
+    }
 
-        return g1;
+    /**
+     * Equivalent to
+     * <pre>{@code
+     *     map.computeIfAbsent(name, k -> new ResolvedModule(cf, mref))
+     * </pre>}
+     */
+    private ResolvedModule computeIfAbsent(Map<String, ResolvedModule> map,
+                                           String name,
+                                           Configuration cf,
+                                           ModuleReference mref)
+    {
+        ResolvedModule m = map.get(name);
+        if (m == null) {
+            m = new ResolvedModule(cf, mref);
+            map.put(name, m);
+        }
+        return m;
     }