changeset 2598:097bc67c0099 default tip

Merge
author henryjen
date Mon, 11 Nov 2013 23:16:35 -0800
parents 6b4d6205366c (diff) be4bcbd410e9 (current diff)
children
files .hgtags .jcheck/conf test/tools/javac/Diagnostics/compressed/T8012003c.java test/tools/javac/Diagnostics/compressed/T8012003c.out test/tools/javac/defaultMethods/TestNoBridgeOnDefaults.java test/tools/javac/defaultMethods/separate/Separate.java test/tools/javac/diags/examples/BadArgTypesInLambda.java test/tools/javac/lambdaShapes/org/openjdk/tests/separate/Compiler.java test/tools/javac/lambdaShapes/org/openjdk/tests/separate/SourceModel.java test/tools/javac/lambdaShapes/org/openjdk/tests/separate/TestHarness.java test/tools/javac/lambdaShapes/org/openjdk/tests/vm/DefaultMethodsTest.java
diffstat 18 files changed, 571 insertions(+), 239 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu Oct 31 14:07:48 2013 -0400
+++ b/.hgtags	Mon Nov 11 23:16:35 2013 -0800
@@ -239,3 +239,4 @@
 af6244ba81b6b8d1bf4ab06587a2067e021e4570 jdk8-b111
 954dd199d6ff3e4cfc42b894c1f611150526eecd jdk8-b112
 54150586ba785e1eb0c0de8d13906f643f640644 jdk8-b113
+850d2602ae9811687b0f404d05ec3e55df91d9cb jdk8-b114
--- a/src/share/classes/com/sun/tools/jdeps/Analyzer.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/src/share/classes/com/sun/tools/jdeps/Analyzer.java	Mon Nov 11 23:16:35 2013 -0800
@@ -26,9 +26,11 @@
 
 import com.sun.tools.classfile.Dependency.Location;
 import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
@@ -52,7 +54,7 @@
 
     private final Type type;
     private final Map<Archive, ArchiveDeps> results = new HashMap<>();
-    private final Map<String, Archive> map = new HashMap<>();
+    private final Map<Location, Archive> map = new HashMap<>();
     private final Archive NOT_FOUND
         = new Archive(JdepsTask.getMessage("artifact.not.found"));
 
