make/tools/classanalyzer/src/com/sun/classanalyzer/Module.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2010 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
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.

@@ -21,92 +21,75 @@
  * questions.
  *
  */
 package com.sun.classanalyzer;
 
-import com.sun.classanalyzer.AnnotatedDependency.OptionalDependency;
+import com.sun.classanalyzer.ModuleInfo.Dependence;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
-import java.io.PrintWriter;
 import java.util.ArrayDeque;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Deque;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.TreeMap;
 import java.util.TreeSet;
 
-import static com.sun.classanalyzer.Platform.*;
-import static com.sun.classanalyzer.Trace.*;
 
 /**
+ * Module contains a list of classes and resources.
  *
  * @author Mandy Chung
  */
 public class Module implements Comparable<Module> {
 
-    private static final Map<String, Module> modules = new LinkedHashMap<String, Module>();
+    private static final Map<String, Module> modules =
+            new LinkedHashMap<String, Module>();
 
-    /**
-     * Returns the top-level modules that are defined in
-     * the input module config files.
-     *
-     */
-    static Collection<Module> getTopLevelModules() {
-        Set<Module> result = new LinkedHashSet<Module>();
-        // always put the boot module first and then the base
-        if (Platform.bootModule() != null) {
-            result.add(Platform.bootModule());
+    public static Collection<Module> getAllModules() {
+        return Collections.unmodifiableCollection(modules.values());
         }
-        result.add(findModule(baseModuleName));
 
-        for (Module m : modules.values()) {
-            if (m.isTopLevel()) {
-                result.add(m);
+    public static void addModule(Module m) {
+        String name = m.name();
+        if (modules.containsKey(name)) {
+            throw new RuntimeException("module \"" + name + "\" already exists");
             }
+        modules.put(name, m);
         }
-        return Collections.unmodifiableCollection(result);
-    }
 
     public static Module addModule(ModuleConfig config) {
         String name = config.module;
         if (modules.containsKey(name)) {
             throw new RuntimeException("module \"" + name + "\" already exists");
         }
-        Module m;
-        if (Platform.isBootModule(config.module)) {
-            m = Platform.createBootModule(config);
-        } else {
-            m = new Module(config);
-        }
-        modules.put(name, m);
+        Module m = new Module(config);
+        addModule(m);
         return m;
     }
 
     public static Module findModule(String name) {
         return modules.get(name);
     }
-    private static String baseModuleName = "base";
-    private static String version = "7-ea";
 
+    private static String baseModuleName = "base";
     static void setBaseModule(String name) {
+        if (name == null || name.isEmpty()) {
+            throw new RuntimeException("Null or empty base module");
+        }
         baseModuleName = name;
     }
 
-    static void setVersion(String ver) {
-        version = ver;
-    }
     private static Properties moduleProps = new Properties();
+    static String getModuleProperty(String key) {
+        return moduleProps.getProperty(key);
+    }
 
     static void setModuleProperties(String file) throws IOException {
         File f = new File(file);
         BufferedReader reader = null;
         try {

@@ -121,167 +104,80 @@
     private final String name;
     private final ModuleConfig config;
     private final Set<Klass> classes;
     private final Set<ResourceFile> resources;
     private final Set<Reference> unresolved;
-    private final Map<String, PackageInfo> packages;
-    private final Set<Dependency> dependents;
     private final Set<Module> members;
-    private final Set<RequiresModule> requires;
     // update during the analysis
-    private Set<Module> permits;
     private Module group;
+    private ModuleInfo minfo;
     private boolean isBaseModule;
-    private int platformApiCount;
 
     protected Module(ModuleConfig config) {
         this.name = config.module;
         this.isBaseModule = name.equals(baseModuleName);
         this.classes = new TreeSet<Klass>();
         this.resources = new TreeSet<ResourceFile>();
         this.config = config;
         this.unresolved = new HashSet<Reference>();
-        this.dependents = new TreeSet<Dependency>();
-        this.packages = new TreeMap<String, PackageInfo>();
         this.members = new TreeSet<Module>();
-        this.requires = new TreeSet<RequiresModule>(config.requires());
         this.group = this; // initialize to itself
-        this.platformApiCount = 0;
     }
 
     String name() {
         return name;
     }
 
+    ModuleConfig config() {
+        return config;
+    }
+
     Module group() {
         return group;
     }
 
     boolean isBase() {
         return isBaseModule;
     }
 
-    // requires local for JRE modules that are strongly
-    // connected with the boot module
-    boolean isBootConnected() {
-        for (RequiresModule rm : requires) {
-            if (Platform.isBootModule(rm.modulename)) {
-                return true;
+    Set<Klass> classes() {
+        return Collections.unmodifiableSet(classes);
             }
-        }
-        return false;
-    }
-    private Module moduleForRequires;
 
-    synchronized Module toRequiredModule() {
-        if (moduleForRequires == null) {
-            // create a module for external requires if needed
-            moduleForRequires = Platform.toRequiresModule(this);
+    Set<ResourceFile> resources() {
+        return Collections.unmodifiableSet(resources);
         }
-        return moduleForRequires;
-    }
 
     Set<Module> members() {
-        return members;
+        return Collections.unmodifiableSet(members);
     }
 
-    boolean hasPlatformAPIs() {
-        return platformApiCount > 0;
-    }
-
     boolean contains(Klass k) {
         return k != null && classes.contains(k);
     }
 
     boolean isEmpty() {
-        return classes.isEmpty() &&
-                resources.isEmpty() &&
-                mainClass() == null;
+        return classes.isEmpty()
+                && resources.isEmpty()
+                && mainClass() == null;
     }
 
     boolean allowEmpty() {
         return moduleProps.getProperty(name + ".allow.empty") != null;
     }
 
-    Module alias() {
-        String mn = moduleProps.getProperty(name + ".alias");
-        Module m = this;
-        if (mn != null) {
-            m = findModule(mn);
-            if (m == null) {
-                throw new RuntimeException(name + ".alias = " + mn + " not found");
+    // returns itself.
+    public Module exporter(Module from) {
+        return this;
             }
-        }
-        return m;
-    }
 
     protected boolean isTopLevel() {
         // module with no class is not included except the base module
-        return this.group == this &&
-                (isBase() || !isEmpty() || isAggregator() || allowEmpty());
+        return this.group == this
+                && (isBase() || !isEmpty() || !config.requires().isEmpty() || allowEmpty());
     }
 
-    boolean isAggregator() {
-        // a module is an aggregator if it has no class and resource and no main class
-        // but has a list of requires.
-        if (isEmpty() && requires.size() > 0) {
-            // return false if it requires only jdk.boot
-            if (requires.size() == 1) {
-                for (RequiresModule rm : requires) {
-                    if (Platform.isBootModule(rm.modulename)) {
-                        return false;
-                    }
-                }
-            }
-            return true;
-        }
-
-        return false;
-    }
-
-    // fixup permits and requires set after modules are merged
-    void fixupModuleInfo() {
-        Set<Module> newPermits = new TreeSet<Module>();
-        for (Module m : permits()) {
-            // in case multiple permits from the same group
-            newPermits.add(m.group());
-        }
-        permits.clear();
-        permits.addAll(newPermits);
-
-        // fixup requires set
-        Set<RequiresModule> newRequires = new TreeSet<RequiresModule>();
-        for (RequiresModule rm : requires) {
-            Module req = rm.module();
-            if (req.isEmpty() && !req.isAggregator()) {
-                // remove from requires set if empty and not a module aggregator
-                continue;
-            }
-
-            newRequires.add(rm);
-            if (req.requirePermits()) {
-                req.permits().add(this.group());
-            }
-        }
-        requires.clear();
-        requires.addAll(newRequires);
-
-        // add this to the permits set of its dependences if needed
-        for (Dependency d : dependences()) {
-            if (d.dynamic && !d.optional) {
-                // ignore dynamic dependencies for now
-                continue;
-            }
-
-            // add permits for all local dependencies
-            Module dm = d.module();
-            if (dm.requirePermits()) {
-                dm.permits().add(this.group());
-            }
-        }
-    }
-
     Klass mainClass() {
         String cls = config.mainClass();
         if (cls == null) {
             return null;
         }

@@ -288,77 +184,10 @@
 
         Klass k = Klass.findKlass(cls);
         return k;
     }
 
-    synchronized Set<Module> permits() {
-        if (permits == null) {
-            this.permits = new TreeSet<Module>();
-            // initialize the permits set
-            for (String s : config.permits()) {
-                Module m = findModule(s);
-                if (m != null) {
-                    permits.add(m.group());
-                } else {
-                    throw new RuntimeException("module " + s +
-                            " specified in the permits rule for " + name + " doesn't exist");
-                }
-            }
-        }
-        return permits;
-    }
-
-    Set<RequiresModule> requires() {
-        return requires;
-    }
-
-    Collection<Dependency> dependents() {
-        Map<Module, Dependency> deps = new LinkedHashMap<Module, Dependency>();
-        for (Dependency dep : dependents) {
-            Dependency d = deps.get(dep.module());
-            if (d == null || dep.compareTo(d) > 0) {
-                deps.put(dep.module(), dep);
-            }
-        }
-        return deps.values();
-    }
-
-    boolean requires(Module m) {
-        for (RequiresModule rm : requires()) {
-            if (rm.module() == m)
-                return true;
-        }
-        return false;
-    }
-    /**
-     * Returns a Collection of Dependency, only one for each dependent
-     * module of the strongest dependency (i.e.
-     * hard static > hard dynamic > optional static > optional dynamic
-     */
-    Collection<Dependency> dependences() {
-        Set<Dependency> result = new TreeSet<Dependency>();
-        for (Dependency d : dependents()) {
-            Module dm = d.module();
-            Module rm = dm;
-            if (!dm.alias().requires(this)) {
-                // use alias as the dependence except this module
-                // is required by the alias that will result in
-                // a recursive dependence.
-                rm = dm.alias();
-            }
-            if (!isBootConnected()) {
-                // If it's a local module requiring jdk.boot, retain
-                // the original requires; otherwise, use its external
-                // module
-                rm = rm.toRequiredModule();
-            }
-
-            result.add(new Dependency(rm, d.optional, d.dynamic));
-        }
-        return result;
-    }
-
     @Override
     public int compareTo(Module o) {
         if (o == null) {
             return -1;
         }

@@ -371,28 +200,12 @@
     }
 
     void addKlass(Klass k) {
         classes.add(k);
         k.setModule(this);
-        if (k.isPlatformAPI()) {
-            platformApiCount++;
         }
 
-        // update package statistics
-        String pkg = k.getPackageName();
-        PackageInfo pkginfo = packages.get(pkg);
-        if (pkginfo == null) {
-            pkginfo = new PackageInfo(pkg);
-            packages.put(pkg, pkginfo);
-        }
-
-        if (k.exists()) {
-            // only count the class that is parsed
-            pkginfo.add(k.getFileSize());
-        }
-    }
-
     void addResource(ResourceFile res) {
         resources.add(res);
         res.setModule(this);
     }
 

@@ -420,11 +233,10 @@
 
             for (Klass other : k.getReferencedClasses()) {
                 Module otherModule = other.getModule();
                 if (otherModule != null && otherModule != this) {
                     // this module is dependent on otherModule
-                    addDependency(k, other);
                     continue;
                 }
 
                 if (!classes.contains(other)) {
                     if (config.isExcluded(other.getClassName())) {

@@ -446,20 +258,15 @@
                     // dependencies
                     for (Klass other : c.getReferencedClasses()) {
                         Module otherModule = other.getModule();
                         if (otherModule == null) {
                             unresolved.add(new Reference(c, other));
-                        } else {
-                            if (otherModule != this) {
-                                // this module is dependent on otherModule
-                                addDependency(c, other);
                             }
                         }
                     }
                 }
             }
-        }
 
         // add other matching classes that don't require dependency analysis
         for (ResourceFile res : ResourceFile.getAllResources()) {
             if (res.getModule() == null) {
                 String name = res.getName();

@@ -468,54 +275,10 @@
                 }
             }
         }
     }
 
-    void addDependency(Klass from, Klass to) {
-        Dependency dep = new Dependency(from, to);
-        dependents.add(dep);
-    }
-
-    void addRequiresModule(Module m) {
-        addRequiresModule(m, false);
-    }
-
-    void addRequiresModule(Module m, boolean optional) {
-        requires.add(new RequiresModule(m, optional));
-        if (m.requirePermits()) {
-            m.permits().add(this);
-        }
-    }
-
-    boolean requirePermits() {
-        return (name().startsWith("sun.") ||
-                permits().size() > 0);
-    }
-
-    void fixupDependencies() {
-        // update dependencies for classes that were allocated to modules after
-        // this module was processed.
-        for (Reference ref : unresolved) {
-            Module m = ref.referree().getModule();
-            if (m == null || m != this) {
-                addDependency(ref.referrer, ref.referree);
-            }
-        }
-
-        // add dependency due to the main class
-        Klass k = mainClass();
-        if (k != null) {
-            dependents.add(new Dependency(k.getModule(), false, false));
-        }
-        fixupAnnotatedDependencies();
-    }
-
-    private void fixupAnnotatedDependencies() {
-        // add dependencies that this klass may depend on due to the AnnotatedDependency
-        dependents.addAll(AnnotatedDependency.getDependencies(this));
-    }
-
     boolean isModuleDependence(Klass k) {
         Module m = k.getModule();
         return m == null || (!classes.contains(k) && !m.isBase());
     }
 

@@ -531,56 +294,24 @@
 
         }
         return null;
     }
 
-    <P> void visitMember(Set<Module> visited, Visitor<P> visitor, P p) {
+    <P> void visitMembers(Set<Module> visited, ModuleVisitor<P> visitor, P p) {
         if (!visited.contains(this)) {
             visited.add(this);
             visitor.preVisit(this, p);
             for (Module m : members) {
-                m.visitMember(visited, visitor, p);
+                m.visitMembers(visited, visitor, p);
                 visitor.visited(this, m, p);
             }
             visitor.postVisit(this, p);
         } else {
             throw new RuntimeException("Cycle detected: module " + this.name);
         }
     }
 
-    private Set<Module> getDepModules() {
-        Set<Module> deps = new TreeSet<Module>();
-        for (Dependency d : dependences()) {
-            if (d.dynamic || d.optional) {
-                // ignore dynamic or optional dependencies for now
-                continue;
-            }
-            deps.add(d.module());
-        }
-        for (RequiresModule req : requires) {
-            if (req.optional) {
-                // ignore optional dependencies for now
-                continue;
-            }
-            deps.add(req.module());
-        }
-        return deps;
-    }
-
-    <P> void visitDependence(Set<Module> visited, Visitor<P> visitor, P p) {
-        if (!visited.contains(this)) {
-            visited.add(this);
-
-            visitor.preVisit(this, p);
-            for (Module m : getDepModules()) {
-                m.visitDependence(visited, visitor, p);
-                visitor.visited(this, m, p);
-            }
-            visitor.postVisit(this, p);
-        }
-    }
-
     void addMember(Module m) {
         // merge class list
         for (Klass k : m.classes) {
             classes.add(k);
         }

@@ -587,30 +318,12 @@
 
         // merge resource list
         for (ResourceFile res : m.resources) {
             resources.add(res);
         }
-
-        platformApiCount += m.platformApiCount;
-
-        // merge the package statistics
-        for (PackageInfo pinfo : m.getPackageInfos()) {
-            String packageName = pinfo.pkgName;
-            PackageInfo pkginfo = packages.get(packageName);
-            if (pkginfo == null) {
-                pkginfo = new PackageInfo(packageName);
-                packages.put(packageName, pkginfo);
             }
 
-            pkginfo.add(pinfo);
-        }
-
-        // merge all permits and requires set
-        permits().addAll(m.permits());
-        requires().addAll(m.requires());
-    }
-
     static void buildModuleMembers() {
         // set up module member relationship
         for (Module m : modules.values()) {
             m.group = m; // initialize to itself
             for (String name : m.config.members()) {

@@ -621,11 +334,11 @@
                 m.members.add(member);
             }
         }
 
         // set up the top-level module
-        Visitor<Module> groupSetter = new Visitor<Module>() {
+        ModuleVisitor<Module> groupSetter = new ModuleVisitor<Module>() {
 
             public void preVisit(Module m, Module p) {
                 m.group = p;
                 if (p.isBaseModule) {
                     // all members are also base

@@ -644,16 +357,16 @@
 
         // propagate the top-level module to all its members
         for (Module p : modules.values()) {
             for (Module m : p.members) {
                 if (m.group == m) {
-                    m.visitMember(new TreeSet<Module>(), groupSetter, p);
+                    m.visitMembers(new TreeSet<Module>(), groupSetter, p);
                 }
             }
         }
 
-        Visitor<Module> mergeClassList = new Visitor<Module>() {
+        ModuleVisitor<Module> mergeClassList = new ModuleVisitor<Module>() {
 
             public void preVisit(Module m, Module p) {
                 // nop - depth-first search
             }
 

@@ -670,522 +383,46 @@
         for (Module m : modules.values()) {
             if (m.group() == m) {
                 groups.add(m);
                 if (m.members().size() > 0) {
                     // merge class list from all its members
-                    m.visitMember(visited, mergeClassList, m);
+                    m.visitMembers(visited, mergeClassList, m);
                 }
-
-                // clear the dependencies before fixup
-                m.dependents.clear();
-
-                // fixup dependencies
-                for (Klass k : m.classes) {
-                    for (Klass other : k.getReferencedClasses()) {
-                        if (m.isModuleDependence(other)) {
-                            // this module is dependent on otherModule
-                            m.addDependency(k, other);
                         }
                     }
                 }
 
-                // add dependency due to the main class
-                Klass k = m.mainClass();
-                if (k != null && m.isModuleDependence(k)) {
-                    m.dependents.add(new Dependency(k.getModule().group(), false, false));
-                }
 
-                // add dependencies that this klass may depend on due to the AnnotatedDependency
-                m.fixupAnnotatedDependencies();
+    ModuleInfo getModuleInfo() {
+        return minfo;
             }
-        }
-    }
 
-    Set<Module> orderedDependencies() {
-        Visitor<Set<Module>> walker = new Visitor<Set<Module>>() {
-
-            public void preVisit(Module m, Set<Module> result) {
-                // nop - depth-first search
+    void setModuleInfo(ModuleInfo mi) {
+        if (minfo != null)
+            throw new AssertionError("ModuleInfo already created for " + name);
+        minfo = mi;
             }
 
-            public void visited(Module m, Module child, Set<Module> result) {
-            }
+    public interface Visitor<R, P> {
 
-            public void postVisit(Module m, Set<Module> result) {
-                result.add(m);
-            }
-        };
+        R visitClass(Klass k, P p);
 
-        Set<Module> visited = new TreeSet<Module>();
-        Set<Module> result = new LinkedHashSet<Module>();
-
-        visitDependence(visited, walker, result);
-        return result;
+        R visitResource(ResourceFile r, P p);
     }
 
-    class PackageInfo implements Comparable {
-
-        final String pkgName;
-        int count;
-        long filesize;
-
-        PackageInfo(String name) {
-            this.pkgName = name;
-            this.count = 0;
-            this.filesize = 0;
-        }
-
-        void add(PackageInfo pkg) {
-            this.count += pkg.count;
-            this.filesize += pkg.filesize;
-        }
-
-        void add(long size) {
-            count++;
-            filesize += size;
-
-        }
-
-        @Override
-        public int compareTo(Object o) {
-            return pkgName.compareTo(((PackageInfo) o).pkgName);
-        }
-    }
-
-    Set<PackageInfo> getPackageInfos() {
-        return new TreeSet<PackageInfo>(packages.values());
-    }
-
-    void printSummaryTo(String output) throws IOException {
-        PrintWriter writer = new PrintWriter(output);
-        try {
-            long total = 0L;
-            int count = 0;
-            int nonCoreAPIs = 0;
-            writer.format("%10s\t%10s\t%s%n", "Bytes", "Classes", "Package name");
-            for (String pkg : packages.keySet()) {
-                PackageInfo info = packages.get(pkg);
-                if (info.count > 0) {
-                    if (Platform.isNonCoreAPI(pkg)) {
-                        nonCoreAPIs += info.count;
-                        writer.format("%10d\t%10d\t%s (*)%n",
-                                info.filesize, info.count, pkg);
-                    } else {
-                        writer.format("%10d\t%10d\t%s%n",
-                                info.filesize, info.count, pkg);
-                    }
-                    total += info.filesize;
-                    count += info.count;
-                }
-            }
-
-
-            writer.format("%nTotal: %d bytes (uncompressed) %d classes%n",
-                    total, count);
-            writer.format("APIs: %d core %d non-core (*)%n",
-                    platformApiCount, nonCoreAPIs);
-        } finally {
-            writer.close();
-        }
-
-    }
-
-    void printClassListTo(String output) throws IOException {
-        if (classes.isEmpty()) {
-            return;
-        }
-
-        PrintWriter writer = new PrintWriter(output);
-        try {
+    public <R, P> void visit(Visitor<R, P> visitor, P p) {
             for (Klass c : classes) {
-                if (c.exists()) {
-                    writer.format("%s\n", c.getClassFilePathname());
-                } else {
-                    trace("%s in module %s missing\n", c, this);
+            visitor.visitClass(c, p);
                 }
-            }
-
-        } finally {
-            writer.close();
-        }
-
-    }
-
-    void printResourceListTo(String output) throws IOException {
-        // no file created if the module doesn't have any resource file
-        if (resources.isEmpty()) {
-            return;
-        }
-
-        PrintWriter writer = new PrintWriter(output);
-        try {
             for (ResourceFile res : resources) {
-                writer.format("%s\n", res.getPathname());
+            visitor.visitResource(res, p);
             }
-
-        } finally {
-            writer.close();
         }
 
-    }
-
-    void printDependenciesTo(String output, boolean showDynamic) throws IOException {
-        PrintWriter writer = new PrintWriter(output);
-        try {
-            // classes that this klass may depend on due to the AnnotatedDependency
-            Map<Reference, Set<AnnotatedDependency>> annotatedDeps = AnnotatedDependency.getReferences(this);
-
-            for (Klass klass : classes) {
-                Set<Klass> references = klass.getReferencedClasses();
-                for (Klass other : references) {
-                    String classname = klass.getClassName();
-                    boolean optional = OptionalDependency.isOptional(klass, other);
-                    if (optional) {
-                        classname = "[optional] " + classname;
-                    }
-
-                    Module m = getModuleDependence(other);
-                    if (m != null || other.getModule() == null) {
-                        writer.format("%-40s -> %s (%s)", classname, other, m);
-                        Reference ref = new Reference(klass, other);
-                        if (annotatedDeps.containsKey(ref)) {
-                            for (AnnotatedDependency ad : annotatedDeps.get(ref)) {
-                                writer.format(" %s", ad.getTag());
-                            }
-                            // printed; so remove the dependency from the annotated deps list
-                            annotatedDeps.remove(ref);
-                        }
-                        writer.format("\n");
-                    }
-                }
-            }
-
-            // print remaining dependencies specified in AnnotatedDependency list
-            if (annotatedDeps.size() > 0) {
-                for (Map.Entry<Reference, Set<AnnotatedDependency>> entry : annotatedDeps.entrySet()) {
-                    Reference ref = entry.getKey();
-                    Module m = getModuleDependence(ref.referree);
-                    if (m != null || ref.referree.getModule() == null) {
-                        String classname = ref.referrer.getClassName();
-                        boolean optional = true;
-                        boolean dynamic = true;
-                        String tag = "";
-                        for (AnnotatedDependency ad : entry.getValue()) {
-                            if (optional && !ad.isOptional()) {
-                                optional = false;
-                                tag = ad.getTag();
-                            }
-
-                            if (!ad.isDynamic()) {
-                                dynamic = false;
-                            }
-                        }
-                        if (!showDynamic && optional && dynamic) {
-                            continue;
-                        }
-
-                        if (optional) {
-                            classname = "[optional] " + classname;
-                        } else if (dynamic) {
-                            classname = "[dynamic] " + classname;
-                        }
-                        writer.format("%-40s -> %s (%s) %s%n", classname, ref.referree, m, tag);
-                    }
-                }
-            }
-        } finally {
-            writer.close();
-        }
-
-    }
-
-    // print module dependency list
-    void printDepModuleListTo(String output) throws IOException {
-        PrintWriter writer = new PrintWriter(output);
-        try {
-            for (Module m : orderedDependencies()) {
-                writer.format("%s\n", m.name());
-            }
-            if (Platform.legacyModule() != null &&
-                    (this == Platform.jdkBaseModule() ||
-                    this == Platform.jdkModule() ||
-                    this == Platform.jreModule())) {
-                // add legacy module in the modules.list
-                // so that it will install legacy module as well.
-                writer.format("%s\n", Platform.legacyModule());
-            }
-        } finally {
-            writer.close();
-        }
-    }
-
-    void printModuleInfoTo(String output) throws IOException {
-        PrintWriter writer = new PrintWriter(output);
-        try {
-            writer.format("module %s @ %s {%n", name, version);
-            String formatSep = "    requires";
-            Map<String, RequiresModule> reqs = new TreeMap<String, RequiresModule>();
-            for (RequiresModule rm : requires()) {
-                reqs.put(rm.module().name(), rm);
-            }
-
-            for (Dependency dep : dependences()) {
-                Module dm = dep.module();
-                if (!isBootConnected()) {
-                    // If it's a local module requiring jdk.boot, retain
-                    // the original requires
-                    dm = dm.toRequiredModule();
-                }
-
-                if (dm == null) {
-                    System.err.format("WARNING: module %s has a dependency on null module%n", name);
-                }
-
-                StringBuilder attributes = new StringBuilder();
-                RequiresModule rm = reqs.get(dm.name());
-
-                if (rm != null && rm.reexport) {
-                    attributes.append(" public");
-                }
-
-                if (isBootConnected() || (rm != null && rm.local)) {
-                    attributes.append(" local");
-                }
-
-                if (dep.optional || (rm != null && rm.optional)) {
-                    attributes.append(" optional");
-                }
-
-                // FIXME: ignore dynamic dependencies
-                // Filter out optional dependencies for the boot module
-                // which are addded in the jdk.base module instead
-                if (!dep.dynamic || dep.optional) {
-                    reqs.remove(dm.name());
-                    writer.format("%s%s %s @ %s;%n",
-                            formatSep,
-                            attributes.toString(),
-                            dep != null ? dm : "null", version);
-                }
-
-            }
-            // additional requires
-            if (reqs.size() > 0) {
-                for (RequiresModule rm : reqs.values()) {
-                    StringBuilder attributes = new StringBuilder();
-                    if (rm.reexport) {
-                        attributes.append(" public");
-                    }
-                    if (rm.optional) {
-                        attributes.append(" optional");
-                    }
-                    if (isBootConnected() || rm.local) {
-                        attributes.append(" local");
-                    }
-
-                    writer.format("%s%s %s @ %s;%n", formatSep, attributes.toString(), rm.module(), version);
-                }
-            }
-
-            // permits
-            if (permits().size() > 0) {
-                formatSep = "    permits";
-                for (Module p : permits()) {
-                    writer.format("%s %s", formatSep, p);
-                    formatSep = ",";
-                }
-                writer.format(";%n");
-            }
-            if (mainClass() != null) {
-                writer.format("    class %s;%n", mainClass().getClassName());
-            }
-            writer.format("}%n");
-        } finally {
-            writer.close();
-        }
-    }
-
-    static class Dependency implements Comparable<Dependency> {
-
-        protected Module module;
-        final boolean optional;
-        final boolean dynamic;
-
-        Dependency(Klass from, Klass to) {
-            // static dependency
-            this.module = to.getModule() != null ? to.getModule().group() : null;
-            this.optional = OptionalDependency.isOptional(from, to);
-            this.dynamic = false;
-        }
-
-        Dependency(Module m, boolean optional, boolean dynamic) {
-            this.module = m != null ? m.group() : null;
-            this.optional = optional;
-            this.dynamic = dynamic;
-        }
-
-        Module module() {
-            return module;
-        }
-
-        public boolean isLocal(Module from) {
-            if (module().isBootConnected()) {
-                // local requires if the requesting module is the boot module
-                // or it's an aggregate platform module
-                return true;
-            }
-
-            for (PackageInfo pkg : from.getPackageInfos()) {
-                // local dependence if any package this module owns is splitted
-                // across its dependence
-                for (PackageInfo p : module().getPackageInfos()) {
-                    if (pkg.pkgName.equals(p.pkgName)) {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof Dependency)) {
-                return false;
-            }
-            if (this == obj) {
-                return true;
-            }
-
-            Dependency d = (Dependency) obj;
-            if (this.module() != d.module()) {
-                return false;
-            } else {
-                return this.optional == d.optional && this.dynamic == d.dynamic;
-            }
-        }
-
-        @Override
-        public int hashCode() {
-            int hash = 3;
-            hash = 19 * hash + (this.module() != null ? this.module().hashCode() : 0);
-            hash = 19 * hash + (this.optional ? 1 : 0);
-            hash = 19 * hash + (this.dynamic ? 1 : 0);
-            return hash;
-        }
-
-        @Override
-        public int compareTo(Dependency d) {
-            if (this.equals(d)) {
-                return 0;
-            }
-
-            // Hard static > hard dynamic > optional static > optional dynamic
-            if (this.module() == d.module()) {
-                if (this.optional == d.optional) {
-                    return this.dynamic ? -1 : 1;
-                } else {
-                    return this.optional ? -1 : 1;
-                }
-            } else if (this.module() != null && d.module() != null) {
-                return (this.module().compareTo(d.module()));
-            } else {
-                return (this.module() == null) ? -1 : 1;
-            }
-        }
-
-        @Override
-        public String toString() {
-            String s = module().name();
-            if (optional) {
-                s += " (optional)";
-            } else if (dynamic) {
-                s += " (dynamic)";
-            }
-            return s;
-        }
-    }
-
-    static class RequiresModule extends Dependency {
-
-        final String modulename;
-        final boolean reexport;
-        final boolean local;
-
-        public RequiresModule(String name, boolean optional, boolean reexport, boolean local) {
-            super(null, optional, false /* dynamic */);
-            this.modulename = name;
-            this.reexport = reexport;
-            this.local = local;
-        }
-
-        public RequiresModule(Module m, boolean optional) {
-            super(m, optional, false);
-            this.modulename = m.name();
-            this.reexport = true;
-            this.local = false;
-        }
-
-        // deferred initialization until it's called.
-        // must call after all modules are merged.
-        synchronized Module fixupModule() {
-            if (module == null) {
-                Module m = findModule(modulename);
-                if (m == null) {
-                    throw new RuntimeException("Required module \"" + modulename + "\" doesn't exist");
-                }
-                module = m.group();
-            }
-            return module;
-        }
-
-        @Override
-        Module module() {
-            return fixupModule();
-        }
-
-        @Override
-        public int compareTo(Dependency d) {
-            RequiresModule rm = (RequiresModule) d;
-            if (this.equals(rm)) {
-                return 0;
-            }
-            return modulename.compareTo(rm.modulename);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof RequiresModule)) {
-                return false;
-            }
-            if (this == obj) {
-                return true;
-            }
-
-            RequiresModule d = (RequiresModule) obj;
-            return this.modulename.equals(d.modulename);
-        }
-
-        @Override
-        public int hashCode() {
-            int hash = 3;
-            hash = 19 * hash + this.modulename.hashCode();
-            return hash;
-        }
-
-        @Override
-        public String toString() {
-            String s = reexport ? "public " : "";
-            if (optional) {
-                s += "optional ";
-            }
-            s += modulename;
-            return s;
-        }
-    }
-
     static class Reference implements Comparable<Reference> {
 
-        private final Klass referrer, referree;
+        final Klass referrer, referree;
 
         Reference(Klass referrer, Klass referree) {
             this.referrer = referrer;
             this.referree = referree;
         }

@@ -1224,11 +461,11 @@
             }
             return ret;
         }
     }
 
-    interface Visitor<P> {
+    interface ModuleVisitor<P> {
 
         public void preVisit(Module m, P param);
 
         public void visited(Module m, Module child, P param);