@@ -69,6 +71,17 @@
      * Performs the dependency analysis on the given archives.
      */
     public void run(List<Archive> archives) {
+        // build a map from Location to Archive
+        for (Archive archive: archives) {
+            for (Location l: archive.getClasses()) {
+                if (!map.containsKey(l)) {
+                    map.put(l, archive);
+                } else {
+                    // duplicated class warning?
+                }
+            }
+        }
+        // traverse and analyze all dependencies
         for (Archive archive : archives) {
             ArchiveDeps deps;
             if (type == Type.CLASS || type == Type.VERBOSE) {
@@ -76,33 +89,9 @@
             } else {
                 deps = new PackageVisitor(archive);
             }
-            archive.visit(deps);
+            archive.visitDependences(deps);
             results.put(archive, deps);
         }
-
-        // set the required dependencies
-        for (ArchiveDeps result: results.values()) {
-            for (Set<String> set : result.deps.values()) {
-                for (String target : set) {
-                    Archive source = getArchive(target);
-                    if (result.archive != source) {
-                        String profile = "";
-                        if (source instanceof JDKArchive) {
-                            profile = result.profile != null ? result.profile.toString() : "";
-                            if (result.getTargetProfile(target) == null) {
-                                profile += ", JDK internal API";
-                                // override the value if it accesses any JDK internal
-                                result.requireArchives.put(source, profile);
-                                continue;
-                            }
-                        }
-                        if (!result.requireArchives.containsKey(source)) {
-                            result.requireArchives.put(source, profile);
-                        }
-                    }
-                }
-            }
-        }
     }
 
     public boolean hasDependences(Archive archive) {
@@ -117,94 +106,143 @@
          * Visits the source archive to its destination archive of
          * a recorded dependency.
          */
-        void visitArchiveDependence(Archive origin, Archive target, String profile);
+        void visitArchiveDependence(Archive origin, Archive target, Profile profile);
         /**
          * Visits a recorded dependency from origin to target which can be
          * a fully-qualified classname, a package name, a profile or
          * archive name depending on the Analyzer's type.
          */
-        void visitDependence(String origin, Archive source, String target, Archive archive, String profile);
+        void visitDependence(String origin, Archive source, String target, Archive archive, Profile profile);
     }
 
     public void visitArchiveDependences(Archive source, Visitor v) {
         ArchiveDeps r = results.get(source);
-        for (Map.Entry<Archive,String> e : r.requireArchives.entrySet()) {
-            v.visitArchiveDependence(r.archive, e.getKey(), e.getValue());
+        for (ArchiveDeps.Dep d: r.requireArchives()) {
+            v.visitArchiveDependence(r.archive, d.archive, d.profile);
         }
     }
 
     public void visitDependences(Archive source, Visitor v) {
         ArchiveDeps r = results.get(source);
-        for (String origin : r.deps.keySet()) {
-            for (String target : r.deps.get(origin)) {
-                Archive archive = getArchive(target);
-                assert source == getArchive(origin);
-                Profile profile = r.getTargetProfile(target);
-
+        for (Map.Entry<String, SortedSet<ArchiveDeps.Dep>> e: r.deps.entrySet()) {
+            String origin = e.getKey();
+            for (ArchiveDeps.Dep d: e.getValue()) {
                 // filter intra-dependency unless in verbose mode
-                if (type == Type.VERBOSE || archive != source) {
-                    v.visitDependence(origin, source, target, archive,
-                                      profile != null ? profile.toString() : "");
+                if (type == Type.VERBOSE || d.archive != source) {
+                    v.visitDependence(origin, source, d.target, d.archive, d.profile);
                 }
             }
         }
     }
 
-    public Archive getArchive(String name) {
-        return map.containsKey(name) ? map.get(name) : NOT_FOUND;
-    }
-
+    /**
+     * ArchiveDeps contains the dependencies for an Archive that
+     * can have one or more classes.
+     */
     private abstract class ArchiveDeps implements Archive.Visitor {
         final Archive archive;
-        final Map<Archive,String> requireArchives;
-        final SortedMap<String, SortedSet<String>> deps;
-        Profile profile = null;
+        final SortedMap<String, SortedSet<Dep>> deps;
         ArchiveDeps(Archive archive) {
             this.archive = archive;
-            this.requireArchives = new HashMap<>();
             this.deps = new TreeMap<>();
         }
 
-        void add(String loc) {
-            Archive a = map.get(loc);
-            if (a == null) {
-                map.put(loc, archive);
-            } else if (a != archive) {
-                // duplicated class warning?
-            }
-        }
-
-        void add(String origin, String target) {
-            SortedSet<String> set = deps.get(origin);
+        void add(String origin, String target, Archive targetArchive, String pkgName) {
+            SortedSet<Dep> set = deps.get(origin);
             if (set == null) {
                 deps.put(origin, set = new TreeSet<>());
             }
-            if (!set.contains(target)) {
-                set.add(target);
-                // find the corresponding profile
-                Profile p = getTargetProfile(target);
-                if (profile == null || (p != null && profile.profile < p.profile)) {
-                     profile = p;
+            Profile p = targetArchive instanceof JDKArchive
+                            ? Profile.getProfile(pkgName) : null;
+            set.add(new Dep(target, targetArchive, p));
+        }
+
+        /**
+         * Returns the list of Archive dependences.  The returned
+         * list contains one {@code Dep} instance per one archive
+         * and with the minimum profile this archive depends on.
+         */
+        List<Dep> requireArchives() {
+            Map<Archive,Profile> map = new HashMap<>();
+            for (Set<Dep> set: deps.values()) {
+                for (Dep d: set) {
+                    if (this.archive != d.archive) {
+                        Profile p = map.get(d.archive);
+                        if (p == null || (d.profile != null && p.profile < d.profile.profile)) {
+                            map.put(d.archive, d.profile);
+                        }
+                    }
                 }
             }
+            List<Dep> list = new ArrayList<>();
+            for (Map.Entry<Archive,Profile> e: map.entrySet()) {
+                list.add(new Dep("", e.getKey(), e.getValue()));
+            }
+            return list;
+        }
+
+        /**
+         * Dep represents a dependence where the target can be
+         * a classname or packagename and the archive and profile
+         * the target belongs to.
+         */
+        class Dep implements Comparable<Dep> {
+            final String target;
+            final Archive archive;
+            final Profile profile;
+            Dep(String target, Archive archive, Profile p) {
+                this.target = target;
+                this.archive = archive;
+                this.profile = p;
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (o instanceof Dep) {
+                    Dep d = (Dep)o;
+                    return this.archive == d.archive && this.target.equals(d.target);
+                }
+                return false;
+            }
+
+            @Override
+            public int hashCode() {
+                int hash = 3;
+                hash = 17 * hash + Objects.hashCode(this.archive);
+                hash = 17 * hash + Objects.hashCode(this.target);
+                return hash;
+            }
+
+            @Override
+            public int compareTo(Dep o) {
+                if (this.target.equals(o.target)) {
+                    if (this.archive == o.archive) {
+                        return 0;
+                    } else {
+                        return this.archive.getFileName().compareTo(o.archive.getFileName());
+                    }
+                }
+                return this.target.compareTo(o.target);
+            }
         }
         public abstract void visit(Location o, Location t);
-        public abstract Profile getTargetProfile(String target);
     }
 
     private class ClassVisitor extends ArchiveDeps {
         ClassVisitor(Archive archive) {
             super(archive);
         }
-        public void visit(Location l) {
-            add(l.getClassName());
-        }
+        @Override
         public void visit(Location o, Location t) {
-            add(o.getClassName(), t.getClassName());
-        }
-        public Profile getTargetProfile(String target) {
-            int i = target.lastIndexOf('.');
-            return (i > 0) ? Profile.getProfile(target.substring(0, i)) : null;
+            Archive targetArchive =
+                this.archive.getClasses().contains(t) ? this.archive : map.get(t);
+            if (targetArchive == null) {
+                map.put(t, targetArchive = NOT_FOUND);
+            }
+
+            String origin = o.getClassName();
+            String target = t.getClassName();
+            add(origin, target, targetArchive, t.getPackageName());
         }
     }
 
@@ -212,18 +250,21 @@
         PackageVisitor(Archive archive) {
             super(archive);
         }
+        @Override
         public void visit(Location o, Location t) {
-            add(packageOf(o), packageOf(t));
-        }
-        public void visit(Location l) {
-            add(packageOf(l));
+            Archive targetArchive =
+                this.archive.getClasses().contains(t) ? this.archive : map.get(t);
+            if (targetArchive == null) {
+                map.put(t, targetArchive = NOT_FOUND);
+            }
+
+            String origin = packageOf(o);
+            String target = packageOf(t);
+            add(origin, target, targetArchive, t.getPackageName());
         }
-        private String packageOf(Location loc) {
-            String pkg = loc.getPackageName();
+        public String packageOf(Location o) {
+            String pkg = o.getPackageName();
             return pkg.isEmpty() ? "<unnamed>" : pkg;
         }
-        public Profile getTargetProfile(String target) {
-            return Profile.getProfile(target);
-        }
     }
 }
--- a/src/share/classes/com/sun/tools/jdeps/Archive.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/src/share/classes/com/sun/tools/jdeps/Archive.java	Mon Nov 11 23:16:35 2013 -0800
@@ -67,6 +67,7 @@
             deps.put(origin, set);
         }
     }
+
     public void addClass(Location origin, Location target) {
         Set<Location> set = deps.get(origin);
         if (set == null) {
@@ -76,21 +77,27 @@
         set.add(target);
     }
 
-    public void visit(Visitor v) {
+    public Set<Location> getClasses() {
+        return deps.keySet();
+    }
+
+    public void visitDependences(Visitor v) {
         for (Map.Entry<Location,Set<Location>> e: deps.entrySet()) {
-            v.visit(e.getKey());
             for (Location target : e.getValue()) {
                 v.visit(e.getKey(), target);
             }
         }
     }
 
+    public String getPathName() {
+        return path != null ? path.toString() : filename;
+    }
+
     public String toString() {
-        return path != null ? path.toString() : filename;
+        return filename;
     }
 
     interface Visitor {
-        void visit(Location loc);
         void visit(Location origin, Location target);
     }
 }
--- a/src/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/src/share/classes/com/sun/tools/jdeps/JdepsTask.java	Mon Nov 11 23:16:35 2013 -0800
@@ -190,6 +190,11 @@
                 task.options.fullVersion = true;
             }
         },
+        new HiddenOption(false, "-showlabel") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.showLabel = true;
+            }
+        },
         new HiddenOption(true, "-depth") {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
                 try {
@@ -279,12 +284,21 @@
 
     private void generateDotFiles(Path dir, Analyzer analyzer) throws IOException {
         Path summary = dir.resolve("summary.dot");
-        try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary));
-             DotFileFormatter formatter = new DotFileFormatter(sw, "summary")) {
-            for (Archive archive : sourceLocations) {
-                 analyzer.visitArchiveDependences(archive, formatter);
+        boolean verbose = options.verbose == Analyzer.Type.VERBOSE;
+        DotGraph<?> graph = verbose ? new DotSummaryForPackage()
+                                    : new DotSummaryForArchive();
+        for (Archive archive : sourceLocations) {
+            analyzer.visitArchiveDependences(archive, graph);
+            if (verbose || options.showLabel) {
+                // traverse detailed dependences to generate package-level
+                // summary or build labels for edges
+                analyzer.visitDependences(archive, graph);
             }
         }
+        try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary))) {
+            graph.writeTo(sw);
+        }
+        // output individual .dot file for each archive
         if (options.verbose != Analyzer.Type.SUMMARY) {
             for (Archive archive : sourceLocations) {
                 if (analyzer.hasDependences(archive)) {
@@ -365,17 +379,16 @@
                 }
             }
         }
+        sourceLocations.addAll(archives);
 
         List<Archive> classpaths = new ArrayList<>(); // for class file lookup
+        classpaths.addAll(getClassPathArchives(options.classpath));
         if (options.includePattern != null) {
-            archives.addAll(getClassPathArchives(options.classpath));
-        } else {
-            classpaths.addAll(getClassPathArchives(options.classpath));
+            archives.addAll(classpaths);
         }
         classpaths.addAll(PlatformClassPath.getArchives());
 
-        // add all archives to the source locations for reporting
-        sourceLocations.addAll(archives);
+        // add all classpath archives to the source locations for reporting
         sourceLocations.addAll(classpaths);
 
         // Work queue of names of classfiles to be searched.
@@ -557,6 +570,7 @@
         boolean showSummary;
         boolean wildcard;
         boolean apiOnly;
+        boolean showLabel;
         String dotOutputDir;
         String classpath = "";
         int depth = 1;
@@ -627,16 +641,34 @@
         return result;
     }
 
+    /**
+     * If the given archive is JDK archive and non-null Profile,
+     * this method returns the profile name only if -profile option is specified;
+     * a null profile indicates it accesses a private JDK API and this method
+     * will return "JDK internal API".
+     *
+     * For non-JDK archives, this method returns the file name of the archive.
+     */
+    private String getProfileArchiveInfo(Archive source, Profile profile) {
+        if (options.showProfile && profile != null)
+            return profile.toString();
+
+        if (source instanceof JDKArchive) {
+            return profile == null ? "JDK internal API (" + source.getFileName() + ")" : "";
+        }
+        return source.getFileName();
+    }
 
     /**
-     * Returns the file name of the archive for non-JRE class or
-     * internal JRE classes.  It returns empty string for SE API.
+     * Returns the profile name or "JDK internal API" for JDK archive;
+     * otherwise empty string.
      */
-    private static String getArchiveName(Archive source, String profile) {
-        String name = source.getFileName();
-        if (source instanceof JDKArchive)
-            return profile.isEmpty() ? "JDK internal API (" + name + ")" : "";
-        return name;
+    private String profileName(Archive archive, Profile profile) {
+        if (archive instanceof JDKArchive) {
+            return Objects.toString(profile, "JDK internal API");
+        } else {
+            return "";
+        }
     }
 
     class RawOutputFormatter implements Analyzer.Visitor {
@@ -648,21 +680,18 @@
         private String pkg = "";
         @Override
         public void visitDependence(String origin, Archive source,
-                                    String target, Archive archive, String profile) {
+                                    String target, Archive archive, Profile profile) {
             if (!origin.equals(pkg)) {
                 pkg = origin;
                 writer.format("   %s (%s)%n", origin, source.getFileName());
             }
-            String name = (options.showProfile && !profile.isEmpty())
-                                ? profile
-                                : getArchiveName(archive, profile);
-            writer.format("      -> %-50s %s%n", target, name);
+            writer.format("      -> %-50s %s%n", target, getProfileArchiveInfo(archive, profile));
         }
 
         @Override
-        public void visitArchiveDependence(Archive origin, Archive target, String profile) {
-            writer.format("%s -> %s", origin, target);
-            if (options.showProfile && !profile.isEmpty()) {
+        public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
+            writer.format("%s -> %s", origin.getPathName(), target.getPathName());
+            if (options.showProfile && profile != null) {
                 writer.format(" (%s)%n", profile);
             } else {
                 writer.format("%n");
@@ -670,19 +699,14 @@
         }
     }
 
-    class DotFileFormatter implements Analyzer.Visitor, AutoCloseable {
+    class DotFileFormatter extends DotGraph<String> implements AutoCloseable {
         private final PrintWriter writer;
         private final String name;
-        DotFileFormatter(PrintWriter writer, String name) {
-            this.writer = writer;
-            this.name = name;
-            writer.format("digraph \"%s\" {%n", name);
-        }
         DotFileFormatter(PrintWriter writer, Archive archive) {
             this.writer = writer;
             this.name = archive.getFileName();
             writer.format("digraph \"%s\" {%n", name);
-            writer.format("    // Path: %s%n", archive.toString());
+            writer.format("    // Path: %s%n", archive.getPathName());
         }
 
         @Override
@@ -690,39 +714,169 @@
             writer.println("}");
         }
 
-        private final Set<String> edges = new HashSet<>();
-        private String node = "";
         @Override
         public void visitDependence(String origin, Archive source,
-                                    String target, Archive archive, String profile) {
-            if (!node.equals(origin)) {
-                edges.clear();
-                node = origin;
-            }
+                                    String target, Archive archive, Profile profile) {
             // if -P option is specified, package name -> profile will
             // be shown and filter out multiple same edges.
-            if (!edges.contains(target)) {
-                StringBuilder sb = new StringBuilder();
-                String name = options.showProfile && !profile.isEmpty()
-                                  ? profile
-                                  : getArchiveName(archive, profile);
-                writer.format("   %-50s -> %s;%n",
-                                 String.format("\"%s\"", origin),
-                                 name.isEmpty() ? String.format("\"%s\"", target)
-                                                :  String.format("\"%s (%s)\"", target, name));
-                edges.add(target);
+            String name = getProfileArchiveInfo(archive, profile);
+            writeEdge(writer, new Edge(origin, target, getProfileArchiveInfo(archive, profile)));
+        }
+        @Override
+        public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    class DotSummaryForArchive extends DotGraph<Archive> {
+        @Override
+        public void visitDependence(String origin, Archive source,
+                                    String target, Archive archive, Profile profile) {
+            Edge e = findEdge(source, archive);
+            assert e != null;
+            // add the dependency to the label if enabled and not compact1
+            if (profile == Profile.COMPACT1) {
+                return;
+            }
+            e.addLabel(origin, target, profileName(archive, profile));
+        }
+        @Override
+        public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
+            // add an edge with the archive's name with no tag
+            // so that there is only one node for each JDK archive
+            // while there may be edges to different profiles
+            Edge e = addEdge(origin, target, "");
+            if (target instanceof JDKArchive) {
+                // add a label to print the profile
+                if (profile == null) {
+                    e.addLabel("JDK internal API");
+                } else if (options.showProfile && !options.showLabel) {
+                    e.addLabel(profile.toString());
+                }
             }
         }
+    }
 
+    // DotSummaryForPackage generates the summary.dot file for verbose mode
+    // (-v or -verbose option) that includes all class dependencies.
+    // The summary.dot file shows package-level dependencies.
+    class DotSummaryForPackage extends DotGraph<String> {
+        private String packageOf(String cn) {
+            int i = cn.lastIndexOf('.');
+            return i > 0 ? cn.substring(0, i) : "<unnamed>";
+        }
+        @Override
+        public void visitDependence(String origin, Archive source,
+                                    String target, Archive archive, Profile profile) {
+            // add a package dependency edge
+            String from = packageOf(origin);
+            String to = packageOf(target);
+            Edge e = addEdge(from, to, getProfileArchiveInfo(archive, profile));
+
+            // add the dependency to the label if enabled and not compact1
+            if (!options.showLabel || profile == Profile.COMPACT1) {
+                return;
+            }
+
+            // trim the package name of origin to shorten the label
+            int i = origin.lastIndexOf('.');
+            String n1 = i < 0 ? origin : origin.substring(i+1);
+            e.addLabel(n1, target, profileName(archive, profile));
+        }
         @Override
-        public void visitArchiveDependence(Archive origin, Archive target, String profile) {
-             String name = options.showProfile && !profile.isEmpty()
-                                ? profile : "";
-             writer.format("   %-30s -> \"%s\";%n",
-                           String.format("\"%s\"", origin.getFileName()),
-                           name.isEmpty()
-                               ? target.getFileName()
-                               : String.format("%s (%s)", target.getFileName(), name));
+        public void visitArchiveDependence(Archive origin, Archive target, Profile profile) {
+            // nop
+        }
+    }
+    abstract class DotGraph<T> implements Analyzer.Visitor  {
+        private final Set<Edge> edges = new LinkedHashSet<>();
+        private Edge curEdge;
+        public void writeTo(PrintWriter writer) {
+            writer.format("digraph \"summary\" {%n");
+            for (Edge e: edges) {
+                writeEdge(writer, e);
+            }
+            writer.println("}");
+        }
+
+        void writeEdge(PrintWriter writer, Edge e) {
+            writer.format("   %-50s -> \"%s\"%s;%n",
+                          String.format("\"%s\"", e.from.toString()),
+                          e.tag.isEmpty() ? e.to
+                                          : String.format("%s (%s)", e.to, e.tag),
+                          getLabel(e));
+        }
+
+        Edge addEdge(T origin, T target, String tag) {
+            Edge e = new Edge(origin, target, tag);
+            if (e.equals(curEdge)) {
+                return curEdge;
+            }
+
+            if (edges.contains(e)) {
+                for (Edge e1 : edges) {
+                   if (e.equals(e1)) {
+                       curEdge = e1;
+                   }
+                }
+            } else {
+                edges.add(e);
+                curEdge = e;
+            }
+            return curEdge;
+        }
+
+        Edge findEdge(T origin, T target) {
+            for (Edge e : edges) {
+                if (e.from.equals(origin) && e.to.equals(target)) {
+                    return e;
+                }
+            }
+            return null;
+        }
+
+        String getLabel(Edge e) {
+            String label = e.label.toString();
+            return label.isEmpty() ? "" : String.format("[label=\"%s\",fontsize=9]", label);
+        }
+
+        class Edge {
+            final T from;
+            final T to;
+            final String tag;  // optional tag
+            final StringBuilder label = new StringBuilder();
+            Edge(T from, T to, String tag) {
+                this.from = from;
+                this.to = to;
+                this.tag = tag;
+            }
+            void addLabel(String s) {
+                label.append(s).append("\\n");
+            }
+            void addLabel(String origin, String target, String profile) {
+                label.append(origin).append(" -> ").append(target);
+                if (!profile.isEmpty()) {
+                    label.append(" (" + profile + ")");
+                }
+                label.append("\\n");
+            }
+            @Override @SuppressWarnings("unchecked")
+            public boolean equals(Object o) {
+                if (o instanceof DotGraph<?>.Edge) {
+                    DotGraph<?>.Edge e = (DotGraph<?>.Edge)o;
+                    return this.from.equals(e.from) &&
+                           this.to.equals(e.to) &&
+                           this.tag.equals(e.tag);
+                }
+                return false;
+            }
+            @Override
+            public int hashCode() {
+                int hash = 7;
+                hash = 67 * hash + Objects.hashCode(this.from) +
+                       Objects.hashCode(this.to) + Objects.hashCode(this.tag);
+                return hash;
+            }
         }
     }
 }
--- a/src/share/classes/com/sun/tools/jdeps/Profile.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/src/share/classes/com/sun/tools/jdeps/Profile.java	Mon Nov 11 23:16:35 2013 -0800
@@ -81,8 +81,12 @@
     }
 
     static class PackageToProfile {
+        static String[] JAVAX_CRYPTO_PKGS = new String[] {
+            "javax.crypto",
+            "javax.crypto.interfaces",
+            "javax.crypto.spec"
+        };
         static Map<String, Profile> map = initProfiles();
-
         private static Map<String, Profile> initProfiles() {
             try {
                 String profilesProps = System.getProperty("jdeps.profiles");
@@ -103,6 +107,9 @@
                                 findProfile(cf);
                             }
                         }
+                        // special case for javax.crypto.* classes that are not
+                        // included in ct.sym since they are in jce.jar
+                        Collections.addAll(Profile.COMPACT1.packages, JAVAX_CRYPTO_PKGS);
                     }
                 }
             } catch (IOException | ConstantPoolException e) {
--- a/test/tools/javac/ExtDirs/ExtDirTest.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/test/tools/javac/ExtDirs/ExtDirTest.java	Mon Nov 11 23:16:35 2013 -0800
@@ -112,11 +112,6 @@
     }
 
     void createJars() throws Exception {
-
-//        for i in 1 2 3; do
-//            if test ! -d ext${i}; then mkdir ext${i}; fi
-//            cp ${TESTSRC}${FS}ext${i}${FS}*.jar ext${i}
-//        done
         sun.tools.jar.Main jarGenerator =
                 new sun.tools.jar.Main(System.out, System.err, "jar");
 
@@ -155,19 +150,19 @@
 
     void compileWithExtDirs() throws Exception {
 
-//"$javac" ${TESTTOOLVMOPTS} -d . -extdirs ext1 "${TESTSRC}${FS}ExtDirTest_1.java"
+//javac -extdirs ext1 ExtDirTest_1.java
         ToolBox.JavaToolArgs params =
                 new ToolBox.JavaToolArgs()
                 .setOptions("-d", ".", "-extdirs", "ext1")
                 .setSources(ExtDirTest_1Src);
         ToolBox.javac(params);
 
-//"$javac" ${TESTTOOLVMOPTS} -d . -extdirs ext1${PS}ext2 "${TESTSRC}${FS}ExtDirTest_2.java"
+//javac -extdirs ext1:ext2 ExtDirTest_2.java
         params.setOptions("-d", ".", "-extdirs", "ext1" + File.pathSeparator + "ext2")
                 .setSources(ExtDirTest_2Src);
         ToolBox.javac(params);
 
-//"$javac" ${TESTTOOLVMOPTS} -d . -extdirs ext3 "${TESTSRC}${FS}ExtDirTest_3.java"
+//javac -extdirs ext3 ExtDirTest_3.java
         params.setOptions("-d", ".", "-extdirs", "ext3")
                 .setSources(ExtDirTest_3Src);
         ToolBox.javac(params);
Binary file test/tools/javac/ExtDirs/ext1/pkg1.jar has changed
Binary file test/tools/javac/ExtDirs/ext2/pkg2.jar has changed
Binary file test/tools/javac/ExtDirs/ext3/pkg1.jar has changed
Binary file test/tools/javac/ExtDirs/ext3/pkg2.jar has changed
--- a/test/tools/javac/lambdaShapes/org/openjdk/tests/separate/Compiler.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/test/tools/javac/lambdaShapes/org/openjdk/tests/separate/Compiler.java	Mon Nov 11 23:16:35 2013 -0800
@@ -46,7 +46,7 @@
         USECACHE // Keeps results around for reuse.  Only use this is
                  // you're sure that each compilation name maps to the
                  // same source code
-    };
+    }
 
     private static final AtomicInteger counter = new AtomicInteger();
     private static final String targetDir = "gen-separate";
@@ -85,7 +85,7 @@
     }
 
     public void setFlags(Flags ... flags) {
-        this.flags = new HashSet<Flags>(Arrays.asList(flags));
+        this.flags = new HashSet<>(Arrays.asList(flags));
     }
 
     public void addPostprocessor(ClassFilePreprocessor cfp) {
@@ -131,17 +131,10 @@
         outputDirs.put(type.getName(), outDir);
 
         Class superClass = type.getSuperclass();
-        if (superClass != null) {
-            for( Map.Entry<String,File> each : compileHierarchy(superClass).entrySet()) {
-                outputDirs.put(each.getKey(), each.getValue());
-            }
-        }
-        for (Extends ext : type.getSupertypes()) {
-            Type iface = ext.getType();
-            for( Map.Entry<String,File> each : compileHierarchy(iface).entrySet()) {
-                outputDirs.put(each.getKey(), each.getValue());
-            }
-        }
+        if (superClass != null)
+            outputDirs.putAll(compileHierarchy(superClass));
+        for (Extends ext : type.getSupertypes())
+            outputDirs.putAll(compileHierarchy(ext.getType()));
 
         return outputDirs;
     }
@@ -157,8 +150,12 @@
         SourceProcessor accum =
             (name, src) -> { files.add(new SourceFile(name, src)); };
 
-        for (Type dep : type.typeDependencies()) {
-            dep.generateAsDependency(accum, type.methodDependencies());
+        Collection<Type> deps = type.typeDependencies(type.isFullCompilation());
+        for (Type dep : deps) {
+            if (type.isFullCompilation())
+                dep.generate(accum);
+            else
+                dep.generateAsDependency(accum, type.methodDependencies());
         }
 
         type.generate(accum);
@@ -185,7 +182,7 @@
                 StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir));
         } catch (IOException e) {
             throw new RuntimeException(
-                "IOException encountered during compilation");
+                "IOException encountered during compilation", e);
         }
         Boolean result = ct.call();
         if (result == Boolean.FALSE) {
--- a/test/tools/javac/lambdaShapes/org/openjdk/tests/separate/SourceModel.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/test/tools/javac/lambdaShapes/org/openjdk/tests/separate/SourceModel.java	Mon Nov 11 23:16:35 2013 -0800
@@ -48,7 +48,7 @@
             generate(pw);
             return sw.toString();
         }
-    };
+    }
 
     public static class AccessFlag extends Element {
         private String flag;
@@ -125,6 +125,7 @@
         // (and thus will be present in stubs)
         private Set<Method> methodDependencies;
         private List<Type> typeDependencies;
+        private boolean fullCompilation;
 
         protected Type(String name,
                 List<AccessFlag> flags, List<TypeParameter> params,
@@ -214,6 +215,14 @@
             methodDependencies.add(m);
         }
 
+        public boolean isFullCompilation() {
+            return fullCompilation;
+        }
+
+        public void setFullCompilation(boolean fullCompilation) {
+            this.fullCompilation = fullCompilation;
+        }
+
         // Convenience method for creating an Extends object using this
         // class and specified type arguments.
         public Extends with(String ... args) {
@@ -255,14 +264,23 @@
             pw.println("}");
         }
 
-        public Collection<Type> typeDependencies() {
+        public Collection<Type> typeDependencies(boolean recursive) {
             HashMap<String,Type> dependencies = new HashMap<>();
             Type superclass = getSuperclass();
             if (superclass != null) {
                 dependencies.put(superclass.getName(), superclass);
+                if (recursive) {
+                    for (Type t : superclass.typeDependencies(true))
+                        dependencies.put(t.getName(), t);
+                }
             }
-            for (Extends e : getSupertypes())
+            for (Extends e : getSupertypes()) {
                 dependencies.put(e.getType().getName(), e.getType());
+                if (recursive) {
+                    for (Type t : e.getType().typeDependencies(true))
+                        dependencies.put(t.getName(), t);
+                }
+            }
             // Do these last so that they override
             for (Type t : this.typeDependencies)
                 dependencies.put(t.getName(), t);
--- a/test/tools/javac/lambdaShapes/org/openjdk/tests/separate/TestHarness.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/test/tools/javac/lambdaShapes/org/openjdk/tests/separate/TestHarness.java	Mon Nov 11 23:16:35 2013 -0800
@@ -198,7 +198,7 @@
                 assertEquals(res, value);
             }
         } catch (InvocationTargetException | IllegalAccessException e) {
-            fail("Unexpected exception thrown: " + e.getCause());
+            fail("Unexpected exception thrown: " + e.getCause(), e.getCause());
         }
     }
 
@@ -227,8 +227,7 @@
      * a return type of 'int', and no arguments.
      */
     public void assertInvokeVirtualEquals(int value, Class target) {
-        assertInvokeVirtualEquals(
-            new Integer(value), target, stdCM, "-1");
+        assertInvokeVirtualEquals(value, target, stdCM, "-1");
     }
 
     /**
@@ -260,12 +259,31 @@
         Compiler compiler = compilerLocal.get();
         compiler.setFlags(compilerFlags());
 
-        assertInvokeInterfaceEquals(
-            new Integer(value), target, new Extends(iface), stdAM);
+        assertInvokeInterfaceEquals(value, target, new Extends(iface), stdAM);
 
         compiler.cleanup();
     }
 
+    protected void assertInvokeInterfaceThrows(java.lang.Class<? extends Throwable> errorClass,
+                                               Class target, Extends iface, AbstractMethod method,
+                                               String... args) {
+        try {
+            assertInvokeInterfaceEquals(0, target, iface, method, args);
+            fail("Expected exception: " + errorClass);
+        }
+        catch (AssertionError e) {
+            Throwable cause = e.getCause();
+            if (cause == null)
+                throw e;
+            else if ((errorClass.isAssignableFrom(cause.getClass()))) {
+                // this is success
+                return;
+            }
+            else
+                throw e;
+        }
+    }
+
     /**
      * Creates a class which calls target::method(args) via invokevirtual,
      * compiles and loads both the new class and 'target', and then invokes
--- a/test/tools/javac/lambdaShapes/org/openjdk/tests/vm/DefaultMethodsTest.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/test/tools/javac/lambdaShapes/org/openjdk/tests/vm/DefaultMethodsTest.java	Mon Nov 11 23:16:35 2013 -0800
@@ -25,18 +25,22 @@
 
 package org.openjdk.tests.vm;
 
-import java.lang.reflect.*;
-import java.util.*;
-import java.io.File;
-import java.io.IOException;
-
+import org.openjdk.tests.separate.Compiler;
+import org.openjdk.tests.separate.TestHarness;
 import org.testng.annotations.Test;
-import org.openjdk.tests.separate.*;
-import org.openjdk.tests.separate.Compiler;
 
-import static org.testng.Assert.*;
-import static org.openjdk.tests.separate.SourceModel.*;
+import static org.openjdk.tests.separate.SourceModel.AbstractMethod;
+import static org.openjdk.tests.separate.SourceModel.AccessFlag;
 import static org.openjdk.tests.separate.SourceModel.Class;
+import static org.openjdk.tests.separate.SourceModel.ConcreteMethod;
+import static org.openjdk.tests.separate.SourceModel.DefaultMethod;
+import static org.openjdk.tests.separate.SourceModel.Extends;
+import static org.openjdk.tests.separate.SourceModel.Interface;
+import static org.openjdk.tests.separate.SourceModel.MethodParameter;
+import static org.openjdk.tests.separate.SourceModel.TypeParameter;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
 
 @Test(groups = "vm")
 public class DefaultMethodsTest extends TestHarness {
@@ -186,7 +190,7 @@
      * TEST: D d = new D(); d.m() == 22;
      * TEST: I i = new D(); i.m() == 22;
      */
-    void testExistingInheritedOverride() {
+    public void testExistingInheritedOverride() {
         Interface I = new Interface("I", DefaultMethod.std("99"));
         Class C = new Class("C", I, ConcreteMethod.std("11"));
         Class D = new Class("D", C, ConcreteMethod.std("22"));
@@ -258,7 +262,6 @@
      * TEST: C c = new C(); c.m() throws ICCE
      */
     public void testConflict() {
-        // debugTest();
         Interface I = new Interface("I", DefaultMethod.std("99"));
         Interface J = new Interface("J", DefaultMethod.std("88"));
         Class C = new Class("C", I, J);
@@ -390,19 +393,16 @@
 
     /**
      * interface I<T> { default int m(T t) { return 99; } }
-     * Class C implements I<String> { public int m() { return 88; } }
+     * Class C implements I<String> { public int m(String s) { return 88; } }
      *
-     * TEST: C c = new C(); c.m() == 88;
-     * TEST: I i = new C(); i.m() == 88;
+     * TEST: C c = new C(); c.m("string") == 88;
+     * TEST: I i = new C(); i.m("string") == 88;
      */
-    @Test(enabled=false)
     public void testSelfFill() {
         // This test ensures that a concrete method overrides a default method
         // that matches at the language-level, but has a different method
         // signature due to erasure.
 
-        // debugTest();
-
         DefaultMethod dm = new DefaultMethod(
             "int", "m", "return 99;", new MethodParameter("T", "t"));
         ConcreteMethod cm = new ConcreteMethod(
@@ -415,9 +415,11 @@
         AbstractMethod pm = new AbstractMethod(
             "int", "m", new MethodParameter("T", "t"));
 
-        assertInvokeVirtualEquals(new Integer(88), C, cm, "-1", "\"string\"");
-        assertInvokeInterfaceEquals(
-            new Integer(88), C, I.with("String"), pm, "\"string\"");
+        assertInvokeVirtualEquals(88, C, cm, "-1", "\"string\"");
+        assertInvokeInterfaceEquals(99, C, I.with("String"), pm, "\"string\"");
+
+        C.setFullCompilation(true); // Force full bridge generation
+        assertInvokeInterfaceEquals(88, C, I.with("String"), pm, "\"string\"");
     }
 
     /**
@@ -485,7 +487,6 @@
      * TEST: J<String,String> j = new C(); j.m("A","B","C") == 88;
      * TEST: K<String> k = new C(); k.m("A","B","C") == 88;
      */
-    @Test(enabled=false)
     public void testBridges() {
         DefaultMethod dm = new DefaultMethod("int", stdMethodName, "return 99;",
             new MethodParameter("T", "t"), new MethodParameter("V", "v"),
@@ -518,13 +519,17 @@
             J.with("String", "T"), pm2);
         Class C = new Class("C", K.with("String"), cm);
 
+        // First, without compiler bridges
         String[] args = new String[] { "\"A\"", "\"B\"", "\"C\"" };
-        assertInvokeInterfaceEquals(new Integer(88), C,
-            I.with("String", "String", "String"), pm0, args);
-        assertInvokeInterfaceEquals(new Integer(88), C,
-            J.with("String", "String"), pm1, args);
-        assertInvokeInterfaceEquals(new Integer(88), C,
-            K.with("String"), pm2, args);
+        assertInvokeInterfaceEquals(99, C, I.with("String", "String", "String"), pm0, args);
+        assertInvokeInterfaceThrows(AbstractMethodError.class, C, J.with("String", "String"), pm1, args);
+        assertInvokeInterfaceThrows(AbstractMethodError.class, C, K.with("String"), pm2, args);
+
+        // Then with compiler bridges
+        C.setFullCompilation(true);
+        assertInvokeInterfaceEquals(88, C, I.with("String", "String", "String"), pm0, args);
+        assertInvokeInterfaceEquals(88, C, J.with("String", "String"), pm1, args);
+        assertInvokeInterfaceEquals(88, C, K.with("String"), pm2, args);
     }
 
     /**
@@ -536,8 +541,6 @@
      * TEST: I i = new C(); i.m() == 88;
      */
     public void testSuperBasic() {
-        // debugTest();
-
         Interface J = new Interface("J", DefaultMethod.std("88"));
         Interface I = new Interface("I", J, new DefaultMethod(
             "int", stdMethodName, "return J.super.m();"));
@@ -559,8 +562,6 @@
      * TODO: add case for K k = new C(); k.m() throws ICCE
      */
     public void testSuperConflict() {
-        // debugTest();
-
         Interface K = new Interface("K", DefaultMethod.std("99"));
         Interface L = new Interface("L", DefaultMethod.std("101"));
         Interface J = new Interface("J", K, L);
@@ -635,8 +636,7 @@
         AbstractMethod pm = new AbstractMethod("int", stdMethodName,
             new MethodParameter("String", "s"));
 
-        assertInvokeInterfaceEquals(
-            new Integer(88), C, new Extends(I), pm, "\"\"");
+        assertInvokeInterfaceEquals(88, C, new Extends(I), pm, "\"\"");
     }
 
     /**
@@ -674,7 +674,6 @@
      * class S { Object foo() { return (new D()).m(); } // link sig: ()LInteger;
      * TEST: S s = new S(); s.foo() == new Integer(99)
      */
-    @Test(enabled=false)
     public void testCovarBridge() {
         Interface I = new Interface("I", new DefaultMethod(
             "Integer", "m", "return new Integer(88);"));
@@ -692,7 +691,8 @@
         S.addCompilationDependency(Dstub);
         S.addCompilationDependency(DstubMethod);
 
-        assertInvokeVirtualEquals(new Integer(99), S, toCall, "null");
+        // NEGATIVE test for separate compilation -- dispatches to I, not C
+        assertInvokeVirtualEquals(88, S, toCall, "null");
     }
 
     /**
@@ -719,7 +719,7 @@
         S.addCompilationDependency(Dstub);
         S.addCompilationDependency(DstubMethod);
 
-        assertInvokeVirtualEquals(new Integer(88), S, toCall, "null");
+        assertInvokeVirtualEquals(88, S, toCall, "null");
     }
 
     /**
@@ -757,7 +757,6 @@
      * Test that a erased-signature-matching method does not implement
      * non-language-level matching methods
      */
-    @Test(enabled=false)
     public void testNonConcreteFill() {
         AbstractMethod ipm = new AbstractMethod("int", "m",
             new MethodParameter("T", "t"),
@@ -781,13 +780,14 @@
             new MethodParameter("T", "t"),
             new MethodParameter("String", "s"),
             new MethodParameter("String", "w"));
+        DefaultMethod kdm = new DefaultMethod("int", "m", "return 99;",
+                                              new MethodParameter("T", "t"),
+                                              new MethodParameter("String", "v"),
+                                              new MethodParameter("String", "w"));
         Interface K = new Interface("K",
             new TypeParameter("T"),
             J.with("T", "String"),
-            new DefaultMethod("int", "m", "return 99;",
-                new MethodParameter("T", "t"),
-                new MethodParameter("String", "v"),
-                new MethodParameter("String", "w")));
+            kdm);
 
         Class C = new Class("C",
             K.with("String"),
@@ -797,13 +797,18 @@
                 new MethodParameter("Object", "v"),
                 new MethodParameter("String", "w")));
 
+        // First, without compiler bridges
         String a = "\"\"";
-        assertInvokeInterfaceEquals(99, C,
-            K.with("String"), kpm, a, a, a);
-        assertInvokeInterfaceEquals(77, C,
-            J.with("String", "String"), jpm, a, a, a);
-        assertInvokeInterfaceEquals(99, C,
-            I.with("String", "String", "String"), ipm, a, a, a);
+        assertInvokeInterfaceEquals(99, C, K.with("String"), kpm, a, a, a);
+        assertInvokeInterfaceEquals(77, C, J.with("String", "String"), jpm, a, a, a);
+        assertInvokeInterfaceThrows(AbstractMethodError.class, C, I.with("String", "String", "String"), ipm, a, a, a);
+
+        // Now, with bridges
+        J.setFullCompilation(true);
+        K.setFullCompilation(true);
+        assertInvokeInterfaceEquals(99, C, K.with("String"), kpm, a, a, a);
+        assertInvokeInterfaceEquals(77, C, J.with("String", "String"), jpm, a, a, a);
+        assertInvokeInterfaceEquals(99, C, I.with("String", "String", "String"), ipm, a, a, a);
     }
 
     public void testStrictfpDefault() {
--- a/test/tools/jdeps/Basic.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/test/tools/jdeps/Basic.java	Mon Nov 11 23:16:35 2013 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -23,9 +23,9 @@
 
 /*
  * @test
- * @bug 8003562 8005428 8015912
+ * @bug 8003562 8005428 8015912 8027481
  * @summary Basic tests for jdeps tool
- * @build Test p.Foo
+ * @build Test p.Foo p.Bar javax.activity.NotCompactProfile
  * @run main Basic
  */
 
@@ -33,10 +33,12 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.*;
 import java.util.regex.*;
+import static java.nio.file.StandardCopyOption.*;
 
 public class Basic {
     private static boolean symbolFileExist = initProfiles();
@@ -74,23 +76,25 @@
              new String[] {"java.lang", "p"},
              new String[] {"compact1", "not found"});
         // test a directory
+        // also test non-SE javax.activity class dependency
         test(new File(testDir, "p"),
-             new String[] {"java.lang", "java.util", "java.lang.management"},
-             new String[] {"compact1", "compact1", "compact3"});
+             new String[] {"java.lang", "java.util", "java.lang.management", "javax.activity", "javax.crypto"},
+             new String[] {"compact1", "compact1", "compact3", testDir.getName(), "compact1"},
+             new String[] {"-classpath", testDir.getPath()});
         // test class-level dependency output
         test(new File(testDir, "Test.class"),
-             new String[] {"java.lang.Object", "java.lang.String", "p.Foo"},
-             new String[] {"compact1", "compact1", "not found"},
+             new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
+             new String[] {"compact1", "compact1", "not found", "not found"},
              new String[] {"-verbose:class"});
         // test -p option
         test(new File(testDir, "Test.class"),
-             new String[] {"p.Foo"},
-             new String[] {"not found"},
+             new String[] {"p.Foo", "p.Bar"},
+             new String[] {"not found", "not found"},
              new String[] {"-verbose:class", "-p", "p"});
         // test -e option
         test(new File(testDir, "Test.class"),
-             new String[] {"p.Foo"},
-             new String[] {"not found"},
+             new String[] {"p.Foo", "p.Bar"},
+             new String[] {"not found", "not found"},
              new String[] {"-verbose:class", "-e", "p\\..*"});
         test(new File(testDir, "Test.class"),
              new String[] {"java.lang"},
@@ -99,13 +103,34 @@
         // test -classpath and -include options
         test(null,
              new String[] {"java.lang", "java.util",
-                           "java.lang.management"},
-             new String[] {"compact1", "compact1", "compact3"},
+                           "java.lang.management", "javax.crypto"},
+             new String[] {"compact1", "compact1", "compact3", "compact1"},
              new String[] {"-classpath", testDir.getPath(), "-include", "p.+|Test.class"});
         test(new File(testDir, "Test.class"),
-             new String[] {"java.lang.Object", "java.lang.String", "p.Foo"},
-             new String[] {"compact1", "compact1", testDir.getName()},
+             new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
+             new String[] {"compact1", "compact1", testDir.getName(), testDir.getName()},
              new String[] {"-v", "-classpath", testDir.getPath(), "Test.class"});
+
+        // split package p - move p/Foo.class to dir1 and p/Bar.class to dir2
+        Path testClassPath = testDir.toPath();
+        Path dirP = testClassPath.resolve("p");
+        Path dir1 = testClassPath.resolve("dir1");
+        Path subdir1P = dir1.resolve("p");
+        Path dir2 = testClassPath.resolve("dir2");
+        Path subdir2P = dir2.resolve("p");
+        if (!Files.exists(subdir1P))
+            Files.createDirectories(subdir1P);
+        if (!Files.exists(subdir2P))
+            Files.createDirectories(subdir2P);
+        Files.move(dirP.resolve("Foo.class"), subdir1P.resolve("Foo.class"), REPLACE_EXISTING);
+        Files.move(dirP.resolve("Bar.class"), subdir2P.resolve("Bar.class"), REPLACE_EXISTING);
+        StringBuilder cpath = new StringBuilder(testDir.toString());
+        cpath.append(File.pathSeparator).append(dir1.toString());
+        cpath.append(File.pathSeparator).append(dir2.toString());
+        test(new File(testDir, "Test.class"),
+             new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"},
+             new String[] {"compact1", "compact1", dir1.toFile().getName(), dir2.toFile().getName()},
+             new String[] {"-v", "-classpath", cpath.toString(), "Test.class"});
         return errors;
     }
 
@@ -148,7 +173,7 @@
     // Use the linePattern to break the given String into lines, applying
     // the pattern to each line to see if we have a match
     private static Map<String,String> findDeps(String out) {
-        Map<String,String> result = new HashMap<>();
+        Map<String,String> result = new LinkedHashMap<>();
         Matcher lm = linePattern.matcher(out);  // Line matcher
         Matcher pm = null;                      // Pattern matcher
         int lines = 0;
--- a/test/tools/jdeps/Test.java	Thu Oct 31 14:07:48 2013 -0400
+++ b/test/tools/jdeps/Test.java	Mon Nov 11 23:16:35 2013 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -24,6 +24,7 @@
 public class Test {
     public void test() {
         p.Foo f = new p.Foo();
+        p.Bar b = new p.Bar();
     }
     private String name() {
         return "this test";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeps/javax/activity/NotCompactProfile.java	Mon Nov 11 23:16:35 2013 -0800
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.activity;
+
+public class NotCompactProfile {
+    public static String name() {
+        return "not Java SE API";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeps/p/Bar.java	Mon Nov 11 23:16:35 2013 -0800
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+public class Bar extends javax.activity.NotCompactProfile {
+    public String bar() {
+        return "bar";
+    }
+    public javax.crypto.Cipher getCiper() {
+        return null;
+    }
+}