changeset 3416:62278f3c373a

Merge
author lana
date Thu, 19 May 2016 19:47:04 +0000
parents 1578b957d223 292a9489d20a
children 9c4984bd4951
files src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModulePaths.java src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditingHistory.java test/tools/jdeps/CompilerUtils.java
diffstat 200 files changed, 9114 insertions(+), 3908 deletions(-) [+]
line wrap: on
line diff
--- a/make/build.properties	Thu May 19 17:48:04 2016 +0000
+++ b/make/build.properties	Thu May 19 19:47:04 2016 +0000
@@ -28,6 +28,10 @@
 javac.source = 9
 javac.target = 9
 
+#version used to compile build tools
+javac.build.source = 8
+javac.build.target = 8
+
 langtools.resource.includes = \
         com/sun/tools/javac/resources/compiler.properties
 
--- a/make/build.xml	Thu May 19 17:48:04 2016 +0000
+++ b/make/build.xml	Thu May 19 19:47:04 2016 +0000
@@ -239,11 +239,12 @@
         </condition>
         <replace file=".idea/ant.xml" token="@IDEA_JTREG_HOME@" value="${idea.jtreg.home}"/>
         <replace file=".idea/ant.xml" token="@IDEA_TARGET_JDK@" value="${idea.target.jdk}"/>
-        <replace file=".idea/workspace.xml" token="@IDEA_TARGET_JDK@" value="${idea.target.jdk}"/>
-        <replace file=".idea/workspace.xml" token="@XPATCH@" value="${xpatch.cmd}"/>
-        <replace file=".idea/workspace.xml" token="@PATH_SEP@" value="${path.separator}"/>
+        <replace dir=".idea/runConfigurations" token="@IDEA_TARGET_JDK@" value="${idea.target.jdk}"/>
+        <replace dir=".idea/runConfigurations" token="@XPATCH@" value="${xpatch.cmd}"/>
         <mkdir dir=".idea/classes"/>
-        <javac srcdir="make/intellij/src"
+        <javac source="${javac.build.source}"
+               target="${javac.build.target}"
+               srcdir="make/intellij/src"
                destdir=".idea/classes"/>
     </target>
 
@@ -255,10 +256,8 @@
         <copy todir="${build.tools}/propertiesparser" >
             <fileset dir="${make.tools.dir}/propertiesparser" includes="**/resources/**"/>
         </copy>
-        <javac fork="true"
-               source="${javac.source}"
-               target="${javac.target}"
-               executable="${langtools.jdk.home}/bin/javac"
+        <javac source="${javac.build.source}"
+               target="${javac.build.target}"
                srcdir="${make.tools.dir}"
                includes="propertiesparser/* anttasks/PropertiesParser* anttasks/PathFileSet*"
                destdir="${build.tools}"
@@ -273,10 +272,9 @@
     </target>
 
      <target name="-def-pcompile">
-        <javac fork="true"
-               source="${javac.source}"
-               target="${javac.target}"
-               executable="${langtools.jdk.home}/bin/javac"
+        <javac
+               source="${javac.build.source}"
+               target="${javac.build.target}"
                srcdir="${make.tools.dir}"
                includes="compileproperties/* anttasks/CompileProperties* anttasks/PathFileSet*"
                destdir="${build.dir}/toolclasses/"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/intellij/runConfigurations/javac.xml	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,22 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="javac" type="Application" factoryName="Application">
+    <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+    <option name="MAIN_CLASS_NAME" value="com.sun.tools.javac.Main" />
+    <option name="VM_PARAMETERS" value="@XPATCH@" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
+    <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
+    <option name="ENABLE_SWING_INSPECTOR" value="false" />
+    <option name="ENV_VARIABLES" />
+    <option name="PASS_PARENT_ENVS" value="true" />
+    <module name="langtools" />
+    <envs />
+    <RunnerSettings RunnerId="Run" />
+    <ConfigurationWrapper RunnerId="Run" />
+    <method>
+      <option name="Make" enabled="false" />
+      <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
+    </method>
+  </configuration>
+</component>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/intellij/runConfigurations/javadoc.xml	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,22 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="javadoc" type="Application" factoryName="Application">
+    <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+    <option name="MAIN_CLASS_NAME" value="com.sun.tools.javadoc.Main" />
+    <option name="VM_PARAMETERS" value="@XPATCH@" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
+    <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
+    <option name="ENABLE_SWING_INSPECTOR" value="false" />
+    <option name="ENV_VARIABLES" />
+    <option name="PASS_PARENT_ENVS" value="true" />
+    <module name="langtools" />
+    <envs />
+    <RunnerSettings RunnerId="Run" />
+    <ConfigurationWrapper RunnerId="Run" />
+    <method>
+      <option name="Make" enabled="false" />
+      <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
+    </method>
+  </configuration>
+</component>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/intellij/runConfigurations/javah.xml	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,22 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="javah" type="Application" factoryName="Application">
+    <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+    <option name="MAIN_CLASS_NAME" value="com.sun.tools.javah.Main" />
+    <option name="VM_PARAMETERS" value="@XPATCH@ -XaddExports:jdk.compiler/com.sun.tools.javah=ALL-UNNAMED" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
+    <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
+    <option name="ENABLE_SWING_INSPECTOR" value="false" />
+    <option name="ENV_VARIABLES" />
+    <option name="PASS_PARENT_ENVS" value="true" />
+    <module name="langtools" />
+    <envs />
+    <RunnerSettings RunnerId="Run" />
+    <ConfigurationWrapper RunnerId="Run" />
+    <method>
+      <option name="Make" enabled="false" />
+      <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
+    </method>
+  </configuration>
+</component>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/intellij/runConfigurations/javap.xml	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,22 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="javap" type="Application" factoryName="Application">
+    <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+    <option name="MAIN_CLASS_NAME" value="com.sun.tools.javap.Main" />
+    <option name="VM_PARAMETERS" value="@XPATCH@ -XaddExports:jdk.jdeps/com.sun.tools.javap=ALL-UNNAMED" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
+    <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
+    <option name="ENABLE_SWING_INSPECTOR" value="false" />
+    <option name="ENV_VARIABLES" />
+    <option name="PASS_PARENT_ENVS" value="true" />
+    <module name="langtools" />
+    <envs />
+    <RunnerSettings RunnerId="Run" />
+    <ConfigurationWrapper RunnerId="Run" />
+    <method>
+      <option name="Make" enabled="false" />
+      <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
+    </method>
+  </configuration>
+</component>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/intellij/runConfigurations/jshell.xml	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,20 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="jshell" type="Application" factoryName="Application">
+    <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+    <option name="MAIN_CLASS_NAME" value="jdk.internal.jshell.tool.JShellTool" />
+    <option name="VM_PARAMETERS" value="@XPATCH@ -XaddExports:jdk.jshell/jdk.internal.jshell.tool=ALL-UNNAMED" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
+    <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
+    <option name="ENABLE_SWING_INSPECTOR" value="false" />
+    <option name="ENV_VARIABLES" />
+    <option name="PASS_PARENT_ENVS" value="true" />
+    <module name="langtools" />
+    <envs />
+    <method>
+      <option name="Make" enabled="false" />
+      <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
+    </method>
+  </configuration>
+</component>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/intellij/runConfigurations/jtreg__debug_.xml	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,18 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="jtreg (debug)" type="Remote" factoryName="Remote" singleton="true">
+    <option name="USE_SOCKET_TRANSPORT" value="true" />
+    <option name="SERVER_MODE" value="true" />
+    <option name="SHMEM_ADDRESS" />
+    <option name="HOST" value="localhost" />
+    <option name="PORT" value="5900" />
+    <RunnerSettings RunnerId="Debug">
+      <option name="DEBUG_PORT" value="5900" />
+      <option name="TRANSPORT" value="0" />
+      <option name="LOCAL" value="false" />
+    </RunnerSettings>
+    <ConfigurationWrapper RunnerId="Debug" />
+    <method>
+      <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="jtreg-debug" />
+    </method>
+  </configuration>
+</component>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/intellij/runConfigurations/jtreg__run_.xml	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,8 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="jtreg (run)" type="AntRunConfiguration" factoryName="Ant Target">
+    <antsettings antfile="file://$PROJECT_DIR$/.idea/build.xml" target="jtreg" />
+    <method>
+      <option name="Make" enabled="false" />
+    </method>
+  </configuration>
+</component>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/intellij/runConfigurations/sjavac.xml	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,22 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="sjavac" type="Application" factoryName="Application">
+    <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
+    <option name="MAIN_CLASS_NAME" value="com.sun.tools.sjavac.Main" />
+    <option name="VM_PARAMETERS" value="@XPATCH@ -XaddExports:jdk.compiler/com.sun.tools.sjavac=ALL-UNNAMED" />
+    <option name="PROGRAM_PARAMETERS" value="" />
+    <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
+    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
+    <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
+    <option name="ENABLE_SWING_INSPECTOR" value="false" />
+    <option name="ENV_VARIABLES" />
+    <option name="PASS_PARENT_ENVS" value="true" />
+    <module name="langtools" />
+    <envs />
+    <RunnerSettings RunnerId="Run" />
+    <ConfigurationWrapper RunnerId="Run" />
+    <method>
+      <option name="Make" enabled="false" />
+      <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
+    </method>
+  </configuration>
+</component>
--- a/make/intellij/workspace.xml	Thu May 19 17:48:04 2016 +0000
+++ b/make/intellij/workspace.xml	Thu May 19 19:47:04 2016 +0000
@@ -1,157 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
-  <component name="ChangeListManager">
-    <ignored path=".idea/" />
-  </component>
-  <component name="CompilerWorkspaceConfiguration">
-    <option name="MAKE_PROJECT_ON_SAVE" value="true" />
-  </component>
-  <component name="RunManager" selected="Application.javac">
-    <!-- javac -->
-    <configuration default="false" name="javac" type="Application" factoryName="Application">
-      <option name="MAIN_CLASS_NAME" value="com.sun.tools.javac.Main" />
-      <option name="VM_PARAMETERS" value="@XPATCH@" />
-      <option name="PROGRAM_PARAMETERS" value="" />
-      <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
-      <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
-      <option name="ENABLE_SWING_INSPECTOR" value="false" />
-      <option name="ENV_VARIABLES" />
-      <option name="PASS_PARENT_ENVS" value="true" />
-      <module name="langtools" />
-      <envs />
-      <RunnerSettings RunnerId="Run" />
-      <ConfigurationWrapper RunnerId="Run" />
-      <method>
-        <option name="Make" enabled="false" />
-        <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
-      </method>
-    </configuration>
-    <!-- javadoc -->
-    <configuration default="false" name="javadoc" type="Application" factoryName="Application">
-      <option name="MAIN_CLASS_NAME" value="com.sun.tools.javadoc.Main" />
-      <option name="VM_PARAMETERS" value="@XPATCH@" />
-      <option name="PROGRAM_PARAMETERS" value="" />
-      <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
-      <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
-      <option name="ENABLE_SWING_INSPECTOR" value="false" />
-      <option name="ENV_VARIABLES" />
-      <option name="PASS_PARENT_ENVS" value="true" />
-      <module name="langtools" />
-      <envs />
-      <RunnerSettings RunnerId="Run" />
-      <ConfigurationWrapper RunnerId="Run" />
-      <method>
-        <option name="Make" enabled="false" />
-        <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
-      </method>
-    </configuration>
-    <!-- javap -->
-    <configuration default="false" name="javap" type="Application" factoryName="Application">
-      <option name="MAIN_CLASS_NAME" value="com.sun.tools.javap.Main" />
-      <option name="VM_PARAMETERS" value="@XPATCH@" />
-      <option name="PROGRAM_PARAMETERS" value="" />
-      <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
-      <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
-      <option name="ENABLE_SWING_INSPECTOR" value="false" />
-      <option name="ENV_VARIABLES" />
-      <option name="PASS_PARENT_ENVS" value="true" />
-      <module name="langtools" />
-      <envs />
-      <RunnerSettings RunnerId="Run" />
-      <ConfigurationWrapper RunnerId="Run" />
-      <method>
-        <option name="Make" enabled="false" />
-        <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
-      </method>
-    </configuration>
-    <!-- javah -->
-    <configuration default="false" name="javah" type="Application" factoryName="Application">
-      <option name="MAIN_CLASS_NAME" value="com.sun.tools.javah.Main" />
-      <option name="VM_PARAMETERS" value="@XPATCH@" />
-      <option name="PROGRAM_PARAMETERS" value="" />
-      <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
-      <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
-      <option name="ENABLE_SWING_INSPECTOR" value="false" />
-      <option name="ENV_VARIABLES" />
-      <option name="PASS_PARENT_ENVS" value="true" />
-      <module name="langtools" />
-      <envs />
-      <RunnerSettings RunnerId="Run" />
-      <ConfigurationWrapper RunnerId="Run" />
-      <method>
-        <option name="Make" enabled="false" />
-        <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
-      </method>
-    </configuration>
-    <!-- sjavac -->
-    <configuration default="false" name="sjavac" type="Application" factoryName="Application">
-      <option name="MAIN_CLASS_NAME" value="com.sun.tools.sjavac.Main" />
-      <option name="VM_PARAMETERS" value="@XPATCH@" />
-      <option name="PROGRAM_PARAMETERS" value="" />
-      <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
-      <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
-      <option name="ENABLE_SWING_INSPECTOR" value="false" />
-      <option name="ENV_VARIABLES" />
-      <option name="PASS_PARENT_ENVS" value="true" />
-      <module name="langtools" />
-      <envs />
-      <RunnerSettings RunnerId="Run" />
-      <ConfigurationWrapper RunnerId="Run" />
-      <method>
-        <option name="Make" enabled="false" />
-        <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
-      </method>
-    </configuration>
-    <!-- jshell -->
-    <configuration default="false" name="jshell" type="Application" factoryName="Application">
-      <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
-      <option name="MAIN_CLASS_NAME" value="jdk.internal.jshell.tool.JShellTool" />
-      <option name="VM_PARAMETERS" value="@XPATCH@ -XaddExports:jdk.jshell/jdk.internal.jshell.tool=ALL-UNNAMED" />
-      <option name="PROGRAM_PARAMETERS" value="" />
-      <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
-      <option name="ALTERNATIVE_JRE_PATH" value="@IDEA_TARGET_JDK@" />
-      <option name="ENABLE_SWING_INSPECTOR" value="false" />
-      <option name="ENV_VARIABLES" />
-      <option name="PASS_PARENT_ENVS" value="true" />
-      <module name="langtools" />
-      <envs />
-      <method>
-        <option name="Make" enabled="false" />
-        <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="build-all-classes" />
-      </method>
-    </configuration>
-    <!-- jtreg run -->
-    <configuration default="false" name="jtreg (run)" type="AntRunConfiguration" factoryName="Ant Target">
-      <antsettings antfile="file://$PROJECT_DIR$/.idea/build.xml" target="jtreg" />
-      <method>
-        <option name="Make" enabled="false" />
-      </method>
-    </configuration>
-    <!-- jtreg debug -->
-    <configuration default="false" name="jtreg (debug)" type="Remote" factoryName="Remote" singleton="true">
-      <option name="USE_SOCKET_TRANSPORT" value="true" />
-      <option name="SERVER_MODE" value="true" />
-      <option name="SHMEM_ADDRESS" />
-      <option name="HOST" value="localhost" />
-      <option name="PORT" value="5900" />
-      <RunnerSettings RunnerId="Debug">
-        <option name="DEBUG_PORT" value="5900" />
-        <option name="TRANSPORT" value="0" />
-        <option name="LOCAL" value="false" />
-      </RunnerSettings>
-      <ConfigurationWrapper RunnerId="Debug" />
-      <method>
-        <option name="AntTarget" enabled="true" antfile="file://$PROJECT_DIR$/.idea/build.xml" target="jtreg-debug" />
-      </method>
-      <method />
-    </configuration>
-  </component>
   <component name="StructureViewFactory">
     <option name="ACTIVE_ACTIONS" value=",ALPHA_COMPARATOR" />
   </component>
--- a/make/tools/crules/AssertCheckAnalyzer.java	Thu May 19 17:48:04 2016 +0000
+++ b/make/tools/crules/AssertCheckAnalyzer.java	Thu May 19 19:47:04 2016 +0000
@@ -37,6 +37,9 @@
 import com.sun.tools.javac.tree.TreeScanner;
 import com.sun.tools.javac.util.Assert;
 
+/**This analyzer guards against complex messages (i.e. those that use string concatenation) passed
+ * to various Assert.check methods.
+ */
 public class AssertCheckAnalyzer extends AbstractCodingRulesAnalyzer {
 
     enum AssertOverloadKind {
--- a/make/tools/crules/MutableFieldsAnalyzer.java	Thu May 19 17:48:04 2016 +0000
+++ b/make/tools/crules/MutableFieldsAnalyzer.java	Thu May 19 19:47:04 2016 +0000
@@ -41,6 +41,7 @@
 import static com.sun.tools.javac.code.Flags.SYNTHETIC;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 
+/**This analyzer guards against non-final static fields.*/
 public class MutableFieldsAnalyzer extends AbstractCodingRulesAnalyzer {
 
     public MutableFieldsAnalyzer(JavacTask task) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java	Thu May 19 19:47:04 2016 +0000
@@ -365,18 +365,22 @@
 
         @Override
         Type speculativeType(Symbol msym, MethodResolutionPhase phase) {
-            for (Map.Entry<ResultInfo, Type> _entry : speculativeTypes.entrySet()) {
-                DeferredAttrContext deferredAttrContext = _entry.getKey().checkContext.deferredAttrContext();
-                if (deferredAttrContext.phase == phase && deferredAttrContext.msym == msym) {
-                    return _entry.getValue();
+            if (pertinentToApplicability) {
+                for (Map.Entry<ResultInfo, Type> _entry : speculativeTypes.entrySet()) {
+                    DeferredAttrContext deferredAttrContext = _entry.getKey().checkContext.deferredAttrContext();
+                    if (deferredAttrContext.phase == phase && deferredAttrContext.msym == msym) {
+                        return _entry.getValue();
+                    }
                 }
+                return Type.noType;
+            } else {
+                return super.speculativeType(msym, phase);
             }
-            return Type.noType;
         }
 
         @Override
         JCTree speculativeTree(DeferredAttrContext deferredAttrContext) {
-            return speculativeTree;
+            return pertinentToApplicability ? speculativeTree : super.speculativeTree(deferredAttrContext);
         }
 
         /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu May 19 19:47:04 2016 +0000
@@ -2678,6 +2678,7 @@
         class ExpressionLambdaReturnContext extends FunctionalReturnContext {
 
             JCExpression expr;
+            boolean expStmtExpected;
 
             ExpressionLambdaReturnContext(JCExpression expr, CheckContext enclosingContext) {
                 super(enclosingContext);
@@ -2685,10 +2686,23 @@
             }
 
             @Override
+            public void report(DiagnosticPosition pos, JCDiagnostic details) {
+                if (expStmtExpected) {
+                    enclosingContext.report(pos, diags.fragment(Fragments.StatExprExpected));
+                } else {
+                    super.report(pos, details);
+                }
+            }
+
+            @Override
             public boolean compatible(Type found, Type req, Warner warn) {
                 //a void return is compatible with an expression statement lambda
-                return TreeInfo.isExpressionStatement(expr) && req.hasTag(VOID) ||
-                        super.compatible(found, req, warn);
+                if (req.hasTag(VOID)) {
+                    expStmtExpected = true;
+                    return TreeInfo.isExpressionStatement(expr);
+                } else {
+                    return super.compatible(found, req, warn);
+                }
             }
         }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Thu May 19 19:47:04 2016 +0000
@@ -35,6 +35,7 @@
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.GraphUtils.DependencyKind;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.comp.Attr.ResultInfo;
@@ -44,9 +45,10 @@
 import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
-import java.util.LinkedHashMap;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
@@ -172,6 +174,7 @@
         public JCExpression tree;
         Env<AttrContext> env;
         AttrMode mode;
+        boolean pertinentToApplicability = true;
         SpeculativeCache speculativeCache;
 
         DeferredType(JCExpression tree, Env<AttrContext> env) {
@@ -290,6 +293,7 @@
                     resultInfo.checkContext.deferredAttrContext();
             Assert.check(deferredAttrContext != emptyDeferredAttrContext);
             if (deferredStuckPolicy.isStuck()) {
+                pertinentToApplicability = false;
                 deferredAttrContext.addDeferredAttrNode(this, resultInfo, deferredStuckPolicy);
                 return Type.noType;
             } else {
@@ -574,28 +578,11 @@
          */
         void complete() {
             while (!deferredAttrNodes.isEmpty()) {
-                Map<Type, Set<Type>> depVarsMap = new LinkedHashMap<>();
-                List<Type> stuckVars = List.nil();
                 boolean progress = false;
                 //scan a defensive copy of the node list - this is because a deferred
                 //attribution round can add new nodes to the list
                 for (DeferredAttrNode deferredAttrNode : List.from(deferredAttrNodes)) {
-                    if (!deferredAttrNode.process(this)) {
-                        List<Type> restStuckVars =
-                                List.from(deferredAttrNode.deferredStuckPolicy.stuckVars())
-                                .intersect(inferenceContext.restvars());
-                        stuckVars = stuckVars.prependList(restStuckVars);
-                        //update dependency map
-                        for (Type t : List.from(deferredAttrNode.deferredStuckPolicy.depVars())
-                                .intersect(inferenceContext.restvars())) {
-                            Set<Type> prevDeps = depVarsMap.get(t);
-                            if (prevDeps == null) {
-                                prevDeps = new LinkedHashSet<>();
-                                depVarsMap.put(t, prevDeps);
-                            }
-                            prevDeps.addAll(restStuckVars);
-                        }
-                    } else {
+                    if (deferredAttrNode.process(this)) {
                         deferredAttrNodes.remove(deferredAttrNode);
                         progress = true;
                     }
@@ -610,7 +597,9 @@
                     //remove all variables that have already been instantiated
                     //from the list of stuck variables
                     try {
-                        inferenceContext.solveAny(stuckVars, depVarsMap, warn);
+                        //find stuck expression to unstuck
+                        DeferredAttrNode toUnstuck = pickDeferredNode();
+                        inferenceContext.solveAny(List.from(toUnstuck.deferredStuckPolicy.stuckVars()), warn);
                         inferenceContext.notifyChange();
                     } catch (Infer.GraphStrategy.NodeNotFoundException ex) {
                         //this means that we are in speculative mode and the
@@ -632,6 +621,59 @@
             }
             return dac.parent.insideOverloadPhase();
         }
+
+        /**
+         * Pick the deferred node to be unstuck. The chosen node is the first strongly connected
+         * component containing exactly one node found in the dependency graph induced by deferred nodes.
+         * If no such component is found, the first deferred node is returned.
+         */
+        DeferredAttrNode pickDeferredNode() {
+            List<StuckNode> nodes = deferredAttrNodes.stream()
+                    .map(StuckNode::new)
+                    .collect(List.collector());
+            //init stuck expression graph; a deferred node A depends on a deferred node B iff
+            //the intersection between A's input variable and B's output variable is non-empty.
+            for (StuckNode sn1 : nodes) {
+                for (Type t : sn1.data.deferredStuckPolicy.stuckVars()) {
+                    for (StuckNode sn2 : nodes) {
+                        if (sn1 != sn2 && sn2.data.deferredStuckPolicy.depVars().contains(t)) {
+                            sn1.deps.add(sn2);
+                        }
+                    }
+                }
+            }
+            //compute tarjan on the stuck graph
+            List<? extends StuckNode> csn = GraphUtils.tarjan(nodes).get(0);
+            return csn.length() == 1 ? csn.get(0).data : deferredAttrNodes.get(0);
+        }
+
+        class StuckNode extends GraphUtils.TarjanNode<DeferredAttrNode, StuckNode> {
+
+            Set<StuckNode> deps = new HashSet<>();
+
+            StuckNode(DeferredAttrNode data) {
+                super(data);
+            }
+
+            @Override
+            public DependencyKind[] getSupportedDependencyKinds() {
+                return new DependencyKind[] { Infer.DependencyKind.STUCK };
+            }
+
+            @Override
+            public Collection<? extends StuckNode> getDependenciesByKind(DependencyKind dk) {
+                if (dk == Infer.DependencyKind.STUCK) {
+                    return deps;
+                } else {
+                    throw new IllegalStateException();
+                }
+            }
+
+            @Override
+            public Iterable<? extends StuckNode> getAllDependencies() {
+                return deps;
+            }
+        }
     }
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Thu May 19 19:47:04 2016 +0000
@@ -2345,10 +2345,11 @@
         // assigned before reading their value
         public void visitSelect(JCFieldAccess tree) {
             super.visitSelect(tree);
+            JCTree sel = TreeInfo.skipParens(tree.selected);
             if (enforceThisDotInit &&
-                tree.selected.hasTag(IDENT) &&
-                ((JCIdent)tree.selected).name == names._this &&
-                tree.sym.kind == VAR) {
+                    sel.hasTag(IDENT) &&
+                    ((JCIdent)sel).name == names._this &&
+                    tree.sym.kind == VAR) {
                 checkInit(tree.pos(), (VarSymbol)tree.sym);
             }
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Thu May 19 19:47:04 2016 +0000
@@ -52,11 +52,9 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.EnumMap;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -1655,12 +1653,10 @@
     class GraphSolver {
 
         InferenceContext inferenceContext;
-        Map<Type, Set<Type>> stuckDeps;
         Warner warn;
 
-        GraphSolver(InferenceContext inferenceContext, Map<Type, Set<Type>> stuckDeps, Warner warn) {
+        GraphSolver(InferenceContext inferenceContext, Warner warn) {
             this.inferenceContext = inferenceContext;
-            this.stuckDeps = stuckDeps;
             this.warn = warn;
         }
 
@@ -1671,7 +1667,7 @@
          */
         void solve(GraphStrategy sstrategy) {
             doIncorporation(inferenceContext, warn); //initial propagation of bounds
-            InferenceGraph inferenceGraph = new InferenceGraph(stuckDeps);
+            InferenceGraph inferenceGraph = new InferenceGraph();
             while (!sstrategy.done()) {
                 if (dependenciesFolder != null) {
                     //add this graph to the pending queue
@@ -1720,12 +1716,12 @@
              */
             class Node extends GraphUtils.TarjanNode<ListBuffer<Type>, Node> implements DottableNode<ListBuffer<Type>, Node> {
 
-                /** map listing all dependencies (grouped by kind) */
-                EnumMap<DependencyKind, Set<Node>> deps;
+                /** node dependencies */
+                Set<Node> deps;
 
                 Node(Type ivar) {
                     super(ListBuffer.of(ivar));
-                    this.deps = new EnumMap<>(DependencyKind.class);
+                    this.deps = new HashSet<>();
                 }
 
                 @Override
@@ -1734,76 +1730,53 @@
                 }
 
                 public Iterable<? extends Node> getAllDependencies() {
-                    return getDependencies(DependencyKind.values());
+                    return deps;
                 }
 
                 @Override
                 public Collection<? extends Node> getDependenciesByKind(GraphUtils.DependencyKind dk) {
-                    return getDependencies((DependencyKind)dk);
-                }
-
-                /**
-                 * Retrieves all dependencies with given kind(s).
-                 */
-                protected Set<Node> getDependencies(DependencyKind... depKinds) {
-                    Set<Node> buf = new LinkedHashSet<>();
-                    for (DependencyKind dk : depKinds) {
-                        Set<Node> depsByKind = deps.get(dk);
-                        if (depsByKind != null) {
-                            buf.addAll(depsByKind);
-                        }
+                    if (dk == DependencyKind.BOUND) {
+                        return deps;
+                    } else {
+                        throw new IllegalStateException();
                     }
-                    return buf;
                 }
 
                 /**
                  * Adds dependency with given kind.
                  */
-                protected void addDependency(DependencyKind dk, Node depToAdd) {
-                    Set<Node> depsByKind = deps.get(dk);
-                    if (depsByKind == null) {
-                        depsByKind = new LinkedHashSet<>();
-                        deps.put(dk, depsByKind);
-                    }
-                    depsByKind.add(depToAdd);
+                protected void addDependency(Node depToAdd) {
+                    deps.add(depToAdd);
                 }
 
                 /**
                  * Add multiple dependencies of same given kind.
                  */
-                protected void addDependencies(DependencyKind dk, Set<Node> depsToAdd) {
+                protected void addDependencies(Set<Node> depsToAdd) {
                     for (Node n : depsToAdd) {
-                        addDependency(dk, n);
+                        addDependency(n);
                     }
                 }
 
                 /**
                  * Remove a dependency, regardless of its kind.
                  */
-                protected Set<DependencyKind> removeDependency(Node n) {
-                    Set<DependencyKind> removedKinds = new HashSet<>();
-                    for (DependencyKind dk : DependencyKind.values()) {
-                        Set<Node> depsByKind = deps.get(dk);
-                        if (depsByKind == null) continue;
-                        if (depsByKind.remove(n)) {
-                            removedKinds.add(dk);
-                        }
-                    }
-                    return removedKinds;
+                protected boolean removeDependency(Node n) {
+                    return deps.remove(n);
                 }
 
                 /**
                  * Compute closure of a give node, by recursively walking
                  * through all its dependencies (of given kinds)
                  */
-                protected Set<Node> closure(DependencyKind... depKinds) {
+                protected Set<Node> closure() {
                     boolean progress = true;
                     Set<Node> closure = new HashSet<>();
                     closure.add(this);
                     while (progress) {
                         progress = false;
                         for (Node n1 : new HashSet<>(closure)) {
-                            progress = closure.addAll(n1.getDependencies(depKinds));
+                            progress = closure.addAll(n1.deps);
                         }
                     }
                     return closure;
@@ -1815,9 +1788,8 @@
                  */
                 protected boolean isLeaf() {
                     //no deps, or only one self dep
-                    Set<Node> allDeps = getDependencies(DependencyKind.BOUND, DependencyKind.STUCK);
-                    if (allDeps.isEmpty()) return true;
-                    for (Node n : allDeps) {
+                    if (deps.isEmpty()) return true;
+                    for (Node n : deps) {
                         if (n != this) {
                             return false;
                         }
@@ -1834,24 +1806,15 @@
                     for (Node n : nodes) {
                         Assert.check(n.data.length() == 1, "Attempt to merge a compound node!");
                         data.appendList(n.data);
-                        for (DependencyKind dk : DependencyKind.values()) {
-                            addDependencies(dk, n.getDependencies(dk));
-                        }
+                        addDependencies(n.deps);
                     }
                     //update deps
-                    EnumMap<DependencyKind, Set<Node>> deps2 = new EnumMap<>(DependencyKind.class);
-                    for (DependencyKind dk : DependencyKind.values()) {
-                        for (Node d : getDependencies(dk)) {
-                            Set<Node> depsByKind = deps2.get(dk);
-                            if (depsByKind == null) {
-                                depsByKind = new LinkedHashSet<>();
-                                deps2.put(dk, depsByKind);
-                            }
-                            if (data.contains(d.data.first())) {
-                                depsByKind.add(this);
-                            } else {
-                                depsByKind.add(d);
-                            }
+                    Set<Node> deps2 = new HashSet<>();
+                    for (Node d : deps) {
+                        if (data.contains(d.data.first())) {
+                            deps2.add(this);
+                        } else {
+                            deps2.add(d);
                         }
                     }
                     deps = deps2;
@@ -1862,9 +1825,9 @@
                  * topology.
                  */
                 private void graphChanged(Node from, Node to) {
-                    for (DependencyKind dk : removeDependency(from)) {
+                    if (removeDependency(from)) {
                         if (to != null) {
-                            addDependency(dk, to);
+                            addDependency(to);
                         }
                     }
                 }
@@ -1880,22 +1843,19 @@
                 public Properties dependencyAttributes(Node sink, GraphUtils.DependencyKind dk) {
                     Properties p = new Properties();
                     p.put("style", ((DependencyKind)dk).dotSyle);
-                    if (dk == DependencyKind.STUCK) return p;
-                    else {
-                        StringBuilder buf = new StringBuilder();
-                        String sep = "";
-                        for (Type from : data) {
-                            UndetVar uv = (UndetVar)inferenceContext.asUndetVar(from);
-                            for (Type bound : uv.getBounds(InferenceBound.values())) {
-                                if (bound.containsAny(List.from(sink.data))) {
-                                    buf.append(sep);
-                                    buf.append(bound);
-                                    sep = ",";
-                                }
+                    StringBuilder buf = new StringBuilder();
+                    String sep = "";
+                    for (Type from : data) {
+                        UndetVar uv = (UndetVar)inferenceContext.asUndetVar(from);
+                        for (Type bound : uv.getBounds(InferenceBound.values())) {
+                            if (bound.containsAny(List.from(sink.data))) {
+                                buf.append(sep);
+                                buf.append(bound);
+                                sep = ",";
                             }
                         }
-                        p.put("label", "\"" + buf.toString() + "\"");
                     }
+                    p.put("label", "\"" + buf.toString() + "\"");
                     return p;
                 }
             }
@@ -1903,8 +1863,8 @@
             /** the nodes in the inference graph */
             ArrayList<Node> nodes;
 
-            InferenceGraph(Map<Type, Set<Type>> optDeps) {
-                initNodes(optDeps);
+            InferenceGraph() {
+                initNodes();
             }
 
             /**
@@ -1946,7 +1906,7 @@
              * in the graph. For each component containing more than one node, a super node is
              * created, effectively replacing the original cyclic nodes.
              */
-            void initNodes(Map<Type, Set<Type>> stuckDeps) {
+            void initNodes() {
                 //add nodes
                 nodes = new ArrayList<>();
                 for (Type t : inferenceContext.restvars()) {
@@ -1955,17 +1915,12 @@
                 //add dependencies
                 for (Node n_i : nodes) {
                     Type i = n_i.data.first();
-                    Set<Type> optDepsByNode = stuckDeps.get(i);
                     for (Node n_j : nodes) {
                         Type j = n_j.data.first();
                         UndetVar uv_i = (UndetVar)inferenceContext.asUndetVar(i);
                         if (Type.containsAny(uv_i.getBounds(InferenceBound.values()), List.of(j))) {
                             //update i's bound dependencies
-                            n_i.addDependency(DependencyKind.BOUND, n_j);
-                        }
-                        if (optDepsByNode != null && optDepsByNode.contains(j)) {
-                            //update i's stuck dependencies
-                            n_i.addDependency(DependencyKind.STUCK, n_j);
+                            n_i.addDependency(n_j);
                         }
                     }
                 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java	Thu May 19 19:47:04 2016 +0000
@@ -469,15 +469,11 @@
         }
     }
 
-    private void solve(GraphStrategy ss, Warner warn) {
-        solve(ss, new HashMap<Type, Set<Type>>(), warn);
-    }
-
     /**
      * Solve with given graph strategy.
      */
-    private void solve(GraphStrategy ss, Map<Type, Set<Type>> stuckDeps, Warner warn) {
-        GraphSolver s = infer.new GraphSolver(this, stuckDeps, warn);
+    private void solve(GraphStrategy ss, Warner warn) {
+        GraphSolver s = infer.new GraphSolver(this, warn);
         s.solve(ss);
     }
 
@@ -506,12 +502,12 @@
     /**
      * Solve at least one variable in given list.
      */
-    public void solveAny(List<Type> varsToSolve, Map<Type, Set<Type>> optDeps, Warner warn) {
+    public void solveAny(List<Type> varsToSolve, Warner warn) {
         solve(infer.new BestLeafSolver(varsToSolve.intersect(restvars())) {
             public boolean done() {
                 return instvars().intersect(varsToSolve).nonEmpty();
             }
-        }, optDeps, warn);
+        }, warn);
     }
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java	Thu May 19 19:47:04 2016 +0000
@@ -380,13 +380,17 @@
                 dest = CharBuffer.allocate(newCapacity).put(dest);
             } else if (result.isMalformed() || result.isUnmappable()) {
                 // bad character in input
+                StringBuilder unmappable = new StringBuilder();
+                int len = result.length();
 
-                log.error(new SimpleDiagnosticPosition(dest.limit()),
-                          "illegal.char.for.encoding",
-                          charset == null ? encodingName : charset.name());
+                for (int i = 0; i < len; i++) {
+                    unmappable.append(String.format("%02X", inbuf.get()));
+                }
 
-                // skip past the coding error
-                inbuf.position(inbuf.position() + result.length());
+                String charsetName = charset == null ? encodingName : charset.name();
+
+                log.error(dest.limit(),
+                          Errors.IllegalCharForEncoding(unmappable.toString(), charsetName));
 
                 // undo the flip() to prepare the output buffer
                 // for more translation
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Thu May 19 19:47:04 2016 +0000
@@ -1138,7 +1138,7 @@
                     }
                 }
 
-                if (warn && false) {  // temp disable
+                if (warn && false) {  // temp disable, when enabled, massage examples.not-yet.txt suitably.
                     log.warning(Warnings.LocnUnknownFileOnModulePath(p));
                 }
                 return null;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu May 19 19:47:04 2016 +0000
@@ -522,8 +522,9 @@
 compiler.err.illegal.char=\
     illegal character: ''{0}''
 
+# 0: string, 1: string
 compiler.err.illegal.char.for.encoding=\
-    unmappable character for encoding {0}
+    unmappable character (0x{0}) for encoding {1}
 
 # 0: set of modifier, 1: set of modifier
 compiler.err.illegal.combination.of.modifiers=\
@@ -779,6 +780,10 @@
     bad return type in lambda expression\n\
     {0}
 
+compiler.misc.stat.expr.expected=\
+    lambda body is not compatible with a void functional interface\n\
+    (consider using a block lambda body, or use a statement expression instead)
+
 # 0: type
 compiler.misc.incompatible.ret.type.in.mref=\
     bad return type in method reference\n\
@@ -2747,9 +2752,6 @@
 compiler.err.module.decl.sb.in.module-info.java=\
     module declarations should be in a file named module-info.java
 
-compiler.err.unexpected.after.module=\
-    unexpected input after module declaration
-
 compiler.err.module-info.with.xmodule.sourcepath=\
     illegal combination of -Xmodule and module-info on sourcepath
 
--- a/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java	Thu May 19 19:47:04 2016 +0000
@@ -714,43 +714,43 @@
     }
 
     public String getText(String key) {
-        try {
-            //Check the doclet specific properties file.
-            return getDocletSpecificMsg().getText(key);
-        } catch (Exception e) {
-            //Check the shared properties file.
-            return message.getText(key);
+        // Check the doclet specific properties file.
+        MessageRetriever docletMessage = getDocletSpecificMsg();
+        if (docletMessage.containsKey(key)) {
+            return docletMessage.getText(key);
         }
+        // Check the shared properties file.
+        return message.getText(key);
     }
 
     public String getText(String key, String a1) {
-        try {
-            //Check the doclet specific properties file.
-            return getDocletSpecificMsg().getText(key, a1);
-        } catch (Exception e) {
-            //Check the shared properties file.
-            return message.getText(key, a1);
+        // Check the doclet specific properties file.
+        MessageRetriever docletMessage = getDocletSpecificMsg();
+        if (docletMessage.containsKey(key)) {
+            return docletMessage.getText(key, a1);
         }
+        // Check the shared properties file.
+        return message.getText(key, a1);
     }
 
     public String getText(String key, String a1, String a2) {
-        try {
-            //Check the doclet specific properties file.
-            return getDocletSpecificMsg().getText(key, a1, a2);
-        } catch (Exception e) {
-            //Check the shared properties file.
-            return message.getText(key, a1, a2);
+        // Check the doclet specific properties file.
+        MessageRetriever docletMessage = getDocletSpecificMsg();
+        if (docletMessage.containsKey(key)) {
+            return docletMessage.getText(key, a1, a2);
         }
+        // Check the shared properties file.
+        return message.getText(key, a1, a2);
     }
 
     public String getText(String key, String a1, String a2, String a3) {
-        try {
-            //Check the doclet specific properties file.
-            return getDocletSpecificMsg().getText(key, a1, a2, a3);
-        } catch (Exception e) {
-            //Check the shared properties file.
-            return message.getText(key, a1, a2, a3);
+        // Check the doclet specific properties file.
+        MessageRetriever docletMessage = getDocletSpecificMsg();
+        if (docletMessage.containsKey(key)) {
+            return docletMessage.getText(key, a1, a2, a3);
         }
+        // Check the shared properties file.
+        return message.getText(key, a1, a2, a3);
     }
 
     public abstract Content newContent();
--- a/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java	Thu May 19 19:47:04 2016 +0000
@@ -83,6 +83,34 @@
         this.resourcelocation = resourcelocation;
     }
 
+    private ResourceBundle initRB() {
+        ResourceBundle bundle = messageRB;
+        if (bundle == null) {
+            try {
+                messageRB = bundle =
+                        ResourceBundle.getBundle(resourcelocation, configuration.getLocale());
+            } catch (MissingResourceException e) {
+                throw new Error("Fatal: Resource (" + resourcelocation
+                        + ") for javadoc doclets is missing.");
+            }
+        }
+        return bundle;
+    }
+
+    /**
+     * Determines whether the given <code>key</code> can be retrieved
+     * from this <code>MessageRetriever</code>
+     *
+     * @param key
+     *        the resource <code>key</code>
+     * @return <code>true</code> if the given <code>key</code> is
+     *        contained in the underlying <code>ResourceBundle</code>.
+     */
+    public boolean containsKey(String key) {
+        ResourceBundle bundle = initRB();
+        return bundle.containsKey(key);
+    }
+
     /**
      * Get and format message string from resource
      *
@@ -92,15 +120,8 @@
      * exist in the properties file.
      */
     public String getText(String key, Object... args) throws MissingResourceException {
-        if (messageRB == null) {
-            try {
-                messageRB = ResourceBundle.getBundle(resourcelocation);
-            } catch (MissingResourceException e) {
-                throw new Error("Fatal: Resource (" + resourcelocation +
-                                    ") for javadoc doclets is missing.");
-            }
-        }
-        String message = messageRB.getString(key);
+        ResourceBundle bundle = initRB();
+        String message = bundle.getString(key);
         return MessageFormat.format(message, args);
     }
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java	Thu May 19 19:47:04 2016 +0000
@@ -894,43 +894,43 @@
     }
 
     public String getText(String key) {
-        try {
-            //Check the doclet specific properties file.
-            return getDocletSpecificMsg().getText(key);
-        } catch (Exception e) {
-            //Check the shared properties file.
-            return message.getText(key);
+        // Check the doclet specific properties file.
+        MessageRetriever docletMessage = getDocletSpecificMsg();
+        if (docletMessage.containsKey(key)) {
+            return docletMessage.getText(key);
         }
+        // Check the shared properties file.
+        return message.getText(key);
     }
 
     public String getText(String key, String a1) {
-        try {
-            //Check the doclet specific properties file.
-            return getDocletSpecificMsg().getText(key, a1);
-        } catch (MissingResourceException e) {
-            //Check the shared properties file.
-            return message.getText(key, a1);
+        // Check the doclet specific properties file.
+        MessageRetriever docletMessage = getDocletSpecificMsg();
+        if (docletMessage.containsKey(key)) {
+            return docletMessage.getText(key, a1);
         }
+        // Check the shared properties file.
+        return message.getText(key, a1);
     }
 
     public String getText(String key, String a1, String a2) {
-        try {
-            //Check the doclet specific properties file.
-            return getDocletSpecificMsg().getText(key, a1, a2);
-        } catch (MissingResourceException e) {
-            //Check the shared properties file.
-            return message.getText(key, a1, a2);
+        // Check the doclet specific properties file.
+        MessageRetriever docletMessage = getDocletSpecificMsg();
+        if (docletMessage.containsKey(key)) {
+            return docletMessage.getText(key, a1, a2);
         }
+        // Check the shared properties file.
+        return message.getText(key, a1, a2);
     }
 
     public String getText(String key, String a1, String a2, String a3) {
-        try {
-            //Check the doclet specific properties file.
-            return getDocletSpecificMsg().getText(key, a1, a2, a3);
-        } catch (MissingResourceException e) {
-            //Check the shared properties file.
-            return message.getText(key, a1, a2, a3);
+        // Check the doclet specific properties file.
+        MessageRetriever docletMessage = getDocletSpecificMsg();
+        if (docletMessage.containsKey(key)) {
+            return docletMessage.getText(key, a1, a2, a3);
         }
+        // Check the shared properties file.
+        return message.getText(key, a1, a2, a3);
     }
 
     public abstract Content newContent();
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/MessageRetriever.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/MessageRetriever.java	Thu May 19 19:47:04 2016 +0000
@@ -86,15 +86,32 @@
         this.resourcelocation = resourcelocation;
     }
 
-    private void initRB() {
-        if (messageRB == null) {
+    private ResourceBundle initRB() {
+        ResourceBundle bundle = messageRB;
+        if (bundle == null) {
             try {
-                messageRB = ResourceBundle.getBundle(resourcelocation, configuration.getLocale());
+                messageRB = bundle =
+                        ResourceBundle.getBundle(resourcelocation, configuration.getLocale());
             } catch (MissingResourceException e) {
                 throw new Error("Fatal: Resource (" + resourcelocation
                         + ") for javadoc doclets is missing.");
             }
         }
+        return bundle;
+    }
+
+    /**
+     * Determines whether the given <code>key</code> can be retrieved
+     * from this <code>MessageRetriever</code>
+     *
+     * @param key
+     *        the resource <code>key</code>
+     * @return <code>true</code> if the given <code>key</code> is
+     *        contained in the underlying <code>ResourceBundle</code>.
+     */
+    public boolean containsKey(String key) {
+        ResourceBundle bundle = initRB();
+        return bundle.containsKey(key);
     }
 
     /**
@@ -107,8 +124,8 @@
      * exist in the properties file.
      */
     public String getText(String key, Object... args) throws MissingResourceException {
-        initRB();
-        String message = messageRB.getString(key);
+        ResourceBundle bundle = initRB();
+        String message = bundle.getString(key);
         return MessageFormat.format(message, args);
     }
 
--- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Dependencies.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Dependencies.java	Thu May 19 19:47:04 2016 +0000
@@ -33,6 +33,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.regex.Pattern;
 
 import com.sun.tools.classfile.Dependency.Filter;
@@ -561,13 +562,10 @@
     }
 
     static abstract class BasicDependencyFinder implements Finder {
-        private Map<String,Location> locations = new HashMap<>();
+        private Map<String,Location> locations = new ConcurrentHashMap<>();
 
         Location getLocation(String className) {
-            Location l = locations.get(className);
-            if (l == null)
-                locations.put(className, l = new SimpleLocation(className));
-            return l;
+            return locations.computeIfAbsent(className, cn -> new SimpleLocation(cn));
         }
 
         class Visitor implements ConstantPool.Visitor<Void,Void>, Type.Visitor<Void, Void> {
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java	Thu May 19 19:47:04 2016 +0000
@@ -25,23 +25,24 @@
 
 package com.sun.tools.jdeps;
 
-import java.io.PrintStream;
-import java.util.ArrayList;
+import static com.sun.tools.jdeps.JdepsConfiguration.*;
+
+import com.sun.tools.classfile.Dependency.Location;
+import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
+import java.util.MissingResourceException;
 import java.util.Objects;
+import java.util.Optional;
+import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import com.sun.tools.classfile.Dependency.Location;
-
 /**
  * Dependency Analyzer.
  */
@@ -52,6 +53,7 @@
      */
     public enum Type {
         SUMMARY,
+        MODULE,  // equivalent to summary in addition, print module descriptor
         PACKAGE,
         CLASS,
         VERBOSE
@@ -62,9 +64,11 @@
      * Only the accepted dependencies are recorded.
      */
     interface Filter {
-        boolean accepts(Location origin, Archive originArchive, Location target, Archive targetArchive);
+        boolean accepts(Location origin, Archive originArchive,
+                        Location target, Archive targetArchive);
     }
 
+    protected final JdepsConfiguration configuration;
     protected final Type type;
     protected final Filter filter;
     protected final Map<Archive, Dependences> results = new HashMap<>();
@@ -78,7 +82,8 @@
      * @param type Type of the dependency analysis
      * @param filter
      */
-    public Analyzer(Type type, Filter filter) {
+    Analyzer(JdepsConfiguration config, Type type, Filter filter) {
+        this.configuration = config;
         this.type = type;
         this.filter = filter;
     }
@@ -86,16 +91,10 @@
     /**
      * Performs the dependency analysis on the given archives.
      */
-    public boolean run(Stream<? extends Archive> archives) {
-        return run(archives.collect(Collectors.toList()));
-    }
-
-    /**
-     * Performs the dependency analysis on the given archives.
-     */
-    public boolean run(Iterable<? extends Archive> archives) {
-        // build a map from Location to Archive
-        buildLocationArchiveMap(archives);
+    boolean run(Iterable<? extends Archive> archives,
+                Map<Location, Archive> locationMap)
+    {
+        this.locationToArchive.putAll(locationMap);
 
         // traverse and analyze all dependencies
         for (Archive archive : archives) {
@@ -106,40 +105,50 @@
         return true;
     }
 
-    protected void buildLocationArchiveMap(Iterable<? extends Archive> archives) {
-        // build a map from Location to Archive
-        for (Archive archive: archives) {
-            archive.getClasses()
-                   .forEach(l -> locationToArchive.putIfAbsent(l, archive));
-        }
+    /**
+     * Returns the analyzed archives
+     */
+    Set<Archive> archives() {
+        return results.keySet();
     }
 
-    public boolean hasDependences(Archive archive) {
+    /**
+     * Returns true if the given archive has dependences.
+     */
+    boolean hasDependences(Archive archive) {
         if (results.containsKey(archive)) {
             return results.get(archive).dependencies().size() > 0;
         }
         return false;
     }
 
-    public Set<String> dependences(Archive source) {
+    /**
+     * Returns the dependences, either class name or package name
+     * as specified in the given verbose level, from the given source.
+     */
+    Set<String> dependences(Archive source) {
         if (!results.containsKey(source)) {
             return Collections.emptySet();
         }
-        Dependences result = results.get(source);
-        return result.dependencies().stream()
-                     .map(Dep::target)
-                     .collect(Collectors.toSet());
+
+        return results.get(source).dependencies()
+                      .stream()
+                      .map(Dep::target)
+                      .collect(Collectors.toSet());
     }
 
-    public Stream<Archive> requires(Archive source) {
+    /**
+     * Returns the direct dependences of the given source
+     */
+    Stream<Archive> requires(Archive source) {
         if (!results.containsKey(source)) {
             return Stream.empty();
         }
-        Dependences result = results.get(source);
-        return result.requires().stream().filter(a -> !a.isEmpty());
+        return results.get(source).requires()
+                      .stream();
     }
 
-    public interface Visitor {
+    interface Visitor {
         /**
          * Visits a recorded dependency from origin to target which can be
          * a fully-qualified classname, a package name, a module or
@@ -153,7 +162,7 @@
      * Visit the dependencies of the given source.
      * If the requested level is SUMMARY, it will visit the required archives list.
      */
-    public void visitDependences(Archive source, Visitor v, Type level) {
+    void visitDependences(Archive source, Visitor v, Type level) {
         if (level == Type.SUMMARY) {
             final Dependences result = results.get(source);
             final Set<Archive> reqs = result.requires();
@@ -187,7 +196,7 @@
         }
     }
 
-    public void visitDependences(Archive source, Visitor v) {
+    void visitDependences(Archive source, Visitor v) {
         visitDependences(source, v, type);
     }
 
@@ -224,14 +233,28 @@
             }
         }
 
+        /*
+         * Returns the archive that contains the given location.
+         */
         Archive findArchive(Location t) {
+            // local in this archive
             if (archive.getClasses().contains(t))
                 return archive;
 
-            return locationToArchive.computeIfAbsent(t, _k -> NOT_FOUND);
+            Archive target;
+            if (locationToArchive.containsKey(t)) {
+                target = locationToArchive.get(t);
+            } else {
+                // special case JDK removed API
+                target = configuration.findClass(t)
+                    .orElseGet(() -> REMOVED_JDK_INTERNALS.contains(t)
+                                        ? REMOVED_JDK_INTERNALS
+                                        : NOT_FOUND);
+            }
+            return locationToArchive.computeIfAbsent(t, _k -> target);
         }
 
-        // return classname or package name depedning on the level
+        // return classname or package name depending on the level
         private String getLocationName(Location o) {
             if (level == Type.CLASS || level == Type.VERBOSE) {
                 return o.getClassName();
@@ -345,4 +368,66 @@
                     target, targetArchive.getName());
         }
     }
+
+    private static final JdkInternals REMOVED_JDK_INTERNALS = new JdkInternals();
+
+    private static class JdkInternals extends Module {
+        private final String BUNDLE = "com.sun.tools.jdeps.resources.jdkinternals";
+
+        private final Set<String> jdkinternals;
+        private final Set<String> jdkUnsupportedClasses;
+        private JdkInternals() {
+            super("JDK removed internal API");
+
+            try {
+                ResourceBundle rb = ResourceBundle.getBundle(BUNDLE);
+                this.jdkinternals = rb.keySet();
+            } catch (MissingResourceException e) {
+                throw new InternalError("Cannot find jdkinternals resource bundle");
+            }
+
+            this.jdkUnsupportedClasses = getUnsupportedClasses();
+        }
+
+        public boolean contains(Location location) {
+            if (jdkUnsupportedClasses.contains(location.getName() + ".class")) {
+                return false;
+            }
+
+            String cn = location.getClassName();
+            int i = cn.lastIndexOf('.');
+            String pn = i > 0 ? cn.substring(0, i) : "";
+            return jdkinternals.contains(cn) || jdkinternals.contains(pn);
+        }
+
+        @Override
+        public String name() {
+            return getName();
+        }
+
+        @Override
+        public boolean isExported(String pn) {
+            return false;
+        }
+
+        private Set<String> getUnsupportedClasses() {
+            // jdk.unsupported may not be observable
+            Optional<Module> om = Profile.FULL_JRE.findModule(JDK_UNSUPPORTED);
+            if (om.isPresent()) {
+                return om.get().reader().entries();
+            }
+
+            // find from local run-time image
+            SystemModuleFinder system = new SystemModuleFinder();
+            if (system.find(JDK_UNSUPPORTED).isPresent()) {
+                try {
+                    return system.getClassReader(JDK_UNSUPPORTED).entries();
+                } catch (IOException e) {
+                    throw new UncheckedIOException(e);
+                }
+            }
+
+            return Collections.emptySet();
+        }
+    }
 }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Archive.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Archive.java	Thu May 19 19:47:04 2016 +0000
@@ -38,6 +38,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
 
 /**
  * Represents the source of the class files.
@@ -86,6 +87,10 @@
         return Module.UNNAMED_MODULE;
     }
 
+    public boolean contains(String entry) {
+        return reader.entries().contains(entry);
+    }
+
     public void addClass(Location origin) {
         deps.computeIfAbsent(origin, _k -> new HashSet<>());
     }
@@ -98,6 +103,15 @@
         return deps.keySet();
     }
 
+    public Stream<Location> getDependencies() {
+        return deps.values().stream()
+                   .flatMap(Set::stream);
+    }
+
+    public boolean hasDependences() {
+        return getDependencies().count() > 0;
+    }
+
     public void visitDependences(Visitor v) {
         for (Map.Entry<Location,Set<Location>> e: deps.entrySet()) {
             for (Location target : e.getValue()) {
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Thu May 19 19:47:04 2016 +0000
@@ -173,7 +173,7 @@
 
     static boolean isClass(Path file) {
         String fn = file.getFileName().toString();
-        return fn.endsWith(".class") && !fn.equals(MODULE_INFO);
+        return fn.endsWith(".class");
     }
 
     class FileIterator implements Iterator<ClassFile> {
@@ -306,7 +306,7 @@
         protected Set<String> scan() {
             try (JarFile jf = new JarFile(path.toFile())) {
                 return jf.stream().map(JarEntry::getName)
-                         .filter(n -> n.endsWith(".class") && !n.endsWith(MODULE_INFO))
+                         .filter(n -> n.endsWith(".class"))
                          .collect(Collectors.toSet());
             } catch (IOException e) {
                 throw new UncheckedIOException(e);
@@ -409,7 +409,7 @@
             while (entries.hasMoreElements()) {
                 JarEntry e = entries.nextElement();
                 String name = e.getName();
-                if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
+                if (name.endsWith(".class")) {
                     return e;
                 }
             }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java	Thu May 19 19:47:04 2016 +0000
@@ -24,360 +24,285 @@
  */
 package com.sun.tools.jdeps;
 
+import static com.sun.tools.jdeps.Module.*;
+import static com.sun.tools.jdeps.Analyzer.NOT_FOUND;
+import static java.util.stream.Collectors.*;
+
 import com.sun.tools.classfile.AccessFlags;
 import com.sun.tools.classfile.ClassFile;
 import com.sun.tools.classfile.ConstantPoolException;
 import com.sun.tools.classfile.Dependencies;
 import com.sun.tools.classfile.Dependency;
+import com.sun.tools.classfile.Dependency.Location;
 
 import java.io.IOException;
-import java.nio.file.Path;
-import java.util.ArrayList;
+import java.io.UncheckedIOException;
 import java.util.Deque;
 import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.HashSet;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedDeque;
-import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.FutureTask;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static com.sun.tools.jdeps.Module.*;
-import static com.sun.tools.jdeps.ModulePaths.SystemModulePath.JAVA_BASE;
+/**
+ * Parses class files and finds dependences
+ */
+class DependencyFinder {
+    private static Finder API_FINDER = new Finder(true);
+    private static Finder CLASS_FINDER = new Finder(false);
 
-public class DependencyFinder {
-    private final List<Archive> roots = new ArrayList<>();
-    private final List<Archive> classpaths = new ArrayList<>();
-    private final List<Module> modulepaths = new ArrayList<>();
-    private final List<String> classes = new ArrayList<>();
-    private final boolean compileTimeView;
+    private final JdepsConfiguration configuration;
+    private final JdepsFilter filter;
 
-    DependencyFinder(boolean compileTimeView) {
-        this.compileTimeView = compileTimeView;
+    private final Map<Finder, Deque<Archive>> parsedArchives = new ConcurrentHashMap<>();
+    private final Map<Location, Archive> parsedClasses = new ConcurrentHashMap<>();
+
+    private final ExecutorService pool = Executors.newFixedThreadPool(2);
+    private final Deque<FutureTask<Set<Location>>> tasks = new ConcurrentLinkedDeque<>();
+
+    DependencyFinder(JdepsConfiguration configuration,
+                     JdepsFilter filter) {
+        this.configuration = configuration;
+        this.filter = filter;
+        this.parsedArchives.put(API_FINDER, new ConcurrentLinkedDeque<>());
+        this.parsedArchives.put(CLASS_FINDER, new ConcurrentLinkedDeque<>());
+    }
+
+    Map<Location, Archive> locationToArchive() {
+        return parsedClasses;
+    }
+
+    /**
+     * Returns the modules of all dependencies found
+     */
+    Stream<Archive> getDependences(Archive source) {
+        return source.getDependencies()
+                     .map(this::locationToArchive)
+                     .filter(a -> a != source);
+    }
+
+    /**
+     * Returns the location to archive map; or NOT_FOUND.
+     *
+     * Location represents a parsed class.
+     */
+    Archive locationToArchive(Location location) {
+        return parsedClasses.containsKey(location)
+            ? parsedClasses.get(location)
+            : configuration.findClass(location).orElse(NOT_FOUND);
+    }
+
+    /**
+     * Returns a map from an archive to its required archives
+     */
+    Map<Archive, Set<Archive>> dependences() {
+        Map<Archive, Set<Archive>> map = new HashMap<>();
+        parsedArchives.values().stream()
+            .flatMap(Deque::stream)
+            .filter(a -> !a.isEmpty())
+            .forEach(source -> {
+                Set<Archive> deps = getDependences(source).collect(toSet());
+                if (!deps.isEmpty()) {
+                    map.put(source, deps);
+                }
+        });
+        return map;
+    }
+
+    boolean isParsed(Location location) {
+        return parsedClasses.containsKey(location);
+    }
+
+    /**
+     * Parses all class files from the given archive stream and returns
+     * all target locations.
+     */
+    public Set<Location> parse(Stream<? extends Archive> archiveStream) {
+        archiveStream.forEach(archive -> parse(archive, CLASS_FINDER));
+        return waitForTasksCompleted();
+    }
+
+    /**
+     * Parses the exported API class files from the given archive stream and
+     * returns all target locations.
+     */
+    public Set<Location> parseExportedAPIs(Stream<? extends Archive> archiveStream) {
+        archiveStream.forEach(archive -> parse(archive, API_FINDER));
+        return waitForTasksCompleted();
+    }
+
+    /**
+     * Parses the named class from the given archive and
+     * returns all target locations the named class references.
+     */
+    public Set<Location> parse(Archive archive, String name) {
+        try {
+            return parse(archive, CLASS_FINDER, name);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    /**
+     * Parses the exported API of the named class from the given archive and
+     * returns all target locations the named class references.
+     */
+    public Set<Location> parseExportedAPIs(Archive archive, String name)
+    {
+        try {
+            return parse(archive, API_FINDER, name);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private Optional<FutureTask<Set<Location>>> parse(Archive archive, Finder finder) {
+        if (parsedArchives.get(finder).contains(archive))
+            return Optional.empty();
+
+        parsedArchives.get(finder).add(archive);
+
+        trace("parsing %s %s%n", archive.getName(), archive.path());
+        FutureTask<Set<Location>> task = new FutureTask<>(new Callable<>() {
+            public Set<Location> call() throws Exception {
+                Set<Location> targets = new HashSet<>();
+                for (ClassFile cf : archive.reader().getClassFiles()) {
+                    String classFileName;
+                    try {
+                        classFileName = cf.getName();
+                    } catch (ConstantPoolException e) {
+                        throw new Dependencies.ClassFileError(e);
+                    }
+
+                    // filter source class/archive
+                    String cn = classFileName.replace('/', '.');
+                    if (!finder.accept(archive, cn, cf.access_flags))
+                        continue;
+
+                    // tests if this class matches the -include
+                    if (!filter.matches(cn))
+                        continue;
+
+                    for (Dependency d : finder.findDependencies(cf)) {
+                        if (filter.accepts(d)) {
+                            archive.addClass(d.getOrigin(), d.getTarget());
+                            targets.add(d.getTarget());
+                        } else {
+                            // ensure that the parsed class is added the archive
+                            archive.addClass(d.getOrigin());
+                        }
+                        parsedClasses.putIfAbsent(d.getOrigin(), archive);
+                    }
+                }
+
+                return targets;
+            }
+        });
+        tasks.add(task);
+        pool.submit(task);
+        return Optional.of(task);
+    }
+
+    private Set<Location> parse(Archive archive, Finder finder, String name)
+        throws IOException
+    {
+        ClassFile cf = archive.reader().getClassFile(name);
+        if (cf == null) {
+            throw new IllegalArgumentException(archive.getName() + " does not contain " + name);
+        }
+
+        Set<Location> targets = new HashSet<>();
+        String cn;
+        try {
+            cn =  cf.getName().replace('/', '.');
+        } catch (ConstantPoolException e) {
+            throw new Dependencies.ClassFileError(e);
+        }
+
+        if (!finder.accept(archive, cn, cf.access_flags))
+            return targets;
+
+        // tests if this class matches the -include
+        if (!filter.matches(cn))
+            return targets;
+
+        // skip checking filter.matches
+        for (Dependency d : finder.findDependencies(cf)) {
+            if (filter.accepts(d)) {
+                targets.add(d.getTarget());
+                archive.addClass(d.getOrigin(), d.getTarget());
+            } else {
+                // ensure that the parsed class is added the archive
+                archive.addClass(d.getOrigin());
+            }
+            parsedClasses.putIfAbsent(d.getOrigin(), archive);
+        }
+        return targets;
     }
 
     /*
-     * Adds a class name to the root set
+     * Waits until all submitted tasks are completed.
      */
-    void addClassName(String cn) {
-        classes.add(cn);
+    private Set<Location> waitForTasksCompleted() {
+        try {
+            Set<Location> targets = new HashSet<>();
+            FutureTask<Set<Location>> task;
+            while ((task = tasks.poll()) != null) {
+                // wait for completion
+                if (!task.isDone())
+                    targets.addAll(task.get());
+            }
+            return targets;
+        } catch (InterruptedException|ExecutionException e) {
+            throw new Error(e);
+        }
     }
 
     /*
-     * Adds the archive of the given path to the root set
+     * Shutdown the executor service.
      */
-    void addRoot(Path path) {
-        addRoot(Archive.getInstance(path));
+    void shutdown() {
+        pool.shutdown();
     }
 
-    /*
-     * Adds the given archive to the root set
-     */
-    void addRoot(Archive archive) {
-        Objects.requireNonNull(archive);
-        if (!roots.contains(archive))
-            roots.add(archive);
+    private interface SourceFilter {
+        boolean accept(Archive archive, String cn, AccessFlags accessFlags);
     }
 
-    /**
-     * Add an archive specified in the classpath.
-     */
-    void addClassPathArchive(Path path) {
-        addClassPathArchive(Archive.getInstance(path));
-    }
+    private static class Finder implements Dependency.Finder, SourceFilter {
+        private final Dependency.Finder finder;
+        private final boolean apiOnly;
+        Finder(boolean apiOnly) {
+            this.apiOnly = apiOnly;
+            this.finder = apiOnly
+                ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED)
+                : Dependencies.getClassDependencyFinder();
 
-    /**
-     * Add an archive specified in the classpath.
-     */
-    void addClassPathArchive(Archive archive) {
-        Objects.requireNonNull(archive);
-        classpaths.add(archive);
-    }
-
-    /**
-     * Add an archive specified in the modulepath.
-     */
-    void addModule(Module m) {
-        Objects.requireNonNull(m);
-        modulepaths.add(m);
-    }
-
-    /**
-     * Returns the root set.
-     */
-    List<Archive> roots() {
-        return roots;
-    }
-
-    /**
-     * Returns a stream of all archives including the root set, module paths,
-     * and classpath.
-     *
-     * This only returns the archives with classes parsed.
-     */
-    Stream<Archive> archives() {
-        Stream<Archive> archives = Stream.concat(roots.stream(), modulepaths.stream());
-        archives = Stream.concat(archives, classpaths.stream());
-        return archives.filter(a -> !a.isEmpty())
-                       .distinct();
-    }
-
-    /**
-     * Finds dependencies
-     *
-     * @param apiOnly  API only
-     * @param maxDepth depth of transitive dependency analysis; zero indicates
-     * @throws IOException
-     */
-    void findDependencies(JdepsFilter filter, boolean apiOnly, int maxDepth)
-            throws IOException
-    {
-        Dependency.Finder finder =
-                apiOnly ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED)
-                        : Dependencies.getClassDependencyFinder();
-
-        // list of archives to be analyzed
-        Set<Archive> roots = new LinkedHashSet<>(this.roots);
-
-        // include java.base in root set
-        roots.add(JAVA_BASE);
-
-        // If -include pattern specified, classes may be in module path or class path.
-        // To get compile time view analysis, all classes are analyzed.
-        // add all modules except JDK modules to root set
-        modulepaths.stream()
-                   .filter(filter::matches)
-                   .forEach(roots::add);
-
-        // add classpath to the root set
-        classpaths.stream()
-                .filter(filter::matches)
-                .forEach(roots::add);
-
-        // transitive dependency
-        int depth = maxDepth > 0 ? maxDepth : Integer.MAX_VALUE;
-
-        // Work queue of names of classfiles to be searched.
-        // Entries will be unique, and for classes that do not yet have
-        // dependencies in the results map.
-        ConcurrentLinkedDeque<String> deque = new ConcurrentLinkedDeque<>();
-        ConcurrentSkipListSet<String> doneClasses = new ConcurrentSkipListSet<>();
-
-        TaskExecutor executor = new TaskExecutor(finder, filter, apiOnly, deque, doneClasses);
-        try {
-            // get the immediate dependencies of the input files
-            for (Archive source : roots) {
-                executor.task(source, deque);
-            }
-            executor.waitForTasksCompleted();
-
-            List<Archive> archives = Stream.concat(Stream.concat(roots.stream(),
-                    modulepaths.stream()),
-                    classpaths.stream())
-                    .collect(Collectors.toList());
-
-            // Additional pass to find archive where dependences are identified
-            // and also any specified classes, if any.
-            // If -R is specified, perform transitive dependency analysis.
-            Deque<String> unresolved = new LinkedList<>(classes);
-            do {
-                String name;
-                while ((name = unresolved.poll()) != null) {
-                    if (doneClasses.contains(name)) {
-                        continue;
-                    }
-                    if (compileTimeView) {
-                        final String cn = name + ".class";
-                        // parse all classes in the source archive
-                        Optional<Archive> source = archives.stream()
-                                .filter(a -> a.reader().entries().contains(cn))
-                                .findFirst();
-                        trace("%s compile time view %s%n", name, source.map(Archive::getName).orElse(" not found"));
-                        if (source.isPresent()) {
-                            executor.runTask(source.get(), deque);
-                        }
-                    }
-                    ClassFile cf = null;
-                    for (Archive archive : archives) {
-                        cf = archive.reader().getClassFile(name);
-
-                        if (cf != null) {
-                            String classFileName;
-                            try {
-                                classFileName = cf.getName();
-                            } catch (ConstantPoolException e) {
-                                throw new Dependencies.ClassFileError(e);
-                            }
-                            if (!doneClasses.contains(classFileName)) {
-                                // if name is a fully-qualified class name specified
-                                // from command-line, this class might already be parsed
-                                doneClasses.add(classFileName);
-                                for (Dependency d : finder.findDependencies(cf)) {
-                                    if (depth == 0) {
-                                        // ignore the dependency
-                                        archive.addClass(d.getOrigin());
-                                        break;
-                                    } else if (filter.accepts(d) && filter.accept(archive)) {
-                                        // continue analysis on non-JDK classes
-                                        archive.addClass(d.getOrigin(), d.getTarget());
-                                        String cn = d.getTarget().getName();
-                                        if (!doneClasses.contains(cn) && !deque.contains(cn)) {
-                                            deque.add(cn);
-                                        }
-                                    } else {
-                                        // ensure that the parsed class is added the archive
-                                        archive.addClass(d.getOrigin());
-                                    }
-                                }
-                            }
-                            break;
-                        }
-                    }
-                    if (cf == null) {
-                        doneClasses.add(name);
-                    }
-                }
-                unresolved = deque;
-                deque = new ConcurrentLinkedDeque<>();
-            } while (!unresolved.isEmpty() && depth-- > 0);
-        } finally {
-            executor.shutdown();
-        }
-     }
-
-    /**
-     * TaskExecutor creates FutureTask to analyze all classes in a given archive
-     */
-    private class TaskExecutor {
-        final ExecutorService pool;
-        final Dependency.Finder finder;
-        final JdepsFilter filter;
-        final boolean apiOnly;
-        final Set<String> doneClasses;
-        final Map<Archive, FutureTask<Void>> tasks = new HashMap<>();
-
-        TaskExecutor(Dependency.Finder finder,
-                     JdepsFilter filter,
-                     boolean apiOnly,
-                     ConcurrentLinkedDeque<String> deque,
-                     Set<String> doneClasses) {
-            this.pool = Executors.newFixedThreadPool(2);
-            this.finder = finder;
-            this.filter = filter;
-            this.apiOnly = apiOnly;
-            this.doneClasses = doneClasses;
         }
 
-        /**
-         * Creates a new task to analyze class files in the given archive.
-         * The dependences are added to the given deque for analysis.
-         */
-        FutureTask<Void> task(Archive archive, final ConcurrentLinkedDeque<String> deque) {
-            trace("parsing %s %s%n", archive.getName(), archive.path());
-            FutureTask<Void> task = new FutureTask<Void>(new Callable<Void>() {
-                public Void call() throws Exception {
-                    for (ClassFile cf : archive.reader().getClassFiles()) {
-                        String classFileName;
-                        try {
-                            classFileName = cf.getName();
-                        } catch (ConstantPoolException e) {
-                            throw new Dependencies.ClassFileError(e);
-                        }
+        @Override
+        public boolean accept(Archive archive, String cn, AccessFlags accessFlags) {
+            int i = cn.lastIndexOf('.');
+            String pn = i > 0 ? cn.substring(0, i) : "";
 
-                        // tests if this class matches the -include
-                        String cn = classFileName.replace('/', '.');
-                        if (!filter.matches(cn))
-                            continue;
-
-                        // if -apionly is specified, analyze only exported and public types
-                        if (apiOnly && !(isExported(archive, cn) && cf.access_flags.is(AccessFlags.ACC_PUBLIC)))
-                            continue;
-
-                        if (!doneClasses.contains(classFileName)) {
-                            doneClasses.add(classFileName);
-                        }
-
-                        for (Dependency d : finder.findDependencies(cf)) {
-                            if (filter.accepts(d) && filter.accept(archive)) {
-                                String name = d.getTarget().getName();
-                                if (!doneClasses.contains(name) && !deque.contains(name)) {
-                                    deque.add(name);
-                                }
-                                archive.addClass(d.getOrigin(), d.getTarget());
-                            } else {
-                                // ensure that the parsed class is added the archive
-                                archive.addClass(d.getOrigin());
-                            }
-                        }
-                    }
-                    return null;
-                }
-            });
-            tasks.put(archive, task);
-            pool.submit(task);
-            return task;
+            // if -apionly is specified, analyze only exported and public types
+            // All packages are exported in unnamed module.
+            return apiOnly ? archive.getModule().isExported(pn) &&
+                                 accessFlags.is(AccessFlags.ACC_PUBLIC)
+                           : true;
         }
 
-        /*
-         * This task will parse all class files of the given archive, if it's a new task.
-         * This method waits until the task is completed.
-         */
-        void runTask(Archive archive, final ConcurrentLinkedDeque<String> deque) {
-            if (tasks.containsKey(archive))
-                return;
-
-            FutureTask<Void> task = task(archive, deque);
-            try {
-                // wait for completion
-                task.get();
-            } catch (InterruptedException|ExecutionException e) {
-                throw new Error(e);
-            }
-        }
-
-        /*
-         * Waits until all submitted tasks are completed.
-         */
-        void waitForTasksCompleted() {
-            try {
-                for (FutureTask<Void> t : tasks.values()) {
-                    if (t.isDone())
-                        continue;
-
-                    // wait for completion
-                    t.get();
-                }
-            } catch (InterruptedException|ExecutionException e) {
-                throw new Error(e);
-            }
-        }
-
-        /*
-         * Shutdown the executor service.
-         */
-        void shutdown() {
-            pool.shutdown();
-        }
-
-        /**
-         * Tests if the given class name is exported by the given archive.
-         *
-         * All packages are exported in unnamed module.
-         */
-        private boolean isExported(Archive archive, String classname) {
-            int i = classname.lastIndexOf('.');
-            String pn = i > 0 ? classname.substring(0, i) : "";
-            return archive.getModule().isExported(pn);
+        @Override
+        public Iterable<? extends Dependency> findDependencies(ClassFile classfile) {
+            return finder.findDependencies(classfile);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DepsAnalyzer.java	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import com.sun.tools.classfile.Dependency.Location;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.sun.tools.jdeps.Analyzer.Type.CLASS;
+import static com.sun.tools.jdeps.Analyzer.Type.VERBOSE;
+import static com.sun.tools.jdeps.Module.trace;
+import static java.util.stream.Collectors.*;
+
+/**
+ * Dependency Analyzer.
+ *
+ * Type of filters:
+ * source filter: -include <pattern>
+ * target filter: -package, -regex, -requires
+ *
+ * The initial archive set for analysis includes
+ * 1. archives specified in the command line arguments
+ * 2. observable modules matching the source filter
+ * 3. classpath archives matching the source filter or target filter
+ * 4. -addmods and -m root modules
+ */
+public class DepsAnalyzer {
+    final JdepsConfiguration configuration;
+    final JdepsFilter filter;
+    final JdepsWriter writer;
+    final Analyzer.Type verbose;
+    final boolean apiOnly;
+
+    final DependencyFinder finder;
+    final Analyzer analyzer;
+    final List<Archive> rootArchives = new ArrayList<>();
+
+    // parsed archives
+    final Set<Archive> archives = new LinkedHashSet<>();
+
+    public DepsAnalyzer(JdepsConfiguration config,
+                        JdepsFilter filter,
+                        JdepsWriter writer,
+                        Analyzer.Type verbose,
+                        boolean apiOnly) {
+        this.configuration = config;
+        this.filter = filter;
+        this.writer = writer;
+        this.verbose = verbose;
+        this.apiOnly = apiOnly;
+
+        this.finder = new DependencyFinder(config, filter);
+        this.analyzer = new Analyzer(configuration, verbose, filter);
+
+        // determine initial archives to be analyzed
+        this.rootArchives.addAll(configuration.initialArchives());
+
+        // if -include pattern is specified, add the matching archives on
+        // classpath to the root archives
+        if (filter.hasIncludePattern() || filter.hasTargetFilter()) {
+            configuration.getModules().values().stream()
+                .filter(source -> filter.include(source) && filter.matches(source))
+                .forEach(this.rootArchives::add);
+        }
+
+        // class path archives
+        configuration.classPathArchives().stream()
+            .filter(filter::matches)
+            .forEach(this.rootArchives::add);
+
+        // Include the root modules for analysis
+        this.rootArchives.addAll(configuration.rootModules());
+
+        trace("analyze root archives: %s%n", this.rootArchives);
+    }
+
+    /*
+     * Perform runtime dependency analysis
+     */
+    public boolean run() throws IOException {
+        return run(false, 1);
+    }
+
+    /**
+     * Perform compile-time view or run-time view dependency analysis.
+     *
+     * @param compileTimeView
+     * @param maxDepth  depth of recursive analysis.  depth == 0 if -R is set
+     */
+    public boolean run(boolean compileTimeView, int maxDepth) throws IOException {
+        try {
+            // parse each packaged module or classpath archive
+            if (apiOnly) {
+                finder.parseExportedAPIs(rootArchives.stream());
+            } else {
+                finder.parse(rootArchives.stream());
+            }
+            archives.addAll(rootArchives);
+
+            int depth = maxDepth > 0 ? maxDepth : Integer.MAX_VALUE;
+
+            // transitive analysis
+            if (depth > 1) {
+                if (compileTimeView)
+                    transitiveArchiveDeps(depth-1);
+                else
+                    transitiveDeps(depth-1);
+            }
+
+            Set<Archive> archives = archives();
+
+            // analyze the dependencies collected
+            analyzer.run(archives, finder.locationToArchive());
+
+            writer.generateOutput(archives, analyzer);
+        } finally {
+            finder.shutdown();
+        }
+        return true;
+    }
+
+    /**
+     * Returns the archives for reporting that has matching dependences.
+     *
+     * If -requires is set, they should be excluded.
+     */
+    Set<Archive> archives() {
+        if (filter.requiresFilter().isEmpty()) {
+            return archives.stream()
+                .filter(filter::include)
+                .filter(Archive::hasDependences)
+                .collect(Collectors.toSet());
+        } else {
+            // use the archives that have dependences and not specified in -requires
+            return archives.stream()
+                .filter(filter::include)
+                .filter(source -> !filter.requiresFilter().contains(source))
+                .filter(source ->
+                        source.getDependencies()
+                              .map(finder::locationToArchive)
+                              .anyMatch(a -> a != source))
+                .collect(Collectors.toSet());
+        }
+    }
+
+    /**
+     * Returns the dependences, either class name or package name
+     * as specified in the given verbose level.
+     */
+    Stream<String> dependences() {
+        return analyzer.archives().stream()
+                       .map(analyzer::dependences)
+                       .flatMap(Set::stream)
+                       .distinct();
+    }
+
+    /**
+     * Returns the archives that contains the given locations and
+     * not parsed and analyzed.
+     */
+    private Set<Archive> unresolvedArchives(Stream<Location> locations) {
+        return locations.filter(l -> !finder.isParsed(l))
+                        .distinct()
+                        .map(configuration::findClass)
+                        .flatMap(Optional::stream)
+                        .filter(filter::include)
+                        .collect(toSet());
+    }
+
+    /*
+     * Recursively analyzes entire module/archives.
+    */
+    private void transitiveArchiveDeps(int depth) throws IOException {
+        Stream<Location> deps = archives.stream()
+                                        .flatMap(Archive::getDependencies);
+
+        // start with the unresolved archives
+        Set<Archive> unresolved = unresolvedArchives(deps);
+        do {
+            // parse all unresolved archives
+            Set<Location> targets = apiOnly
+                ? finder.parseExportedAPIs(unresolved.stream())
+                : finder.parse(unresolved.stream());
+            archives.addAll(unresolved);
+
+            // Add dependencies to the next batch for analysis
+            unresolved = unresolvedArchives(targets.stream());
+        } while (!unresolved.isEmpty() && depth-- > 0);
+    }
+
+    /*
+     * Recursively analyze the class dependences
+     */
+    private void transitiveDeps(int depth) throws IOException {
+        Stream<Location> deps = archives.stream()
+                                        .flatMap(Archive::getDependencies);
+
+        Deque<Location> unresolved = deps.collect(Collectors.toCollection(LinkedList::new));
+        ConcurrentLinkedDeque<Location> deque = new ConcurrentLinkedDeque<>();
+        do {
+            Location target;
+            while ((target = unresolved.poll()) != null) {
+                if (finder.isParsed(target))
+                    continue;
+
+                Archive archive = configuration.findClass(target).orElse(null);
+                if (archive != null && filter.include(archive)) {
+                    archives.add(archive);
+
+                    String name = target.getName();
+                    Set<Location> targets = apiOnly
+                            ? finder.parseExportedAPIs(archive, name)
+                            : finder.parse(archive, name);
+
+                    // build unresolved dependencies
+                    targets.stream()
+                           .filter(t -> !finder.isParsed(t))
+                           .forEach(deque::add);
+                }
+            }
+            unresolved = deque;
+            deque = new ConcurrentLinkedDeque<>();
+        } while (!unresolved.isEmpty() && depth-- > 0);
+    }
+
+    // ----- for testing purpose -----
+
+    public static enum Info {
+        REQUIRES,
+        REQUIRES_PUBLIC,
+        EXPORTED_API,
+        MODULE_PRIVATE,
+        QUALIFIED_EXPORTED_API,
+        INTERNAL_API,
+        JDK_INTERNAL_API
+    }
+
+    public static class Node {
+        public final String name;
+        public final String source;
+        public final Info info;
+        Node(String name, Info info) {
+            this(name, name, info);
+        }
+        Node(String name, String source, Info info) {
+            this.name = name;
+            this.source = source;
+            this.info = info;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (info != Info.REQUIRES && info != Info.REQUIRES_PUBLIC)
+                sb.append(source).append("/");
+
+            sb.append(name);
+            if (info == Info.QUALIFIED_EXPORTED_API)
+                sb.append(" (qualified)");
+            else if (info == Info.JDK_INTERNAL_API)
+                sb.append(" (JDK internal)");
+            else if (info == Info.INTERNAL_API)
+                sb.append(" (internal)");
+            return sb.toString();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof Node))
+                return false;
+
+            Node other = (Node)o;
+            return this.name.equals(other.name) &&
+                    this.source.equals(other.source) &&
+                    this.info.equals(other.info);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = name.hashCode();
+            result = 31 * result + source.hashCode();
+            result = 31 * result + info.hashCode();
+            return result;
+        }
+    }
+
+    /**
+     * Returns a graph of module dependences.
+     *
+     * Each Node represents a module and each edge is a dependence.
+     * No analysis on "requires public".
+     */
+    public Graph<Node> moduleGraph() {
+        Graph.Builder<Node> builder = new Graph.Builder<>();
+
+        archives().stream()
+            .forEach(m -> {
+                Node u = new Node(m.getName(), Info.REQUIRES);
+                builder.addNode(u);
+                analyzer.requires(m)
+                    .map(req -> new Node(req.getName(), Info.REQUIRES))
+                    .forEach(v -> builder.addEdge(u, v));
+            });
+        return builder.build();
+    }
+
+    /**
+     * Returns a graph of dependences.
+     *
+     * Each Node represents a class or package per the specified verbose level.
+     * Each edge indicates
+     */
+    public Graph<Node> dependenceGraph() {
+        Graph.Builder<Node> builder = new Graph.Builder<>();
+
+        archives().stream()
+            .map(analyzer.results::get)
+            .filter(deps -> !deps.dependencies().isEmpty())
+            .flatMap(deps -> deps.dependencies().stream())
+            .forEach(d -> addEdge(builder, d));
+        return builder.build();
+    }
+
+    private void addEdge(Graph.Builder<Node> builder, Analyzer.Dep dep) {
+        Archive source = dep.originArchive();
+        Archive target = dep.targetArchive();
+        String pn = dep.target();
+        if ((verbose == CLASS || verbose == VERBOSE)) {
+            int i = dep.target().lastIndexOf('.');
+            pn = i > 0 ? dep.target().substring(0, i) : "";
+        }
+        final Info info;
+        if (source == target) {
+            info = Info.MODULE_PRIVATE;
+        } else if (!target.getModule().isNamed()) {
+            info = Info.EXPORTED_API;
+        } else if (target.getModule().isExported(pn)) {
+            info = Info.EXPORTED_API;
+        } else {
+            Module module = target.getModule();
+
+            if (!source.getModule().isJDK() && module.isJDK())
+                info = Info.JDK_INTERNAL_API;
+                // qualified exports or inaccessible
+            else if (module.isExported(pn, source.getModule().name()))
+                info = Info.QUALIFIED_EXPORTED_API;
+            else
+                info = Info.INTERNAL_API;
+        }
+
+        Node u = new Node(dep.origin(), source.getName(), info);
+        Node v = new Node(dep.target(), target.getName(), info);
+        builder.addEdge(u, v);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Graph.java	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import java.io.PrintWriter;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public final class Graph<T> {
+    private final Set<T> nodes;
+    private final Map<T, Set<T>> edges;
+
+    public Graph(Set<T> nodes, Map<T, Set<T>> edges) {
+        this.nodes = Collections.unmodifiableSet(nodes);
+        this.edges = Collections.unmodifiableMap(edges);
+    }
+
+    public Set<T> nodes() {
+        return nodes;
+    }
+
+    public Map<T, Set<T>> edges() {
+        return edges;
+    }
+
+    public Set<T> adjacentNodes(T u) {
+        return edges.get(u);
+    }
+
+    public boolean contains(T u) {
+        return nodes.contains(u);
+    }
+
+    public Set<Edge<T>> edgesFrom(T u) {
+        return edges.get(u).stream()
+                    .map(v -> new Edge<T>(u, v))
+                    .collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns a new Graph after transitive reduction
+     */
+    public Graph<T> reduce() {
+        Builder<T> builder = new Builder<>();
+        nodes.stream()
+                .forEach(u -> {
+                    builder.addNode(u);
+                    edges.get(u).stream()
+                         .filter(v -> !pathExists(u, v, false))
+                         .forEach(v -> builder.addEdge(u, v));
+                });
+        return builder.build();
+    }
+
+    /**
+     * Returns a new Graph after transitive reduction.  All edges in
+     * the given g takes precedence over this graph.
+     *
+     * @throw IllegalArgumentException g must be a subgraph this graph
+     */
+    public Graph<T> reduce(Graph<T> g) {
+        boolean subgraph = nodes.containsAll(g.nodes) &&
+                g.edges.keySet().stream()
+                       .allMatch(u -> adjacentNodes(u).containsAll(g.adjacentNodes(u)));
+        if (!subgraph) {
+            throw new IllegalArgumentException(g + " is not a subgraph of " + this);
+        }
+
+        Builder<T> builder = new Builder<>();
+        nodes.stream()
+                .forEach(u -> {
+                    builder.addNode(u);
+                    // filter the edge if there exists a path from u to v in the given g
+                    // or there exists another path from u to v in this graph
+                    edges.get(u).stream()
+                         .filter(v -> !g.pathExists(u, v) && !pathExists(u, v, false))
+                         .forEach(v -> builder.addEdge(u, v));
+                });
+
+        // add the overlapped edges from this graph and the given g
+        g.edges().keySet().stream()
+                .forEach(u -> g.adjacentNodes(u).stream()
+                                .filter(v -> isAdjacent(u, v))
+                                .forEach(v -> builder.addEdge(u, v)));
+        return builder.build();
+    }
+
+    /**
+     * Returns nodes sorted in topological order.
+     */
+    public Stream<T> orderedNodes() {
+        TopoSorter<T> sorter = new TopoSorter<>(this);
+        return sorter.result.stream();
+    }
+
+    /**
+     * Traverse this graph and performs the given action in topological order
+     */
+    public void ordered(Consumer<T> action) {
+        TopoSorter<T> sorter = new TopoSorter<>(this);
+        sorter.ordered(action);
+    }
+
+    /**
+     * Traverses this graph and performs the given action in reverse topological order
+     */
+    public void reverse(Consumer<T> action) {
+        TopoSorter<T> sorter = new TopoSorter<>(this);
+        sorter.reverse(action);
+    }
+
+    /**
+     * Returns a transposed graph from this graph
+     */
+    public Graph<T> transpose() {
+        Builder<T> builder = new Builder<>();
+        builder.addNodes(nodes);
+        // reverse edges
+        edges.keySet().forEach(u -> {
+            edges.get(u).stream()
+                .forEach(v -> builder.addEdge(v, u));
+        });
+        return builder.build();
+    }
+
+    /**
+     * Returns all nodes reachable from the given set of roots.
+     */
+    public Set<T> dfs(Set<T> roots) {
+        Deque<T> deque = new LinkedList<>(roots);
+        Set<T> visited = new HashSet<>();
+        while (!deque.isEmpty()) {
+            T u = deque.pop();
+            if (!visited.contains(u)) {
+                visited.add(u);
+                if (contains(u)) {
+                    adjacentNodes(u).stream()
+                        .filter(v -> !visited.contains(v))
+                        .forEach(deque::push);
+                }
+            }
+        }
+        return visited;
+    }
+
+    private boolean isAdjacent(T u, T v) {
+        return edges.containsKey(u) && edges.get(u).contains(v);
+    }
+
+    private boolean pathExists(T u, T v) {
+        return pathExists(u, v, true);
+    }
+
+    /**
+     * Returns true if there exists a path from u to v in this graph.
+     * If includeAdjacent is false, it returns true if there exists
+     * another path from u to v of distance > 1
+     */
+    private boolean pathExists(T u, T v, boolean includeAdjacent) {
+        if (!nodes.contains(u) || !nodes.contains(v)) {
+            return false;
+        }
+        if (includeAdjacent && isAdjacent(u, v)) {
+            return true;
+        }
+        Deque<T> stack = new LinkedList<>();
+        Set<T> visited = new HashSet<>();
+        stack.push(u);
+        while (!stack.isEmpty()) {
+            T node = stack.pop();
+            if (node.equals(v)) {
+                return true;
+            }
+            if (!visited.contains(node)) {
+                visited.add(node);
+                edges.get(node).stream()
+                     .filter(e -> includeAdjacent || !node.equals(u) || !e.equals(v))
+                     .forEach(e -> stack.push(e));
+            }
+        }
+        assert !visited.contains(v);
+        return false;
+    }
+
+    public void printGraph(PrintWriter out) {
+        out.println("graph for " + nodes);
+        nodes.stream()
+             .forEach(u -> adjacentNodes(u).stream()
+                               .forEach(v -> out.format("  %s -> %s%n", u, v)));
+    }
+
+    @Override
+    public String toString() {
+        return nodes.toString();
+    }
+
+    static class Edge<T> {
+        final T u;
+        final T v;
+        Edge(T u, T v) {
+            this.u = u;
+            this.v = v;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("%s -> %s", u, v);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || !(o instanceof Edge))
+                return false;
+
+            @SuppressWarnings("unchecked")
+            Edge<T> edge = (Edge<T>) o;
+
+            return u.equals(edge.u) && v.equals(edge.v);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = u.hashCode();
+            result = 31 * result + v.hashCode();
+            return result;
+        }
+    }
+
+    static class Builder<T> {
+        final Set<T> nodes = new HashSet<>();
+        final Map<T, Set<T>> edges = new HashMap<>();
+
+        public void addNode(T node) {
+            if (nodes.contains(node)) {
+                return;
+            }
+            nodes.add(node);
+            edges.computeIfAbsent(node, _e -> new HashSet<>());
+        }
+
+        public void addNodes(Set<T> nodes) {
+            nodes.addAll(nodes);
+        }
+
+        public void addEdge(T u, T v) {
+            addNode(u);
+            addNode(v);
+            edges.get(u).add(v);
+        }
+
+        public Graph<T> build() {
+            return new Graph<T>(nodes, edges);
+        }
+    }
+
+    /**
+     * Topological sort
+     */
+    static class TopoSorter<T> {
+        final Deque<T> result = new LinkedList<>();
+        final Deque<T> nodes;
+        final Graph<T> graph;
+        TopoSorter(Graph<T> graph) {
+            this.graph = graph;
+            this.nodes = new LinkedList<>(graph.nodes);
+            sort();
+        }
+
+        public void ordered(Consumer<T> action) {
+            result.iterator().forEachRemaining(action);
+        }
+
+        public void reverse(Consumer<T> action) {
+            result.descendingIterator().forEachRemaining(action);
+        }
+
+        private void sort() {
+            Deque<T> visited = new LinkedList<>();
+            Deque<T> done = new LinkedList<>();
+            T node;
+            while ((node = nodes.poll()) != null) {
+                if (!visited.contains(node)) {
+                    visit(node, visited, done);
+                }
+            }
+        }
+
+        private void visit(T node, Deque<T> visited, Deque<T> done) {
+            if (visited.contains(node)) {
+                if (!done.contains(node)) {
+                    throw new IllegalArgumentException("Cyclic detected: " +
+                        node + " " + graph.edges().get(node));
+                }
+                return;
+            }
+            visited.add(node);
+            graph.edges().get(node).stream()
+                .forEach(x -> visit(x, visited, done));
+            done.add(node);
+            result.addLast(node);
+        }
+    }
+
+    public static class DotGraph {
+        static final String ORANGE = "#e76f00";
+        static final String BLUE = "#437291";
+        static final String GRAY = "#dddddd";
+
+        static final String REEXPORTS = "";
+        static final String REQUIRES = "style=\"dashed\"";
+        static final String REQUIRES_BASE = "color=\"" + GRAY + "\"";
+
+        static final Set<String> javaModules = modules(name ->
+            (name.startsWith("java.") && !name.equals("java.smartcardio")));
+        static final Set<String> jdkModules = modules(name ->
+            (name.startsWith("java.") ||
+                name.startsWith("jdk.") ||
+                name.startsWith("javafx.")) && !javaModules.contains(name));
+
+        private static Set<String> modules(Predicate<String> predicate) {
+            return ModuleFinder.ofSystem().findAll()
+                               .stream()
+                               .map(ModuleReference::descriptor)
+                               .map(ModuleDescriptor::name)
+                               .filter(predicate)
+                               .collect(Collectors.toSet());
+        }
+
+        static void printAttributes(PrintWriter out) {
+            out.format("  size=\"25,25\";%n");
+            out.format("  nodesep=.5;%n");
+            out.format("  ranksep=1.5;%n");
+            out.format("  pencolor=transparent;%n");
+            out.format("  node [shape=plaintext, fontname=\"DejaVuSans\", fontsize=36, margin=\".2,.2\"];%n");
+            out.format("  edge [penwidth=4, color=\"#999999\", arrowhead=open, arrowsize=2];%n");
+        }
+
+        static void printNodes(PrintWriter out, Graph<String> graph) {
+            out.format("  subgraph se {%n");
+            graph.nodes().stream()
+                 .filter(javaModules::contains)
+                 .forEach(mn -> out.format("  \"%s\" [fontcolor=\"%s\", group=%s];%n",
+                                           mn, ORANGE, "java"));
+            out.format("  }%n");
+            graph.nodes().stream()
+                 .filter(jdkModules::contains)
+                 .forEach(mn -> out.format("    \"%s\" [fontcolor=\"%s\", group=%s];%n",
+                                           mn, BLUE, "jdk"));
+
+            graph.nodes().stream()
+                 .filter(mn -> !javaModules.contains(mn) && !jdkModules.contains(mn))
+                 .forEach(mn -> out.format("  \"%s\";%n", mn));
+        }
+
+        static void printEdges(PrintWriter out, Graph<String> graph,
+                               String node, Set<String> requiresPublic) {
+            graph.adjacentNodes(node).forEach(dn -> {
+                String attr = dn.equals("java.base") ? REQUIRES_BASE
+                        : (requiresPublic.contains(dn) ? REEXPORTS : REQUIRES);
+                out.format("  \"%s\" -> \"%s\" [%s];%n", node, dn, attr);
+            });
+        }
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/InverseDepsAnalyzer.java	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import static com.sun.tools.jdeps.JdepsFilter.DEFAULT_FILTER;
+import static com.sun.tools.jdeps.Module.trace;
+import static com.sun.tools.jdeps.Graph.*;
+
+import java.lang.module.ModuleDescriptor.Requires;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Inverse transitive dependency analysis (compile-time view)
+ */
+public class InverseDepsAnalyzer extends DepsAnalyzer {
+    // the end points for the resulting paths to be reported
+    private final Map<Archive, Set<Archive>> endPoints = new HashMap<>();
+    // target archives for inverse transitive dependence analysis
+    private final Set<Archive> targets = new HashSet<>();
+
+    public InverseDepsAnalyzer(JdepsConfiguration config,
+                               JdepsFilter filter,
+                               JdepsWriter writer,
+                               Analyzer.Type verbose,
+                               boolean apiOnly) {
+        super(config, filter, writer, verbose, apiOnly);
+    }
+
+    public boolean run() throws IOException {
+        try {
+            if (apiOnly) {
+                finder.parseExportedAPIs(rootArchives.stream());
+            } else {
+                finder.parse(rootArchives.stream());
+            }
+            archives.addAll(rootArchives);
+
+            Set<Archive> archives = archives();
+
+            // If -package or -regex is specified, the archives that reference
+            // the matching types are used as the targets for inverse
+            // transitive analysis.  If -requires is specified, the
+            // specified modules are the targets.
+
+            if (filter.requiresFilter().isEmpty()) {
+                targets.addAll(archives);
+            } else {
+                filter.requiresFilter().stream()
+                      .map(configuration::findModule)
+                      .flatMap(Optional::stream)
+                      .forEach(targets::add);
+            }
+
+            // If -package or -regex is specified, the end points are
+            // the matching archives.  If -requires is specified,
+            // the end points are the modules specified in -requires.
+            if (filter.requiresFilter().isEmpty()) {
+                Map<Archive, Set<Archive>> dependences = finder.dependences();
+                targets.forEach(source -> endPoints.put(source, dependences.get(source)));
+            } else {
+                targets.forEach(t -> endPoints.put(t, Collections.emptySet()));
+            }
+
+            analyzer.run(archives, finder.locationToArchive());
+
+            // print the first-level of dependencies
+            if (writer != null) {
+                writer.generateOutput(archives, analyzer);
+            }
+
+        } finally {
+            finder.shutdown();
+        }
+        return true;
+    }
+
+    /**
+     * Returns the target archives determined from the dependency analysis.
+     *
+     * Inverse transitive dependency will find all nodes that depend
+     * upon the returned set of archives directly and indirectly.
+     */
+    public Set<Archive> targets() {
+        return Collections.unmodifiableSet(targets);
+    }
+
+    /**
+     * Finds all inverse transitive dependencies using the given requires set
+     * as the targets, if non-empty.  If the given requires set is empty,
+     * use the archives depending the packages specified in -regex or -p options.
+     */
+    public Set<Deque<Archive>> inverseDependences() throws IOException {
+        // create a new dependency finder to do the analysis
+        DependencyFinder dependencyFinder = new DependencyFinder(configuration, DEFAULT_FILTER);
+        try {
+            // parse all archives in unnamed module to get compile-time dependences
+            Stream<Archive> archives =
+                Stream.concat(configuration.initialArchives().stream(),
+                              configuration.classPathArchives().stream());
+            if (apiOnly) {
+                dependencyFinder.parseExportedAPIs(archives);
+            } else {
+                dependencyFinder.parse(archives);
+            }
+
+            Graph.Builder<Archive> builder = new Graph.Builder<>();
+            // include all target nodes
+            targets().forEach(builder::addNode);
+
+            // transpose the module graph - may filter JDK module
+            configuration.getModules().values().stream()
+                .filter(filter::include)
+                .forEach(m -> {
+                    builder.addNode(m);
+                    m.descriptor().requires().stream()
+                        .map(Requires::name)
+                        .map(configuration::findModule)  // must be present
+                        .forEach(v -> builder.addEdge(v.get(), m));
+                });
+
+            // add the dependences from the analysis
+            Map<Archive, Set<Archive>> dependences = dependencyFinder.dependences();
+            dependences.entrySet().stream()
+                .forEach(e -> {
+                    Archive u = e.getKey();
+                    builder.addNode(u);
+                    e.getValue().forEach(v -> builder.addEdge(v, u));
+                });
+
+            // transposed dependence graph.
+            Graph<Archive> graph = builder.build();
+            trace("targets: %s%n", targets());
+
+            // Traverse from the targets and find all paths
+            // rebuild a graph with all nodes that depends on targets
+            // targets directly and indirectly
+            return targets().stream()
+                .map(t -> findPaths(graph, t))
+                .flatMap(Set::stream)
+                .collect(Collectors.toSet());
+        } finally {
+            dependencyFinder.shutdown();
+        }
+    }
+
+    /**
+     * Returns all paths reachable from the given targets.
+     */
+    private Set<Deque<Archive>> findPaths(Graph<Archive> graph, Archive target) {
+
+        // path is in reversed order
+        Deque<Archive> path = new LinkedList<>();
+        path.push(target);
+
+        Set<Edge<Archive>> visited = new HashSet<>();
+
+        Deque<Edge<Archive>> deque = new LinkedList<>();
+        deque.addAll(graph.edgesFrom(target));
+        if (deque.isEmpty()) {
+            return makePaths(path).collect(Collectors.toSet());
+        }
+
+        Set<Deque<Archive>> allPaths = new HashSet<>();
+        while (!deque.isEmpty()) {
+            Edge<Archive> edge = deque.pop();
+
+            if (visited.contains(edge))
+                continue;
+
+            Archive node = edge.v;
+            path.addLast(node);
+            visited.add(edge);
+
+            Set<Edge<Archive>> unvisitedDeps = graph.edgesFrom(node)
+                    .stream()
+                    .filter(e -> !visited.contains(e))
+                    .collect(Collectors.toSet());
+
+            trace("visiting %s %s (%s)%n", edge, path, unvisitedDeps);
+            if (unvisitedDeps.isEmpty()) {
+                makePaths(path).forEach(allPaths::add);
+                path.removeLast();
+            }
+
+            // push unvisited adjacent edges
+            unvisitedDeps.stream().forEach(deque::push);
+
+
+            // when the adjacent edges of a node are visited, pop it from the path
+            while (!path.isEmpty()) {
+                if (visited.containsAll(graph.edgesFrom(path.peekLast())))
+                    path.removeLast();
+                else
+                    break;
+            }
+        }
+
+       return allPaths;
+    }
+
+    /**
+     * Prepend end point to the path
+     */
+    private Stream<Deque<Archive>> makePaths(Deque<Archive> path) {
+        Set<Archive> nodes = endPoints.get(path.peekFirst());
+        if (nodes == null || nodes.isEmpty()) {
+            return Stream.of(new LinkedList<>(path));
+        } else {
+            return nodes.stream().map(n -> {
+                Deque<Archive> newPath = new LinkedList<>();
+                newPath.addFirst(n);
+                newPath.addAll(path);
+                return newPath;
+            });
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java	Thu May 19 19:47:04 2016 +0000
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2012, 2016, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import static com.sun.tools.jdeps.Module.trace;
+import static java.util.stream.Collectors.*;
+
+import com.sun.tools.classfile.Dependency;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public class JdepsConfiguration {
+    // the token for "all modules on the module path"
+    public static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
+    public static final String ALL_DEFAULT = "ALL-DEFAULT";
+    public static final String MODULE_INFO = "module-info.class";
+
+    private final SystemModuleFinder system;
+    private final ModuleFinder finder;
+
+    private final Map<String, Module> nameToModule = new LinkedHashMap<>();
+    private final Map<String, Module> packageToModule = new HashMap<>();
+    private final Map<String, List<Archive>> packageToUnnamedModule = new HashMap<>();
+
+    private final List<Archive> classpathArchives = new ArrayList<>();
+    private final List<Archive> initialArchives = new ArrayList<>();
+    private final Set<Module> rootModules = new HashSet<>();
+    private final Configuration configuration;
+
+    private JdepsConfiguration(SystemModuleFinder systemModulePath,
+                               ModuleFinder finder,
+                               Set<String> roots,
+                               List<Path> classpaths,
+                               List<Archive> initialArchives,
+                               boolean allDefaultModules)
+        throws IOException
+    {
+        trace("root: %s%n", roots);
+
+        this.system = systemModulePath;
+        this.finder = finder;
+
+        // build root set for resolution
+        Set<String> mods = new HashSet<>(roots);
+
+        // add default modules to the root set
+        // unnamed module
+        if (!initialArchives.isEmpty() || !classpaths.isEmpty() ||
+                roots.isEmpty() || allDefaultModules) {
+            mods.addAll(systemModulePath.defaultSystemRoots());
+        }
+
+        this.configuration = Configuration.empty()
+                .resolveRequires(finder, ModuleFinder.of(), mods);
+
+        this.configuration.modules().stream()
+                .map(ResolvedModule::reference)
+                .forEach(this::addModuleReference);
+
+        // packages in unnamed module
+        initialArchives.forEach(archive -> {
+            addPackagesInUnnamedModule(archive);
+            this.initialArchives.add(archive);
+        });
+
+        // classpath archives
+        for (Path p : classpaths) {
+            if (Files.exists(p)) {
+                Archive archive = Archive.getInstance(p);
+                addPackagesInUnnamedModule(archive);
+                classpathArchives.add(archive);
+            }
+        }
+
+        // all roots specified in -addmods or -m are included
+        // as the initial set for analysis.
+        roots.stream()
+             .map(nameToModule::get)
+             .forEach(this.rootModules::add);
+
+        initProfiles();
+
+        trace("resolved modules: %s%n", nameToModule.keySet().stream()
+                .sorted().collect(joining("\n", "\n", "")));
+    }
+
+    private void initProfiles() {
+        // other system modules are not observed and not added in nameToModule map
+        Map<String, Module> systemModules =
+            system.moduleNames()
+                .collect(toMap(Function.identity(), (mn) -> {
+                    Module m = nameToModule.get(mn);
+                    if (m == null) {
+                        ModuleReference mref = finder.find(mn).get();
+                        m = toModule(mref);
+                    }
+                    return m;
+                }));
+        Profile.init(systemModules);
+    }
+
+    private void addModuleReference(ModuleReference mref) {
+        Module module = toModule(mref);
+        nameToModule.put(mref.descriptor().name(), module);
+        mref.descriptor().packages()
+            .forEach(pn -> packageToModule.putIfAbsent(pn, module));
+    }
+
+    private void addPackagesInUnnamedModule(Archive archive) {
+        archive.reader().entries().stream()
+               .filter(e -> e.endsWith(".class") && !e.equals(MODULE_INFO))
+               .map(this::toPackageName)
+               .distinct()
+               .forEach(pn -> packageToUnnamedModule
+                   .computeIfAbsent(pn, _n -> new ArrayList<>()).add(archive));
+    }
+
+    private String toPackageName(String name) {
+        int i = name.lastIndexOf('/');
+        return i > 0 ? name.replace('/', '.').substring(0, i) : "";
+    }
+
+    public Optional<Module> findModule(String name) {
+        Objects.requireNonNull(name);
+        Module m = nameToModule.get(name);
+        return m!= null ? Optional.of(m) : Optional.empty();
+
+    }
+
+    public Optional<ModuleDescriptor> findModuleDescriptor(String name) {
+        Objects.requireNonNull(name);
+        Module m = nameToModule.get(name);
+        return m!= null ? Optional.of(m.descriptor()) : Optional.empty();
+    }
+
+    boolean isSystem(Module m) {
+        return system.find(m.name()).isPresent();
+    }
+
+    boolean isValidToken(String name) {
+        return ALL_MODULE_PATH.equals(name) || ALL_DEFAULT.equals(name);
+    }
+
+    /**
+     * Returns the modules that the given module can read
+     */
+    public Stream<Module> reads(Module module) {
+        return configuration.findModule(module.name()).get()
+            .reads().stream()
+            .map(ResolvedModule::name)
+            .map(nameToModule::get);
+    }
+
+    /**
+     * Returns the list of packages that split between resolved module and
+     * unnamed module
+     */
+    public Map<String, Set<String>> splitPackages() {
+        Set<String> splitPkgs = packageToModule.keySet().stream()
+                                       .filter(packageToUnnamedModule::containsKey)
+                                       .collect(toSet());
+        if (splitPkgs.isEmpty())
+            return Collections.emptyMap();
+
+        return splitPkgs.stream().collect(toMap(Function.identity(), (pn) -> {
+            Set<String> sources = new LinkedHashSet<>();
+            sources.add(packageToModule.get(pn).getModule().location().toString());
+            packageToUnnamedModule.get(pn).stream()
+                .map(Archive::getPathName)
+                .forEach(sources::add);
+            return sources;
+        }));
+    }
+
+    /**
+     * Returns an optional archive containing the given Location
+     */
+    public Optional<Archive> findClass(Dependency.Location location) {
+        String name = location.getName();
+        int i = name.lastIndexOf('/');
+        String pn = i > 0 ? name.substring(0, i).replace('/', '.') : "";
+        Archive archive = packageToModule.get(pn);
+        if (archive != null) {
+            return archive.contains(name + ".class")
+                        ? Optional.of(archive)
+                        : Optional.empty();
+        }
+
+        if (packageToUnnamedModule.containsKey(pn)) {
+            return packageToUnnamedModule.get(pn).stream()
+                    .filter(a -> a.contains(name + ".class"))
+                    .findFirst();
+        }
+        return Optional.empty();
+    }
+
+    /**
+     * Returns the list of Modules that can be found in the specified
+     * module paths.
+     */
+    public Map<String, Module> getModules() {
+        return nameToModule;
+    }
+
+    public Stream<Module> resolve(Set<String> roots) {
+        if (roots.isEmpty()) {
+            return nameToModule.values().stream();
+        } else {
+            return Configuration.empty()
+                    .resolveRequires(finder, ModuleFinder.of(), roots)
+                    .modules().stream()
+                    .map(ResolvedModule::name)
+                    .map(nameToModule::get);
+        }
+    }
+
+    public List<Archive> classPathArchives() {
+        return classpathArchives;
+    }
+
+    public List<Archive> initialArchives() {
+        return initialArchives;
+    }
+
+    public Set<Module> rootModules() {
+        return rootModules;
+    }
+
+    public Module toModule(ModuleReference mref) {
+        try {
+            String mn = mref.descriptor().name();
+            URI location = mref.location().orElseThrow(FileNotFoundException::new);
+            ModuleDescriptor md = mref.descriptor();
+            Module.Builder builder = new Module.Builder(md, system.find(mn).isPresent());
+
+            final ClassFileReader reader;
+            if (location.getScheme().equals("jrt")) {
+                reader = system.getClassReader(mn);
+            } else {
+                reader = ClassFileReader.newInstance(Paths.get(location));
+            }
+
+            builder.classes(reader);
+            builder.location(location);
+
+            return builder.build();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    static class SystemModuleFinder implements ModuleFinder {
+        private static final String JAVA_HOME = System.getProperty("java.home");
+        private static final String JAVA_SE = "java.se";
+
+        private final FileSystem fileSystem;
+        private final Path root;
+        private final Map<String, ModuleReference> systemModules;
+
+        SystemModuleFinder() {
+            if (Files.isRegularFile(Paths.get(JAVA_HOME, "lib", "modules"))) {
+                // jrt file system
+                this.fileSystem = FileSystems.getFileSystem(URI.create("jrt:/"));
+                this.root = fileSystem.getPath("/modules");
+                this.systemModules = walk(root);
+            } else {
+                // exploded image
+                this.fileSystem = FileSystems.getDefault();
+                root = Paths.get(JAVA_HOME, "modules");
+                this.systemModules = ModuleFinder.ofSystem().findAll().stream()
+                    .collect(toMap(mref -> mref.descriptor().name(), Function.identity()));
+            }
+        }
+
+        SystemModuleFinder(String javaHome) throws IOException {
+            if (javaHome == null) {
+                // -system none
+                this.fileSystem = null;
+                this.root = null;
+                this.systemModules = Collections.emptyMap();
+            } else {
+                if (Files.isRegularFile(Paths.get(javaHome, "lib", "modules")))
+                    throw new IllegalArgumentException("Invalid java.home: " + javaHome);
+
+                // alternate java.home
+                Map<String, String> env = new HashMap<>();
+                env.put("java.home", javaHome);
+                // a remote run-time image
+                this.fileSystem = FileSystems.newFileSystem(URI.create("jrt:/"), env);
+                this.root = fileSystem.getPath("/modules");
+                this.systemModules = walk(root);
+            }
+        }
+
+        private Map<String, ModuleReference> walk(Path root) {
+            try {
+                return Files.walk(root, 1)
+                    .filter(path -> !path.equals(root))
+                    .map(this::toModuleReference)
+                    .collect(toMap(mref -> mref.descriptor().name(),
+                                    Function.identity()));
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }
+
+        private ModuleReference toModuleReference(Path path) {
+            Path minfo = path.resolve(MODULE_INFO);
+            try (InputStream in = Files.newInputStream(minfo);
+                 BufferedInputStream bin = new BufferedInputStream(in)) {
+
+                ModuleDescriptor descriptor = dropHashes(ModuleDescriptor.read(bin));
+                String mn = descriptor.name();
+                URI uri = URI.create("jrt:/" + path.getFileName().toString());
+                Supplier<ModuleReader> readerSupplier = new Supplier<>() {
+                    @Override
+                    public ModuleReader get() {
+                        return new ModuleReader() {
+                            @Override
+                            public Optional<URI> find(String name) throws IOException {
+                                return name.equals(mn)
+                                    ? Optional.of(uri) : Optional.empty();
+                            }
+
+                            @Override
+                            public void close() throws IOException {
+                            }
+                        };
+                    }
+                };
+
+                return new ModuleReference(descriptor, uri, readerSupplier);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }
+
+        private ModuleDescriptor dropHashes(ModuleDescriptor md) {
+            ModuleDescriptor.Builder builder = new ModuleDescriptor.Builder(md.name());
+            md.requires().forEach(builder::requires);
+            md.exports().forEach(builder::exports);
+            md.provides().values().stream().forEach(builder::provides);
+            md.uses().stream().forEach(builder::uses);
+            builder.conceals(md.conceals());
+            return builder.build();
+        }
+
+        @Override
+        public Set<ModuleReference> findAll() {
+            return systemModules.values().stream().collect(toSet());
+        }
+
+        @Override
+        public Optional<ModuleReference> find(String mn) {
+            return systemModules.containsKey(mn)
+                    ? Optional.of(systemModules.get(mn)) : Optional.empty();
+        }
+
+        public Stream<String> moduleNames() {
+            return systemModules.values().stream()
+                .map(mref -> mref.descriptor().name());
+        }
+
+        public ClassFileReader getClassReader(String modulename) throws IOException {
+            Path mp = root.resolve(modulename);
+            if (Files.exists(mp) && Files.isDirectory(mp)) {
+                return ClassFileReader.newInstance(fileSystem, mp);
+            } else {
+                throw new FileNotFoundException(mp.toString());
+            }
+        }
+
+        public Set<String> defaultSystemRoots() {
+            Set<String> roots = new HashSet<>();
+            boolean hasJava = false;
+            if (systemModules.containsKey(JAVA_SE)) {
+                // java.se is a system module
+                hasJava = true;
+                roots.add(JAVA_SE);
+            }
+
+            for (ModuleReference mref : systemModules.values()) {
+                String mn = mref.descriptor().name();
+                if (hasJava && mn.startsWith("java."))
+                    continue;
+
+                // add as root if observable and exports at least one package
+                ModuleDescriptor descriptor = mref.descriptor();
+                for (ModuleDescriptor.Exports e : descriptor.exports()) {
+                    if (!e.isQualified()) {
+                        roots.add(mn);
+                        break;
+                    }
+                }
+            }
+            return roots;
+        }
+    }
+
+    public static class Builder {
+
+        final SystemModuleFinder systemModulePath;
+        final Set<String> rootModules = new HashSet<>();
+        final List<Archive> initialArchives = new ArrayList<>();
+        final List<Path> paths = new ArrayList<>();
+        final List<Path> classPaths = new ArrayList<>();
+
+        ModuleFinder upgradeModulePath;
+        ModuleFinder appModulePath;
+        boolean addAllApplicationModules;
+        boolean addAllDefaultModules;
+
+        public Builder() {
+            this.systemModulePath = new SystemModuleFinder();
+        }
+
+        public Builder(String javaHome) throws IOException {
+            this.systemModulePath = SystemModuleFinder.JAVA_HOME.equals(javaHome)
+                ? new SystemModuleFinder()
+                : new SystemModuleFinder(javaHome);
+        }
+
+        public Builder upgradeModulePath(String upgradeModulePath) {
+            this.upgradeModulePath = createModulePathFinder(upgradeModulePath);
+            return this;
+        }
+
+        public Builder appModulePath(String modulePath) {
+            this.appModulePath = createModulePathFinder(modulePath);
+            return this;
+        }
+
+        public Builder addmods(Set<String> addmods) {
+            for (String mn : addmods) {
+                switch (mn) {
+                    case ALL_MODULE_PATH:
+                        this.addAllApplicationModules = true;
+                        break;
+                    case ALL_DEFAULT:
+                        this.addAllDefaultModules = true;
+                        break;
+                    default:
+                        this.rootModules.add(mn);
+                }
+            }
+            return this;
+        }
+
+        /*
+         * This method is for -check option to find all target modules specified
+         * in qualified exports.
+         *
+         * Include all system modules and modules found on modulepath
+         */
+        public Builder allModules() {
+            systemModulePath.moduleNames()
+                            .forEach(this.rootModules::add);
+            this.addAllApplicationModules = true;
+            return this;
+        }
+
+        public Builder addRoot(Path path) {
+            Archive archive = Archive.getInstance(path);
+            if (archive.contains(MODULE_INFO)) {
+                paths.add(path);
+            } else {
+                initialArchives.add(archive);
+            }
+            return this;
+        }
+
+        public Builder addClassPath(String classPath) {
+            this.classPaths.addAll(getClassPaths(classPath));
+            return this;
+        }
+
+        public JdepsConfiguration build() throws  IOException {
+            ModuleFinder finder = systemModulePath;
+            if (upgradeModulePath != null) {
+                finder = ModuleFinder.compose(upgradeModulePath, systemModulePath);
+            }
+            if (appModulePath != null) {
+                finder = ModuleFinder.compose(finder, appModulePath);
+            }
+            if (!paths.isEmpty()) {
+                ModuleFinder otherModulePath = ModuleFinder.of(paths.toArray(new Path[0]));
+
+                finder = ModuleFinder.compose(finder, otherModulePath);
+                // add modules specified on command-line (convenience) as root set
+                otherModulePath.findAll().stream()
+                        .map(mref -> mref.descriptor().name())
+                        .forEach(rootModules::add);
+            }
+            if (addAllApplicationModules && appModulePath != null) {
+                appModulePath.findAll().stream()
+                    .map(mref -> mref.descriptor().name())
+                    .forEach(rootModules::add);
+            }
+
+            return new JdepsConfiguration(systemModulePath,
+                                          finder,
+                                          rootModules,
+                                          classPaths,
+                                          initialArchives,
+                                          addAllDefaultModules);
+        }
+
+        private static ModuleFinder createModulePathFinder(String mpaths) {
+            if (mpaths == null) {
+                return null;
+            } else {
+                String[] dirs = mpaths.split(File.pathSeparator);
+                Path[] paths = new Path[dirs.length];
+                int i = 0;
+                for (String dir : dirs) {
+                    paths[i++] = Paths.get(dir);
+                }
+                return ModuleFinder.of(paths);
+            }
+        }
+
+        /*
+         * Returns the list of Archive specified in cpaths and not included
+         * initialArchives
+         */
+        private List<Path> getClassPaths(String cpaths) {
+            if (cpaths.isEmpty()) {
+                return Collections.emptyList();
+            }
+            List<Path> paths = new ArrayList<>();
+            for (String p : cpaths.split(File.pathSeparator)) {
+                if (p.length() > 0) {
+                    // wildcard to parse all JAR files e.g. -classpath dir/*
+                    int i = p.lastIndexOf(".*");
+                    if (i > 0) {
+                        Path dir = Paths.get(p.substring(0, i));
+                        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.jar")) {
+                            for (Path entry : stream) {
+                                paths.add(entry);
+                            }
+                        } catch (IOException e) {
+                            throw new UncheckedIOException(e);
+                        }
+                    } else {
+                        paths.add(Paths.get(p));
+                    }
+                }
+            }
+            return paths;
+        }
+    }
+
+}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java	Thu May 19 19:47:04 2016 +0000
@@ -41,22 +41,27 @@
  * 2. -filter:package to filter out same-package dependencies
  *    This filter is applied when jdeps parses the class files
  *    and filtered dependencies are not stored in the Analyzer.
- * 3. -module specifies to match target dependencies from the given module
+ * 3. -requires specifies to match target dependence from the given module
  *    This gets expanded into package lists to be filtered.
  * 4. -filter:archive to filter out same-archive dependencies
  *    This filter is applied later in the Analyzer as the
  *    containing archive of a target class may not be known until
  *    the entire archive
  */
-class JdepsFilter implements Dependency.Filter, Analyzer.Filter {
+public class JdepsFilter implements Dependency.Filter, Analyzer.Filter {
+
+    public static final JdepsFilter DEFAULT_FILTER =
+        new JdepsFilter.Builder().filter(true, true).build();
+
     private final Dependency.Filter filter;
     private final Pattern filterPattern;
     private final boolean filterSamePackage;
     private final boolean filterSameArchive;
     private final boolean findJDKInternals;
     private final Pattern includePattern;
-    private final Set<String> includePackages;
-    private final Set<String> excludeModules;
+    private final Pattern includeSystemModules;
+
+    private final Set<String> requires;
 
     private JdepsFilter(Dependency.Filter filter,
                         Pattern filterPattern,
@@ -64,16 +69,16 @@
                         boolean filterSameArchive,
                         boolean findJDKInternals,
                         Pattern includePattern,
-                        Set<String> includePackages,
-                        Set<String> excludeModules) {
+                        Pattern includeSystemModules,
+                        Set<String> requires) {
         this.filter = filter;
         this.filterPattern = filterPattern;
         this.filterSamePackage = filterSamePackage;
         this.filterSameArchive = filterSameArchive;
         this.findJDKInternals = findJDKInternals;
         this.includePattern = includePattern;
-        this.includePackages = includePackages;
-        this.excludeModules = excludeModules;
+        this.includeSystemModules = includeSystemModules;
+        this.requires = requires;
     }
 
     /**
@@ -82,12 +87,7 @@
      * @param cn fully-qualified name
      */
     public boolean matches(String cn) {
-        if (includePackages.isEmpty() && includePattern == null)
-            return true;
-
-        int i = cn.lastIndexOf('.');
-        String pn = i > 0 ? cn.substring(0, i) : "";
-        if (includePackages.contains(pn))
+        if (includePattern == null)
             return true;
 
         if (includePattern != null)
@@ -97,29 +97,39 @@
     }
 
     /**
-     * Tests if the given source includes classes specified in includePattern
-     * or includePackages filters.
+     * Tests if the given source includes classes specified in -include option
      *
      * This method can be used to determine if the given source should eagerly
      * be processed.
      */
     public boolean matches(Archive source) {
-        if (!includePackages.isEmpty() && source.getModule().isNamed()) {
-            boolean found = source.getModule().packages()
-                                  .stream()
-                                  .filter(pn -> includePackages.contains(pn))
-                                  .findAny().isPresent();
-            if (found)
-                return true;
+        if (includePattern != null) {
+            return source.reader().entries().stream()
+                    .map(name -> name.replace('/', '.'))
+                    .filter(name -> !name.equals("module-info.class"))
+                    .anyMatch(this::matches);
         }
-        if (!includePackages.isEmpty() || includePattern != null) {
-            return source.reader().entries()
-                         .stream()
-                         .map(name -> name.replace('/', '.'))
-                         .filter(this::matches)
-                         .findAny().isPresent();
-        }
-        return false;
+        return hasTargetFilter();
+    }
+
+    public boolean include(Archive source) {
+        Module module = source.getModule();
+        // skip system module by default; or if includeSystemModules is set
+        // only include the ones matching the pattern
+        return  !module.isSystem() || (includeSystemModules != null &&
+            includeSystemModules.matcher(module.name()).matches());
+    }
+
+    public boolean hasIncludePattern() {
+        return includePattern != null || includeSystemModules != null;
+    }
+
+    public boolean hasTargetFilter() {
+        return filter != null;
+    }
+
+    public Set<String> requiresFilter() {
+        return requires;
     }
 
     // ----- Dependency.Filter -----
@@ -164,42 +174,35 @@
         return true;
     }
 
-    /**
-     * Returns true if dependency should be recorded for the given source.
-     */
-    public boolean accept(Archive source) {
-        return !excludeModules.contains(source.getName());
-    }
-
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("exclude modules: ")
-          .append(excludeModules.stream().sorted().collect(Collectors.joining(",")))
-          .append("\n");
+        sb.append("include pattern: ").append(includePattern).append("\n");
         sb.append("filter same archive: ").append(filterSameArchive).append("\n");
         sb.append("filter same package: ").append(filterSamePackage).append("\n");
+        sb.append("requires: ").append(requires).append("\n");
         return sb.toString();
     }
 
-    static class Builder {
-        Dependency.Filter filter;
+    public static class Builder {
+        static Pattern SYSTEM_MODULE_PATTERN = Pattern.compile("java\\..*|jdk\\..*|javafx\\..*");
         Pattern filterPattern;
+        Pattern regex;
         boolean filterSamePackage;
         boolean filterSameArchive;
         boolean findJDKInterals;
         // source filters
         Pattern includePattern;
-        Set<String> includePackages = new HashSet<>();
-        Set<String> includeModules = new HashSet<>();
-        Set<String> excludeModules = new HashSet<>();
+        Pattern includeSystemModules;
+        Set<String> requires = new HashSet<>();
+        Set<String> targetPackages = new HashSet<>();
 
         public Builder packages(Set<String> packageNames) {
-            this.filter = Dependencies.getPackageFilter(packageNames, false);
+            this.targetPackages.addAll(packageNames);
             return this;
         }
         public Builder regex(Pattern regex) {
-            this.filter = Dependencies.getRegexFilter(regex);
+            this.regex = regex;
             return this;
         }
         public Builder filter(Pattern regex) {
@@ -211,6 +214,13 @@
             this.filterSameArchive = sameArchive;
             return this;
         }
+        public Builder requires(String name, Set<String> packageNames) {
+            this.requires.add(name);
+            this.targetPackages.addAll(packageNames);
+
+            includeIfSystemModule(name);
+            return this;
+        }
         public Builder findJDKInternals(boolean value) {
             this.findJDKInterals = value;
             return this;
@@ -219,30 +229,33 @@
             this.includePattern = regex;
             return this;
         }
-        public Builder includePackage(String pn) {
-            this.includePackages.add(pn);
+        public Builder includeSystemModules(Pattern regex) {
+            this.includeSystemModules = regex;
             return this;
         }
-        public Builder includeModules(Set<String> includes) {
-            this.includeModules.addAll(includes);
-            return this;
-        }
-        public Builder excludeModules(Set<String> excludes) {
-            this.excludeModules.addAll(excludes);
+        public Builder includeIfSystemModule(String name) {
+            if (includeSystemModules == null &&
+                    SYSTEM_MODULE_PATTERN.matcher(name).matches()) {
+                this.includeSystemModules = SYSTEM_MODULE_PATTERN;
+            }
             return this;
         }
 
-        JdepsFilter build() {
+        public JdepsFilter build() {
+            Dependency.Filter filter = null;
+            if (regex != null)
+                filter = Dependencies.getRegexFilter(regex);
+            else if (!targetPackages.isEmpty()) {
+                filter = Dependencies.getPackageFilter(targetPackages, false);
+            }
             return new JdepsFilter(filter,
                                    filterPattern,
                                    filterSamePackage,
                                    filterSameArchive,
                                    findJDKInterals,
                                    includePattern,
-                                   includePackages,
-                                   excludeModules.stream()
-                                        .filter(mn -> !includeModules.contains(mn))
-                                        .collect(Collectors.toSet()));
+                                   includeSystemModules,
+                                   requires);
         }
 
     }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu May 19 19:47:04 2016 +0000
@@ -25,31 +25,29 @@
 
 package com.sun.tools.jdeps;
 
+import static com.sun.tools.jdeps.Analyzer.NOT_FOUND;
 import static com.sun.tools.jdeps.Analyzer.Type.*;
 import static com.sun.tools.jdeps.JdepsWriter.*;
-import static com.sun.tools.jdeps.ModuleAnalyzer.Graph;
+import static com.sun.tools.jdeps.JdepsConfiguration.ALL_MODULE_PATH;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.module.ResolutionException;
-import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.text.MessageFormat;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.util.Comparator;
+import java.util.Deque;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.MissingResourceException;
-import java.util.Optional;
 import java.util.ResourceBundle;
 import java.util.Set;
-import java.util.TreeMap;
+import java.util.function.Function;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -58,7 +56,12 @@
  * Implementation for the jdeps tool for static class dependency analysis.
  */
 class JdepsTask {
-    static class BadArgs extends Exception {
+    static interface BadArguments {
+        String getKey();
+        Object[] getArgs();
+        boolean showUsage();
+    }
+    static class BadArgs extends Exception implements BadArguments {
         static final long serialVersionUID = 8765093759964640721L;
         BadArgs(String key, Object... args) {
             super(JdepsTask.getMessage(key, args));
@@ -73,6 +76,44 @@
         final String key;
         final Object[] args;
         boolean showUsage;
+
+        @Override
+        public String getKey() {
+            return key;
+        }
+
+        @Override
+        public Object[] getArgs() {
+            return args;
+        }
+
+        @Override
+        public boolean showUsage() {
+            return showUsage;
+        }
+    }
+
+    static class UncheckedBadArgs extends RuntimeException implements BadArguments {
+        static final long serialVersionUID = -1L;
+        final BadArgs cause;
+        UncheckedBadArgs(BadArgs cause) {
+            super(cause);
+            this.cause = cause;
+        }
+        @Override
+        public String getKey() {
+            return cause.key;
+        }
+
+        @Override
+        public Object[] getArgs() {
+            return cause.args;
+        }
+
+        @Override
+        public boolean showUsage() {
+            return cause.showUsage;
+        }
     }
 
     static abstract class Option {
@@ -126,7 +167,7 @@
                 if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
                     throw new BadArgs("err.invalid.path", arg);
                 }
-                task.options.dotOutputDir = arg;
+                task.options.dotOutputDir = Paths.get(arg);;
             }
         },
         new Option(false, "-s", "-summary") {
@@ -136,8 +177,9 @@
             }
         },
         new Option(false, "-v", "-verbose",
-                          "-verbose:package",
-                          "-verbose:class") {
+                                "-verbose:module",
+                                "-verbose:package",
+                                "-verbose:class") {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
                 switch (opt) {
                     case "-v":
@@ -146,6 +188,9 @@
                         task.options.filterSameArchive = false;
                         task.options.filterSamePackage = false;
                         break;
+                    case "-verbose:module":
+                        task.options.verbose = MODULE;
+                        break;
                     case "-verbose:package":
                         task.options.verbose = PACKAGE;
                         break;
@@ -157,6 +202,80 @@
                 }
             }
         },
+        new Option(false, "-apionly") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.apiOnly = true;
+            }
+        },
+        new Option(true, "-check") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                Set<String> mods =  Set.of(arg.split(","));
+                task.options.checkModuleDeps = mods;
+                task.options.addmods.addAll(mods);
+            }
+        },
+        new Option(true, "-genmoduleinfo") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                Path p = Paths.get(arg);
+                if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
+                    throw new BadArgs("err.invalid.path", arg);
+                }
+                task.options.genModuleInfo = Paths.get(arg);
+            }
+        },
+        new Option(false, "-jdkinternals") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.findJDKInternals = true;
+                task.options.verbose = CLASS;
+                if (task.options.includePattern == null) {
+                    task.options.includePattern = Pattern.compile(".*");
+                }
+            }
+        },
+
+        // ---- paths option ----
+        new Option(true, "-cp", "-classpath") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.classpath = arg;
+            }
+        },
+        new Option(true, "-mp", "-modulepath") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                task.options.modulePath = arg;
+            }
+        },
+        new Option(true, "-upgrademodulepath") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                task.options.upgradeModulePath = arg;
+            }
+        },
+        new Option(true, "-system") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                if (arg.equals("none")) {
+                    task.options.systemModulePath = null;
+                } else {
+                    Path path = Paths.get(arg);
+                    if (Files.isRegularFile(path.resolve("lib").resolve("modules")))
+                        task.options.systemModulePath = arg;
+                    else
+                        throw new BadArgs("err.invalid.path", arg);
+                }
+            }
+        },
+        new Option(true, "-addmods") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                Set<String> mods = Set.of(arg.split(","));
+                task.options.addmods.addAll(mods);
+            }
+        },
+        new Option(true, "-m") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                task.options.rootModule = arg;
+                task.options.addmods.add(arg);
+            }
+        },
+
+        // ---- Target filtering options ----
         new Option(true, "-p", "-package") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.packageNames.add(arg);
@@ -167,7 +286,7 @@
                 task.options.regex = Pattern.compile(arg);
             }
         },
-        new Option(true, "-module") {
+        new Option(true, "-requires") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.requires.add(arg);
             }
@@ -198,28 +317,27 @@
                 }
             }
         },
+
+        // ---- Source filtering options ----
         new Option(true, "-include") {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
                 task.options.includePattern = Pattern.compile(arg);
             }
         },
+
+        // Another alternative to list modules in -addmods option
+        new HiddenOption(true, "-include-system-modules") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                task.options.includeSystemModulePattern = Pattern.compile(arg);
+            }
+        },
+
         new Option(false, "-P", "-profile") {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
                 task.options.showProfile = true;
-                task.options.showModule = false;
             }
         },
-        new Option(false, "-M") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                task.options.showModule = true;
-                task.options.showProfile = false;
-            }
-        },
-        new Option(false, "-apionly") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.apiOnly = true;
-            }
-        },
+
         new Option(false, "-R", "-recursive") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.depth = 0;
@@ -228,15 +346,17 @@
                 task.options.filterSamePackage = false;
             }
         },
-        new Option(true, "-genmoduleinfo") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                Path p = Paths.get(arg);
-                if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
-                    throw new BadArgs("err.invalid.path", arg);
-                }
-                task.options.genModuleInfo = arg;
+
+        new Option(false, "-I", "-inverse") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.inverse = true;
+                // equivalent to the inverse of compile-time view analysis
+                task.options.compileTimeView = true;
+                task.options.filterSamePackage = true;
+                task.options.filterSameArchive = true;
             }
         },
+
         new Option(false, "-ct", "-compile-time") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.compileTimeView = true;
@@ -245,62 +365,11 @@
                 task.options.depth = 0;
             }
         },
-        new Option(false, "-jdkinternals") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.findJDKInternals = true;
-                task.options.verbose = CLASS;
-                if (task.options.includePattern == null) {
-                    task.options.includePattern = Pattern.compile(".*");
-                }
-            }
-        },
-        new Option(true, "-cp", "-classpath") {
-            void process(JdepsTask task, String opt, String arg) {
-                    task.options.classpath = arg;
-                }
-        },
-        new Option(true, "-mp", "-modulepath") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                task.options.modulePath = arg;
-                task.options.showModule = true;
-            }
-        },
-        new Option(true, "-upgrademodulepath") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                task.options.upgradeModulePath = arg;
-                task.options.showModule = true;
-            }
-        },
-        new Option(true, "-m") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                task.options.rootModule = arg;
-                task.options.includes.add(arg);
-                task.options.showModule = true;
-            }
-        },
-        new Option(false, "-check") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                task.options.checkModuleDeps = true;
-            }
-        },
-        new HiddenOption(true, "-include-modules") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                Arrays.stream(arg.split(","))
-                        .forEach(task.options.includes::add);
-                task.options.showModule = true;
-            }
-        },
-        new HiddenOption(true, "-exclude-modules") {
-                void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                    Arrays.stream(arg.split(","))
-                            .forEach(task.options.excludes::add);
-                    task.options.showModule = true;
-                }
-        },
+
         new Option(false, "-q", "-quiet") {
             void process(JdepsTask task, String opt, String arg) {
-                    task.options.nowarning = true;
-                }
+                task.options.nowarning = true;
+            }
         },
 
         new Option(false, "-version") {
@@ -318,7 +387,11 @@
                 task.options.showLabel = true;
             }
         },
-
+        new HiddenOption(false, "-hide-module") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.showModule = false;
+            }
+        },
         new HiddenOption(true, "-depth") {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
                 try {
@@ -332,7 +405,7 @@
 
     private static final String PROGNAME = "jdeps";
     private final Options options = new Options();
-    private final List<String> classes = new ArrayList<>();
+    private final List<String> inputArgs = new ArrayList<>();
 
     private PrintWriter log;
     void setLog(PrintWriter out) {
@@ -342,13 +415,13 @@
     /**
      * Result codes.
      */
-    static final int EXIT_OK = 0, // Completed with no errors.
-                     EXIT_ERROR = 1, // Completed but reported errors.
-                     EXIT_CMDERR = 2, // Bad command-line arguments
-                     EXIT_SYSERR = 3, // System error or resource exhaustion.
-                     EXIT_ABNORMAL = 4;// terminated abnormally
+    static final int EXIT_OK = 0,       // Completed with no errors.
+                     EXIT_ERROR = 1,    // Completed but reported errors.
+                     EXIT_CMDERR = 2,   // Bad command-line arguments
+                     EXIT_SYSERR = 3,   // System error or resource exhaustion.
+                     EXIT_ABNORMAL = 4; // terminated abnormally
 
-    int run(String[] args) {
+    int run(String... args) {
         if (log == null) {
             log = new PrintWriter(System.out);
         }
@@ -360,15 +433,11 @@
             if (options.version || options.fullVersion) {
                 showVersion(options.fullVersion);
             }
-            if (options.rootModule != null && !classes.isEmpty()) {
-                reportError("err.invalid.module.option", options.rootModule, classes);
-                return EXIT_CMDERR;
+            if (!inputArgs.isEmpty() && options.rootModule != null) {
+                reportError("err.invalid.arg.for.option", "-m");
             }
-            if (options.checkModuleDeps && options.rootModule == null) {
-                reportError("err.root.module.not.set");
-                return EXIT_CMDERR;
-            }
-            if (classes.isEmpty() && options.rootModule == null && options.includePattern == null) {
+            if (inputArgs.isEmpty() && options.addmods.isEmpty() && options.includePattern == null
+                    && options.includeSystemModulePattern == null && options.checkModuleDeps == null) {
                 if (options.help || options.version || options.fullVersion) {
                     return EXIT_OK;
                 } else {
@@ -377,19 +446,10 @@
                 }
             }
             if (options.genModuleInfo != null) {
-                if (options.dotOutputDir != null || !options.classpath.isEmpty() || options.hasFilter()) {
+                if (options.dotOutputDir != null || options.classpath != null || options.hasFilter()) {
                     showHelp();
                     return EXIT_CMDERR;
                 }
-                // default to compile time view analysis
-                options.compileTimeView = true;
-                for (String fn : classes) {
-                    Path p = Paths.get(fn);
-                    if (!Files.exists(p) || !fn.endsWith(".jar")) {
-                        reportError("err.genmoduleinfo.not.jarfile", fn);
-                        return EXIT_CMDERR;
-                    }
-                }
             }
 
             if (options.numFilters() > 1) {
@@ -397,6 +457,16 @@
                 return EXIT_CMDERR;
             }
 
+            if (options.inverse && options.depth != 1) {
+                reportError("err.invalid.inverse.option", "-R");
+                return EXIT_CMDERR;
+            }
+
+            if (options.inverse && options.numFilters() == 0) {
+                reportError("err.invalid.filters");
+                return EXIT_CMDERR;
+            }
+
             if ((options.findJDKInternals) && (options.hasFilter() || options.showSummary)) {
                 showHelp();
                 return EXIT_CMDERR;
@@ -405,12 +475,15 @@
                 showHelp();
                 return EXIT_CMDERR;
             }
+            if (options.checkModuleDeps != null && !inputArgs.isEmpty()) {
+                reportError("err.invalid.module.option", inputArgs, "-check");
+            }
 
             boolean ok = run();
             return ok ? EXIT_OK : EXIT_ERROR;
-        } catch (BadArgs e) {
-            reportError(e.key, e.args);
-            if (e.showUsage) {
+        } catch (BadArgs|UncheckedBadArgs e) {
+            reportError(e.getKey(), e.getArgs());
+            if (e.showUsage()) {
                 log.println(getMessage("main.usage.summary", PROGNAME));
             }
             return EXIT_CMDERR;
@@ -419,176 +492,217 @@
             return EXIT_CMDERR;
         } catch (IOException e) {
             e.printStackTrace();
-            return EXIT_ABNORMAL;
+            return EXIT_CMDERR;
         } finally {
             log.flush();
         }
     }
 
-    private ModulePaths modulePaths;
-    private boolean run() throws BadArgs, IOException {
-        DependencyFinder dependencyFinder =
-            new DependencyFinder(options.compileTimeView);
+    boolean run() throws IOException {
+        JdepsConfiguration config = buildConfig();
 
-        buildArchive(dependencyFinder);
+        // detect split packages
+        config.splitPackages().entrySet().stream()
+            .sorted(Map.Entry.comparingByKey())
+            .forEach(e -> System.out.format("split package: %s %s%n", e.getKey(),
+                                            e.getValue().toString()));
 
-        if (options.rootModule != null &&
-                (options.checkModuleDeps || (options.dotOutputDir != null &&
-                                      options.verbose == SUMMARY))) {
-            // -dotfile -s prints the configuration of the given root
-            // -checkModuleDeps prints the suggested module-info.java
-            return analyzeModules(dependencyFinder);
+        // check if any module specified in -requires is missing
+        Stream.concat(options.addmods.stream(), options.requires.stream())
+              .filter(mn -> !config.isValidToken(mn))
+              .forEach(mn -> config.findModule(mn).orElseThrow(() ->
+                  new UncheckedBadArgs(new BadArgs("err.module.not.found", mn))));
+
+        // -genmoduleinfo
+        if (options.genModuleInfo != null) {
+            return genModuleInfo(config);
         }
 
-        // otherwise analyze the dependencies
-        if (options.genModuleInfo != null) {
-            return genModuleInfo(dependencyFinder);
+        // -check
+        if (options.checkModuleDeps != null) {
+            return new ModuleAnalyzer(config, log, options.checkModuleDeps).run();
+        }
+
+        if (options.dotOutputDir != null &&
+                (options.verbose == SUMMARY || options.verbose == MODULE) &&
+                !options.addmods.isEmpty() && inputArgs.isEmpty()) {
+            return new ModuleAnalyzer(config, log).genDotFiles(options.dotOutputDir);
+        }
+
+        if (options.inverse) {
+            return analyzeInverseDeps(config);
         } else {
-            return analyzeDeps(dependencyFinder);
+            return analyzeDeps(config);
         }
     }
 
-    private void buildArchive(DependencyFinder dependencyFinder)
-            throws BadArgs, IOException
-    {
-        // If -genmoduleinfo is specified, the input arguments must be JAR files
-        // Treat them as automatic modules for analysis
-        List<Path> jarfiles = options.genModuleInfo != null
-                                    ?  classes.stream().map(Paths::get)
-                                              .collect(Collectors.toList())
-                                    : Collections.emptyList();
-        // Set module paths
-        this.modulePaths = new ModulePaths(options.upgradeModulePath, options.modulePath, jarfiles);
+    private JdepsConfiguration buildConfig() throws IOException {
+        JdepsConfiguration.Builder builder =
+            new JdepsConfiguration.Builder(options.systemModulePath);
 
-        // add modules to dependency finder for analysis
-        Map<String, Module> modules = modulePaths.getModules();
-        modules.values().stream()
-               .forEach(dependencyFinder::addModule);
+        builder.upgradeModulePath(options.upgradeModulePath)
+               .appModulePath(options.modulePath)
+               .addmods(options.addmods);
 
-        // If -m option is set, add the specified module and its transitive dependences
-        // to the root set
-        if (options.rootModule != null) {
-            modulePaths.dependences(options.rootModule)
-                       .forEach(dependencyFinder::addRoot);
+        if (options.checkModuleDeps != null) {
+            // check all system modules in the image
+            builder.allModules();
         }
 
-        // check if any module specified in -requires is missing
-        Optional<String> req = options.requires.stream()
-                .filter(mn -> !modules.containsKey(mn))
-                .findFirst();
-        if (req.isPresent()) {
-            throw new BadArgs("err.module.not.found", req.get());
-        }
+        if (options.classpath != null)
+            builder.addClassPath(options.classpath);
 
-        // classpath
-        for (Path p : getClassPaths(options.classpath)) {
+        // build the root set of archives to be analyzed
+        for (String s : inputArgs) {
+            Path p = Paths.get(s);
             if (Files.exists(p)) {
-                dependencyFinder.addClassPathArchive(p);
+                builder.addRoot(p);
             }
         }
 
-        // if -genmoduleinfo is not set, the input arguments are considered as
-        // unnamed module.  Add them to the root set
-        if (options.genModuleInfo == null) {
-            // add root set
-            for (String s : classes) {
-                Path p = Paths.get(s);
-                if (Files.exists(p)) {
-                    // add to the initial root set
-                    dependencyFinder.addRoot(p);
-                } else {
-                    if (isValidClassName(s)) {
-                        dependencyFinder.addClassName(s);
-                    } else {
-                        warning("warn.invalid.arg", s);
-                    }
-                }
-            }
-        }
+        return builder.build();
     }
 
-    private boolean analyzeDeps(DependencyFinder dependencyFinder) throws IOException {
-        JdepsFilter filter = dependencyFilter();
-
-        // parse classfiles and find all dependencies
-        findDependencies(dependencyFinder, filter, options.apiOnly);
-
-        // analyze the dependencies collected
-        Analyzer analyzer = new Analyzer(options.verbose, filter);
-        analyzer.run(dependencyFinder.archives());
-
+    private boolean analyzeDeps(JdepsConfiguration config) throws IOException {
         // output result
         final JdepsWriter writer;
         if (options.dotOutputDir != null) {
-            Path dir = Paths.get(options.dotOutputDir);
-            Files.createDirectories(dir);
-            writer = new DotFileWriter(dir, options.verbose,
+            writer = new DotFileWriter(options.dotOutputDir,
+                                       options.verbose,
                                        options.showProfile,
                                        options.showModule,
                                        options.showLabel);
         } else {
-            writer = new SimpleWriter(log, options.verbose,
+            writer = new SimpleWriter(log,
+                                      options.verbose,
                                       options.showProfile,
                                       options.showModule);
         }
 
-        // Targets for reporting - include the root sets and other analyzed archives
-        final List<Archive> targets;
-        if (options.rootModule == null) {
-            // no module as the root set
-            targets = dependencyFinder.archives()
-                                      .filter(filter::accept)
-                                      .filter(a -> !a.getModule().isNamed())
-                                      .collect(Collectors.toList());
-        } else {
-            // named modules in topological order
-            Stream<Module> modules = dependencyFinder.archives()
-                                                     .filter(a -> a.getModule().isNamed())
-                                                     .map(Archive::getModule);
-            Graph<Module> graph = ModuleAnalyzer.graph(modulePaths, modules.toArray(Module[]::new));
-            // then add unnamed module
-            targets = graph.orderedNodes()
-                           .filter(filter::accept)
-                           .collect(Collectors.toList());
+        // analyze the dependencies
+        DepsAnalyzer analyzer = new DepsAnalyzer(config,
+                                        dependencyFilter(config),
+                                        writer,
+                                        options.verbose,
+                                        options.apiOnly);
 
-            // in case any reference not found
-            dependencyFinder.archives()
-                    .filter(a -> !a.getModule().isNamed())
-                    .forEach(targets::add);
+        boolean ok = analyzer.run(options.compileTimeView, options.depth);
+
+        // print skipped entries, if any
+        analyzer.archives()
+            .forEach(archive -> archive.reader()
+                .skippedEntries().stream()
+                .forEach(name -> warning("warn.skipped.entry",
+                                         name, archive.getPathName())));
+
+        if (options.findJDKInternals && !options.nowarning) {
+            Map<String, String> jdkInternals = analyzer.dependences()
+                .collect(Collectors.toMap(Function.identity(), this::replacementFor));
+
+            if (!jdkInternals.isEmpty()) {
+                log.println();
+                warning("warn.replace.useJDKInternals", getMessage("jdeps.wiki.url"));
+
+                if (jdkInternals.values().stream().anyMatch(repl -> repl != null)) {
+                    log.println();
+                    log.format("%-40s %s%n", "JDK Internal API", "Suggested Replacement");
+                    log.format("%-40s %s%n", "----------------", "---------------------");
+                        jdkInternals.entrySet().stream()
+                            .filter(e -> e.getValue() != null)
+                            .sorted(Map.Entry.comparingByKey())
+                            .forEach(e -> log.format("%-40s %s%n", e.getKey(), e.getValue()));
+                }
+            }
+
         }
-
-        writer.generateOutput(targets, analyzer);
-        if (options.findJDKInternals && !options.nowarning) {
-            showReplacements(targets, analyzer);
-        }
-        return true;
+        return ok;
     }
 
-    private JdepsFilter dependencyFilter() {
-        // Filter specified by -filter, -package, -regex, and -module options
+    private boolean analyzeInverseDeps(JdepsConfiguration config) throws IOException {
+        JdepsWriter writer = new SimpleWriter(log,
+                                              options.verbose,
+                                              options.showProfile,
+                                              options.showModule);
+
+        InverseDepsAnalyzer analyzer = new InverseDepsAnalyzer(config,
+                                                               dependencyFilter(config),
+                                                               writer,
+                                                               options.verbose,
+                                                               options.apiOnly);
+        boolean ok = analyzer.run();
+
+        log.println();
+        if (!options.requires.isEmpty())
+            log.format("Inverse transitive dependences on %s%n", options.requires);
+        else
+            log.format("Inverse transitive dependences matching %s%n",
+                options.regex != null
+                    ? options.regex.toString()
+                    : "packages " + options.packageNames);
+
+        analyzer.inverseDependences().stream()
+                .sorted(Comparator.comparing(this::sortPath))
+                .forEach(path -> log.println(path.stream()
+                                                .map(Archive::getName)
+                                                .collect(Collectors.joining(" <- "))));
+        return ok;
+    }
+
+    private String sortPath(Deque<Archive> path) {
+        return path.peekFirst().getName();
+    }
+
+    private boolean genModuleInfo(JdepsConfiguration config) throws IOException {
+        ModuleInfoBuilder builder
+            = new ModuleInfoBuilder(config, inputArgs, options.genModuleInfo);
+        boolean ok = builder.run();
+
+        builder.modules().forEach(module -> {
+            if (module.packages().contains("")) {
+                reportError("ERROR: %s contains unnamed package.  " +
+                    "module-info.java not generated%n", module.getPathName());
+            }
+        });
+
+        if (!ok && !options.nowarning) {
+            log.println("Missing dependencies");
+            builder.visitMissingDeps(
+                new Analyzer.Visitor() {
+                    @Override
+                    public void visitDependence(String origin, Archive originArchive,
+                                                String target, Archive targetArchive) {
+                        if (targetArchive == NOT_FOUND)
+                            log.format("   %-50s -> %-50s %s%n",
+                                origin, target, targetArchive.getName());
+                    }
+                });
+
+            log.println("ERROR: missing dependencies (check \"requires NOT_FOUND;\")");
+        }
+        return ok;
+    }
+
+    /**
+     * Returns a filter used during dependency analysis
+     */
+    private JdepsFilter dependencyFilter(JdepsConfiguration config) {
+        // Filter specified by -filter, -package, -regex, and -requires options
         JdepsFilter.Builder builder = new JdepsFilter.Builder();
 
-        // Exclude JDK modules from analysis and reporting if -m specified.
-        modulePaths.getModules().values().stream()
-                   .filter(m -> m.isJDK())
-                   .map(Module::name)
-                   .forEach(options.excludes::add);
-
         // source filters
         builder.includePattern(options.includePattern);
-        builder.includeModules(options.includes);
-        builder.excludeModules(options.excludes);
+        builder.includeSystemModules(options.includeSystemModulePattern);
 
         builder.filter(options.filterSamePackage, options.filterSameArchive);
         builder.findJDKInternals(options.findJDKInternals);
 
-        // -module
+        // -requires
         if (!options.requires.isEmpty()) {
-            Map<String, Module> modules = modulePaths.getModules();
-            builder.packages(options.requires.stream()
-                    .map(modules::get)
-                    .flatMap(m -> m.packages().stream())
-                    .collect(Collectors.toSet()));
+            options.requires.stream()
+                .forEach(mn -> {
+                    Module m = config.findModule(mn).get();
+                    builder.requires(mn, m.packages());
+                });
         }
         // -regex
         if (options.regex != null)
@@ -600,62 +714,14 @@
         if (options.filterRegex != null)
             builder.filter(options.filterRegex);
 
+        // check if system module is set
+        config.rootModules().stream()
+            .map(Module::name)
+            .forEach(builder::includeIfSystemModule);
+
         return builder.build();
     }
 
-    private void findDependencies(DependencyFinder dependencyFinder,
-                                  JdepsFilter filter,
-                                  boolean apiOnly)
-        throws IOException
-    {
-        dependencyFinder.findDependencies(filter, apiOnly, options.depth);
-
-        // print skipped entries, if any
-        for (Archive a : dependencyFinder.roots()) {
-            for (String name : a.reader().skippedEntries()) {
-                warning("warn.skipped.entry", name, a.getPathName());
-            }
-        }
-    }
-
-    private boolean genModuleInfo(DependencyFinder dependencyFinder) throws IOException {
-        ModuleInfoBuilder builder = new ModuleInfoBuilder(modulePaths, dependencyFinder);
-        boolean result = builder.run(options.verbose, options.nowarning);
-        builder.build(Paths.get(options.genModuleInfo));
-        return result;
-    }
-
-    private boolean analyzeModules(DependencyFinder dependencyFinder)
-            throws IOException
-    {
-        ModuleAnalyzer analyzer = new ModuleAnalyzer(modulePaths,
-                                                     dependencyFinder,
-                                                     options.rootModule);
-        if (options.checkModuleDeps) {
-            return analyzer.run();
-        }
-        if (options.dotOutputDir != null && options.verbose == SUMMARY) {
-            Path dir = Paths.get(options.dotOutputDir);
-            Files.createDirectories(dir);
-            analyzer.genDotFile(dir);
-            return true;
-        }
-        return false;
-    }
-
-    private boolean isValidClassName(String name) {
-        if (!Character.isJavaIdentifierStart(name.charAt(0))) {
-            return false;
-        }
-        for (int i=1; i < name.length(); i++) {
-            char c = name.charAt(i);
-            if (c != '.'  && !Character.isJavaIdentifierPart(c)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     public void handleOptions(String[] args) throws BadArgs {
         // process options
         for (int i=0; i < args.length; i++) {
@@ -684,7 +750,7 @@
                     if (name.charAt(0) == '-') {
                         throw new BadArgs("err.option.after.class", name).showUsage(true);
                     }
-                    classes.add(name);
+                    inputArgs.add(name);
                 }
             }
         }
@@ -703,7 +769,7 @@
         log.println(getMessage("error.prefix") + " " + getMessage(key, args));
     }
 
-    private void warning(String key, Object... args) {
+    void warning(String key, Object... args) {
         log.println(getMessage("warn.prefix") + " " + getMessage(key, args));
     }
 
@@ -749,7 +815,7 @@
         boolean version;
         boolean fullVersion;
         boolean showProfile;
-        boolean showModule;
+        boolean showModule = true;
         boolean showSummary;
         boolean apiOnly;
         boolean showLabel;
@@ -761,22 +827,23 @@
         boolean filterSamePackage = true;
         boolean filterSameArchive = false;
         Pattern filterRegex;
-        String dotOutputDir;
-        String genModuleInfo;
-        String classpath = "";
+        Path dotOutputDir;
+        Path genModuleInfo;
+        String classpath;
         int depth = 1;
         Set<String> requires = new HashSet<>();
         Set<String> packageNames = new HashSet<>();
         Pattern regex;             // apply to the dependences
-        Pattern includePattern;    // apply to classes
+        Pattern includePattern;
+        Pattern includeSystemModulePattern;
+        boolean inverse = false;
         boolean compileTimeView = false;
-        boolean checkModuleDeps = false;
+        Set<String> checkModuleDeps;
+        String systemModulePath = System.getProperty("java.home");
         String upgradeModulePath;
         String modulePath;
         String rootModule;
-        // modules to be included or excluded
-        Set<String> includes = new HashSet<>();
-        Set<String> excludes = new HashSet<>();
+        Set<String> addmods = new HashSet<>();
 
         boolean hasFilter() {
             return numFilters() > 0;
@@ -789,11 +856,8 @@
             if (packageNames.size() > 0) count++;
             return count;
         }
+    }
 
-        boolean isRootModule() {
-            return rootModule != null;
-        }
-    }
     private static class ResourceBundleHelper {
         static final ResourceBundle versionRB;
         static final ResourceBundle bundle;
@@ -819,35 +883,6 @@
         }
     }
 
-    /*
-     * Returns the list of Archive specified in cpaths and not included
-     * initialArchives
-     */
-    private List<Path> getClassPaths(String cpaths) throws IOException
-    {
-        if (cpaths.isEmpty()) {
-            return Collections.emptyList();
-        }
-        List<Path> paths = new ArrayList<>();
-        for (String p : cpaths.split(File.pathSeparator)) {
-            if (p.length() > 0) {
-                // wildcard to parse all JAR files e.g. -classpath dir/*
-                int i = p.lastIndexOf(".*");
-                if (i > 0) {
-                    Path dir = Paths.get(p.substring(0, i));
-                    try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.jar")) {
-                        for (Path entry : stream) {
-                            paths.add(entry);
-                        }
-                    }
-                } else {
-                    paths.add(Paths.get(p));
-                }
-            }
-        }
-        return paths;
-    }
-
     /**
      * Returns the recommended replacement API for the given classname;
      * or return null if replacement API is not known.
@@ -865,32 +900,5 @@
             }
         }
         return value;
-    };
-
-    private void showReplacements(List<Archive> archives, Analyzer analyzer) {
-        Map<String,String> jdkinternals = new TreeMap<>();
-        boolean useInternals = false;
-        for (Archive source : archives) {
-            useInternals = useInternals || analyzer.hasDependences(source);
-            for (String cn : analyzer.dependences(source)) {
-                String repl = replacementFor(cn);
-                if (repl != null) {
-                    jdkinternals.putIfAbsent(cn, repl);
-                }
-            }
-        }
-        if (useInternals) {
-            log.println();
-            warning("warn.replace.useJDKInternals", getMessage("jdeps.wiki.url"));
-        }
-        if (!jdkinternals.isEmpty()) {
-            log.println();
-            log.format("%-40s %s%n", "JDK Internal API", "Suggested Replacement");
-            log.format("%-40s %s%n", "----------------", "---------------------");
-            for (Map.Entry<String,String> e : jdkinternals.entrySet()) {
-                log.format("%-40s %s%n", e.getKey(), e.getValue());
-            }
-        }
     }
-
 }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java	Thu May 19 19:47:04 2016 +0000
@@ -24,23 +24,33 @@
  */
 package com.sun.tools.jdeps;
 
+import static com.sun.tools.jdeps.Analyzer.Type.*;
+
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor.Requires;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 
-import static com.sun.tools.jdeps.Analyzer.Type.*;
+public abstract class JdepsWriter {
+    public static JdepsWriter newDotWriter(Path outputdir, Analyzer.Type type) {
+        return new DotFileWriter(outputdir, type, false, true, false);
+    }
 
-public abstract class JdepsWriter {
+    public static JdepsWriter newSimpleWriter(PrintWriter writer,  Analyzer.Type type) {
+        return new SimpleWriter(writer, type, false, true);
+    }
+
     final Analyzer.Type type;
     final boolean showProfile;
     final boolean showModule;
 
-    JdepsWriter(Analyzer.Type type, boolean showProfile, boolean showModule) {
+    private JdepsWriter(Analyzer.Type type, boolean showProfile, boolean showModule) {
         this.type = type;
         this.showProfile = showProfile;
         this.showModule = showModule;
@@ -48,7 +58,7 @@
 
     abstract void generateOutput(Collection<Archive> archives, Analyzer analyzer) throws IOException;
 
-    public static class DotFileWriter extends JdepsWriter {
+    static class DotFileWriter extends JdepsWriter {
         final boolean showLabel;
         final Path outputDir;
         DotFileWriter(Path dir, Analyzer.Type type,
@@ -62,8 +72,10 @@
         void generateOutput(Collection<Archive> archives, Analyzer analyzer)
                 throws IOException
         {
+            Files.createDirectories(outputDir);
+
             // output individual .dot file for each archive
-            if (type != SUMMARY) {
+            if (type != SUMMARY && type != MODULE) {
                 archives.stream()
                         .filter(analyzer::hasDependences)
                         .forEach(archive -> {
@@ -85,13 +97,13 @@
         {
             // If verbose mode (-v or -verbose option),
             // the summary.dot file shows package-level dependencies.
-            Analyzer.Type summaryType =
-                (type == PACKAGE || type == SUMMARY) ? SUMMARY : PACKAGE;
+            boolean isSummary =  type == PACKAGE || type == SUMMARY || type == MODULE;
+            Analyzer.Type summaryType = isSummary ? SUMMARY : PACKAGE;
             Path summary = outputDir.resolve("summary.dot");
             try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary));
                  SummaryDotFile dotfile = new SummaryDotFile(sw, summaryType)) {
                 for (Archive archive : archives) {
-                    if (type == PACKAGE || type == SUMMARY) {
+                    if (isSummary) {
                         if (showLabel) {
                             // build labels listing package-level dependencies
                             analyzer.visitDependences(archive, dotfile.labelBuilder(), PACKAGE);
@@ -208,19 +220,22 @@
         void generateOutput(Collection<Archive> archives, Analyzer analyzer) {
             RawOutputFormatter depFormatter = new RawOutputFormatter(writer);
             RawSummaryFormatter summaryFormatter = new RawSummaryFormatter(writer);
-            for (Archive archive : archives) {
-                // print summary
-                if (showModule && archive.getModule().isNamed()) {
-                    summaryFormatter.showModuleRequires(archive.getModule());
-                } else {
+            archives.stream()
+                .filter(analyzer::hasDependences)
+                .sorted(Comparator.comparing(Archive::getName))
+                .forEach(archive -> {
+                    if (showModule && archive.getModule().isNamed() && type != SUMMARY) {
+                        // print module-info except -summary
+                        summaryFormatter.printModuleDescriptor(archive.getModule());
+                    }
+                    // print summary
                     analyzer.visitDependences(archive, summaryFormatter, SUMMARY);
-                }
 
-                if (analyzer.hasDependences(archive) && type != SUMMARY) {
-                    // print the class-level or package-level dependences
-                    analyzer.visitDependences(archive, depFormatter);
-                }
-            }
+                    if (analyzer.hasDependences(archive) && type != SUMMARY) {
+                        // print the class-level or package-level dependences
+                        analyzer.visitDependences(archive, depFormatter);
+                    }
+            });
         }
 
         class RawOutputFormatter implements Analyzer.Visitor {
@@ -269,20 +284,16 @@
                 writer.format("%n");
             }
 
-            public void showModuleRequires(Module module) {
+            public void printModuleDescriptor(Module module) {
                 if (!module.isNamed())
                     return;
 
-                writer.format("module %s", module.name());
-                if (module.isAutomatic())
-                    writer.format(" (automatic)");
-                writer.println();
-                module.requires().keySet()
+                writer.format("%s%s%n", module.name(), module.isAutomatic() ? " automatic" : "");
+                writer.format(" [%s]%n", module.location());
+                module.descriptor().requires()
                         .stream()
-                        .sorted()
-                        .forEach(req -> writer.format(" requires %s%s%n",
-                                                      module.requires.get(req) ? "public " : "",
-                                                      req));
+                        .sorted(Comparator.comparing(Requires::name))
+                        .forEach(req -> writer.format("   requires %s%n", req));
             }
         }
     }
@@ -307,7 +318,7 @@
         }
 
         // exported API
-        boolean jdkunsupported = Module.isJDKUnsupported(module, pn);
+        boolean jdkunsupported = Module.JDK_UNSUPPORTED.equals(module.name());
         if (module.isExported(pn) && !jdkunsupported) {
             return showProfileOrModule(module);
         }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java	Thu May 19 19:47:04 2016 +0000
@@ -25,67 +25,56 @@
 
 package com.sun.tools.jdeps;
 
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UncheckedIOException;
 import java.lang.module.ModuleDescriptor;
 import java.net.URI;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
 import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.stream.Collectors;
 
 /**
- * JDeps internal representation of module for dependency analysis.
+ * Jdeps internal representation of module for dependency analysis.
  */
 class Module extends Archive {
-    static final boolean traceOn = Boolean.getBoolean("jdeps.debug");
+    static final Module UNNAMED_MODULE = new UnnamedModule();
+    static final String JDK_UNSUPPORTED = "jdk.unsupported";
+
+    static final boolean DEBUG = Boolean.getBoolean("jdeps.debug");
     static void trace(String fmt, Object... args) {
+        trace(DEBUG, fmt, args);
+    }
+
+    static void trace(boolean traceOn, String fmt, Object... args) {
         if (traceOn) {
             System.err.format(fmt, args);
         }
     }
 
-    /*
-     * Returns true if the given package name is JDK critical internal API
-     * in jdk.unsupported module
-     */
-    static boolean isJDKUnsupported(Module m, String pn) {
-        return JDK_UNSUPPORTED.equals(m.name()) || unsupported.contains(pn);
-    };
+    private final ModuleDescriptor descriptor;
+    private final Map<String, Set<String>> exports;
+    private final boolean isSystem;
+    private final URI location;
 
-    protected final ModuleDescriptor descriptor;
-    protected final Map<String, Boolean> requires;
-    protected final Map<String, Set<String>> exports;
-    protected final Set<String> packages;
-    protected final boolean isJDK;
-    protected final URI location;
+    protected Module(String name) {
+        super(name);
+        this.descriptor = null;
+        this.location = null;
+        this.exports = Collections.emptyMap();
+        this.isSystem = true;
+    }
 
     private Module(String name,
                    URI location,
                    ModuleDescriptor descriptor,
-                   Map<String, Boolean> requires,
                    Map<String, Set<String>> exports,
-                   Set<String> packages,
-                   boolean isJDK,
+                   boolean isSystem,
                    ClassFileReader reader) {
         super(name, location, reader);
         this.descriptor = descriptor;
         this.location = location;
-        this.requires = Collections.unmodifiableMap(requires);
         this.exports = Collections.unmodifiableMap(exports);
-        this.packages = Collections.unmodifiableSet(packages);
-        this.isJDK = isJDK;
+        this.isSystem = isSystem;
     }
 
     /**
@@ -111,31 +100,35 @@
         return descriptor;
     }
 
-    public boolean isJDK() {
-        return isJDK;
+    public URI location() {
+        return location;
     }
 
-    public Map<String, Boolean> requires() {
-        return requires;
+    public boolean isJDK() {
+        String mn = name();
+        return isSystem &&
+            (mn.startsWith("java.") || mn.startsWith("jdk.") || mn.startsWith("javafx."));
+    }
+
+    public boolean isSystem() {
+        return isSystem;
     }
 
     public Map<String, Set<String>> exports() {
         return exports;
     }
 
-    public Map<String, Set<String>> provides() {
-        return descriptor.provides().entrySet().stream()
-                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().providers()));
-    }
-
     public Set<String> packages() {
-        return packages;
+        return descriptor.packages();
     }
 
     /**
      * Tests if the package of the given name is exported.
      */
     public boolean isExported(String pn) {
+        if (JDK_UNSUPPORTED.equals(this.name())) {
+            return false;
+        }
         return exports.containsKey(pn) ? exports.get(pn).isEmpty() : false;
     }
 
@@ -159,11 +152,6 @@
         return isExported(pn) || exports.containsKey(pn) && exports.get(pn).contains(target);
     }
 
-    private final static String JDK_UNSUPPORTED = "jdk.unsupported";
-
-    // temporary until jdk.unsupported module
-    private final static List<String> unsupported = Arrays.asList("sun.misc", "sun.reflect");
-
     @Override
     public String toString() {
         return name();
@@ -171,21 +159,19 @@
 
     public final static class Builder {
         final String name;
-        final Map<String, Boolean> requires = new HashMap<>();
-        final Map<String, Set<String>> exports = new HashMap<>();
-        final Set<String> packages = new HashSet<>();
-        final boolean isJDK;
+        final ModuleDescriptor descriptor;
+        final boolean isSystem;
         ClassFileReader reader;
-        ModuleDescriptor descriptor;
         URI location;
 
-        public Builder(String name) {
-            this(name, false);
+        public Builder(ModuleDescriptor md) {
+            this(md, false);
         }
 
-        public Builder(String name, boolean isJDK) {
-            this.name = name;
-            this.isJDK = isJDK;
+        public Builder(ModuleDescriptor md, boolean isSystem) {
+            this.name = md.name();
+            this.descriptor = md;
+            this.isSystem = isSystem;
         }
 
         public Builder location(URI location) {
@@ -193,48 +179,30 @@
             return this;
         }
 
-        public Builder descriptor(ModuleDescriptor md) {
-            this.descriptor = md;
-            return this;
-        }
-
-        public Builder require(String d, boolean reexport) {
-            requires.put(d, reexport);
-            return this;
-        }
-
-        public Builder packages(Set<String> pkgs) {
-            packages.addAll(pkgs);
-            return this;
-        }
-
-        public Builder export(String p, Set<String> ms) {
-            Objects.requireNonNull(p);
-            Objects.requireNonNull(ms);
-            exports.put(p, new HashSet<>(ms));
-            return this;
-        }
         public Builder classes(ClassFileReader reader) {
             this.reader = reader;
             return this;
         }
 
         public Module build() {
-            if (descriptor.isAutomatic() && isJDK) {
+            if (descriptor.isAutomatic() && isSystem) {
                 throw new InternalError("JDK module: " + name + " can't be automatic module");
             }
 
-            return new Module(name, location, descriptor, requires, exports, packages, isJDK, reader);
+            Map<String, Set<String>> exports = new HashMap<>();
+
+            descriptor.exports().stream()
+                .forEach(exp -> exports.computeIfAbsent(exp.source(), _k -> new HashSet<>())
+                                    .addAll(exp.targets()));
+
+            return new Module(name, location, descriptor, exports, isSystem, reader);
         }
     }
 
-    final static Module UNNAMED_MODULE = new UnnamedModule();
     private static class UnnamedModule extends Module {
         private UnnamedModule() {
             super("unnamed", null, null,
                   Collections.emptyMap(),
-                  Collections.emptyMap(),
-                  Collections.emptySet(),
                   false, null);
         }
 
@@ -260,10 +228,7 @@
     }
 
     private static class StrictModule extends Module {
-        private static final String SERVICES_PREFIX = "META-INF/services/";
-        private final Map<String, Set<String>> provides;
-        private final Module module;
-        private final JarFile jarfile;
+        private final ModuleDescriptor md;
 
         /**
          * Converts the given automatic module to a strict module.
@@ -272,114 +237,26 @@
          * declare service providers, if specified in META-INF/services configuration file
          */
         private StrictModule(Module m, Map<String, Boolean> requires) {
-            super(m.name(), m.location, m.descriptor, requires, m.exports, m.packages, m.isJDK, m.reader());
-            this.module = m;
-            try {
-                this.jarfile = new JarFile(m.path().toFile(), false);
-            } catch (IOException e) {
-                throw new UncheckedIOException(e);
-            }
-            this.provides = providers(jarfile);
+            super(m.name(), m.location, m.descriptor, m.exports, m.isSystem, m.reader());
+
+            ModuleDescriptor.Builder builder = new ModuleDescriptor.Builder(m.name());
+            requires.keySet().forEach(mn -> {
+                if (requires.get(mn).equals(Boolean.TRUE)) {
+                    builder.requires(ModuleDescriptor.Requires.Modifier.PUBLIC, mn);
+                } else {
+                    builder.requires(mn);
+                }
+            });
+            m.descriptor.exports().forEach(e -> builder.exports(e));
+            m.descriptor.uses().forEach(s -> builder.uses(s));
+            m.descriptor.provides().values().forEach(p -> builder.provides(p));
+            builder.conceals(m.descriptor.conceals());
+            this.md = builder.build();
         }
 
         @Override
-        public Map<String, Set<String>> provides() {
-            return provides;
-        }
-
-        private Map<String, Set<String>> providers(JarFile jf) {
-            Map<String, Set<String>> provides = new HashMap<>();
-            // map names of service configuration files to service names
-            Set<String> serviceNames =  jf.stream()
-                    .map(e -> e.getName())
-                    .filter(e -> e.startsWith(SERVICES_PREFIX))
-                    .distinct()
-                    .map(this::toServiceName)
-                    .filter(Optional::isPresent)
-                    .map(Optional::get)
-                    .collect(Collectors.toSet());
-
-            // parse each service configuration file
-            for (String sn : serviceNames) {
-                JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
-                Set<String> providerClasses = new HashSet<>();
-                try (InputStream in = jf.getInputStream(entry)) {
-                    BufferedReader reader
-                            = new BufferedReader(new InputStreamReader(in, "UTF-8"));
-                    String cn;
-                    while ((cn = nextLine(reader)) != null) {
-                        if (isJavaIdentifier(cn)) {
-                            providerClasses.add(cn);
-                        }
-                    }
-                } catch (IOException e) {
-                    throw new UncheckedIOException(e);
-                }
-                if (!providerClasses.isEmpty())
-                    provides.put(sn, providerClasses);
-            }
-
-            return provides;
-        }
-
-        /**
-         * Returns a container with the service type corresponding to the name of
-         * a services configuration file.
-         *
-         * For example, if called with "META-INF/services/p.S" then this method
-         * returns a container with the value "p.S".
-         */
-        private Optional<String> toServiceName(String cf) {
-            assert cf.startsWith(SERVICES_PREFIX);
-            int index = cf.lastIndexOf("/") + 1;
-            if (index < cf.length()) {
-                String prefix = cf.substring(0, index);
-                if (prefix.equals(SERVICES_PREFIX)) {
-                    String sn = cf.substring(index);
-                    if (isJavaIdentifier(sn))
-                        return Optional.of(sn);
-                }
-            }
-            return Optional.empty();
-        }
-
-        /**
-         * Reads the next line from the given reader and trims it of comments and
-         * leading/trailing white space.
-         *
-         * Returns null if the reader is at EOF.
-         */
-        private String nextLine(BufferedReader reader) throws IOException {
-            String ln = reader.readLine();
-            if (ln != null) {
-                int ci = ln.indexOf('#');
-                if (ci >= 0)
-                    ln = ln.substring(0, ci);
-                ln = ln.trim();
-            }
-            return ln;
-        }
-
-        /**
-         * Returns {@code true} if the given identifier is a legal Java identifier.
-         */
-        private static boolean isJavaIdentifier(String id) {
-            int n = id.length();
-            if (n == 0)
-                return false;
-            if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
-                return false;
-            int cp = id.codePointAt(0);
-            int i = Character.charCount(cp);
-            for (; i < n; i += Character.charCount(cp)) {
-                cp = id.codePointAt(i);
-                if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
-                    return false;
-            }
-            if (cp == '.')
-                return false;
-
-            return true;
+        public ModuleDescriptor descriptor() {
+            return md;
         }
     }
 }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java	Thu May 19 19:47:04 2016 +0000
@@ -24,277 +24,364 @@
  */
 package com.sun.tools.jdeps;
 
+import static com.sun.tools.jdeps.Graph.*;
+import static com.sun.tools.jdeps.JdepsFilter.DEFAULT_FILTER;
+import static com.sun.tools.jdeps.Module.*;
+import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
+import static java.util.stream.Collectors.*;
+
+import com.sun.tools.classfile.Dependency;
+import com.sun.tools.jdeps.JdepsTask.BadArgs;
+
 import java.io.IOException;
-import java.io.PrintStream;
-import java.io.UncheckedIOException;
-
-import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
-
-import java.lang.module.Configuration;
+import java.io.OutputStream;
+import java.io.PrintWriter;
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReference;
-import java.lang.module.ResolvedModule;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
-import java.util.function.Consumer;
 import java.util.function.Function;
-import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static com.sun.tools.jdeps.Module.*;
-import static com.sun.tools.jdeps.ModulePaths.SystemModulePath.JAVA_BASE;
-
 /**
  * Analyze module dependences and compare with module descriptor.
  * Also identify any qualified exports not used by the target module.
  */
-class ModuleAnalyzer {
-    private final ModulePaths modulePaths;
+public class ModuleAnalyzer {
+    private static final String JAVA_BASE = "java.base";
+
+    private final JdepsConfiguration configuration;
+    private final PrintWriter log;
+
     private final DependencyFinder dependencyFinder;
-    private final Module root;
-    private final Set<Module> modules;
-    private final Set<String> requiresPublic = new HashSet<>();
-    private final Set<String> requires = new HashSet<>();
-    private final Set<Module> exportTargets = new HashSet<>();
-    private final JdepsFilter filter;
-    private Graph<Module> graph;
-    ModuleAnalyzer(ModulePaths modulePaths, DependencyFinder finder,
-                   String moduleName) {
-        this.modulePaths = modulePaths;
-        this.dependencyFinder = finder;
-        this.root = modulePaths.getModules().get(moduleName);
-        this.modules = modulePaths.dependences(moduleName);
+    private final Map<Module, ModuleDeps> modules;
 
-        root.exports().values().stream()
-             .flatMap(Set::stream)
-             .map(target -> modulePaths.getModules().get(target))
-             .forEach(this.exportTargets::add);
+    public ModuleAnalyzer(JdepsConfiguration config,
+                          PrintWriter log) {
+        this(config, log, Collections.emptySet());
+    }
+    public ModuleAnalyzer(JdepsConfiguration config,
+                          PrintWriter log,
+                          Set<String> names) {
 
-        this.filter = new JdepsFilter.Builder().filter(true, true).build();
+        if (!config.initialArchives().isEmpty()) {
+            String list = config.initialArchives().stream()
+                .map(Archive::getPathName).collect(joining(" "));
+            throw new JdepsTask.UncheckedBadArgs(new BadArgs("err.invalid.module.option",
+                list, "-check"));
+        }
+
+        this.configuration = config;
+        this.log = log;
+
+        this.dependencyFinder = new DependencyFinder(config, DEFAULT_FILTER);
+        if (names.isEmpty()) {
+            this.modules = configuration.rootModules().stream()
+                .collect(toMap(Function.identity(), ModuleDeps::new));
+        } else {
+            this.modules = names.stream()
+                .map(configuration::findModule)
+                .flatMap(Optional::stream)
+                .collect(toMap(Function.identity(), ModuleDeps::new));
+        }
     }
 
-    /**
-     * Returns a graph of transitive closure of the given modules.
-     *
-     * This method does not add the implicit read edges and is intended to
-     * get all transitive closures in (reverse) topological sort.
-     */
-    public static Graph<Module> graph(ModulePaths modulePaths, Module... modules) {
-        Graph.Builder<Module> gb = new Graph.Builder<>();
-        for (Module module : modules) {
-            module.descriptor().requires().stream()
-                    .map(ModuleDescriptor.Requires::name)
-                    .map(mn -> modulePaths.getModules().get(mn))
-                    .forEach(m -> {
-                        gb.addNode(m);
-                        gb.addEdge(module, m);
-                    });
-        }
-        return gb.build();
-    }
+    public boolean run() throws IOException {
+        try {
+            // compute "requires public" dependences
+            modules.values().forEach(ModuleDeps::computeRequiresPublic);
 
-    /**
-     * Do the analysis
-     */
-    public boolean run() {
-        try {
-            computeRequiresPublic();
-            computeRequires();
-            // apply transitive reduction and reports recommended requires.
-            analyzeDeps();
-            // detect any qualiifed exports not used by the target module
-            checkQualifiedExports();
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
+            modules.values().forEach(md -> {
+                // compute "requires" dependences
+                md.computeRequires();
+                // apply transitive reduction and reports recommended requires.
+                md.analyzeDeps();
+            });
+        } finally {
+            dependencyFinder.shutdown();
         }
         return true;
     }
 
-    /**
-     * Compute 'requires public' dependences by analyzing API dependencies
-     */
-    private void computeRequiresPublic() throws IOException {
-        JdepsFilter.Builder builder = new JdepsFilter.Builder();
-        // only analyze exported API
-        root.descriptor.exports().stream()
-                .filter(exp -> !exp.isQualified())
-                .map(ModuleDescriptor.Exports::source)
-                .forEach(builder::includePackage);
+    class ModuleDeps {
+        final Module root;
+        Set<Module> requiresPublic;
+        Set<Module> requires;
+        Map<String, Set<String>> unusedQualifiedExports;
 
-        JdepsFilter filter = builder.filter(true, true).build();
+        ModuleDeps(Module root) {
+            this.root = root;
+        }
 
-        // analyze dependences for exported packages
-        dependencyFinder.findDependencies(filter, true /* api only */, 1);
-        Analyzer analyzer = new Analyzer(Analyzer.Type.CLASS, filter);
-        analyzer.run(modules);
+        /**
+         * Compute 'requires public' dependences by analyzing API dependencies
+         */
+        private void computeRequiresPublic() {
+            // record requires public
+            this.requiresPublic = computeRequires(true)
+                .filter(m -> !m.name().equals(JAVA_BASE))
+                .collect(toSet());
 
-        // record requires public
-        analyzer.requires(root)
-                .filter(m -> m != JAVA_BASE && m != root)
-                .map(Archive::getName)
-                .forEach(requiresPublic::add);
-        trace("requires public: %s%n", requiresPublic);
-    }
+            trace("requires public: %s%n", requiresPublic);
+        }
 
-    private void computeRequires() throws IOException {
-        // add the exportTargets of the qualified exports to the root set
-        exportTargets.stream()
-                .peek(target -> trace("add root: %s%n", target))
-                .forEach(dependencyFinder::addRoot);
+        private void computeRequires() {
+            this.requires = computeRequires(false).collect(toSet());
+            trace("requires: %s%n", requires);
+        }
 
-        // analyze all classes
-        dependencyFinder.findDependencies(filter, false /* all classes */, 1);
-        Analyzer analyzer = new Analyzer(Analyzer.Type.CLASS, filter);
-        analyzer.run(modules);
+        private Stream<Module> computeRequires(boolean apionly) {
+            // analyze all classes
 
-        // record requires
-        analyzer.requires(root)
-                .filter(m -> m != JAVA_BASE && m != root)
-                .map(Archive::getName)
-                .forEach(requires::add);
+            if (apionly) {
+                dependencyFinder.parseExportedAPIs(Stream.of(root));
+            } else {
+                dependencyFinder.parse(Stream.of(root));
+            }
 
-        this.graph = buildGraph(analyzer, root);
-        if (traceOn) {
-            trace("dependences: %s%n", graph.nodes());
-            graph.printGraph(System.out);
+            // find the modules of all the dependencies found
+            return dependencyFinder.getDependences(root)
+                        .map(Archive::getModule);
+        }
+
+        ModuleDescriptor descriptor() {
+            return descriptor(requiresPublic, requires);
+        }
+
+        private ModuleDescriptor descriptor(Set<Module> requiresPublic,
+                                            Set<Module> requires) {
+
+            ModuleDescriptor.Builder builder = new ModuleDescriptor.Builder(root.name());
+
+            if (!root.name().equals(JAVA_BASE))
+                builder.requires(MANDATED, JAVA_BASE);
+
+            requiresPublic.stream()
+                .filter(m -> !m.name().equals(JAVA_BASE))
+                .map(Module::name)
+                .forEach(mn -> builder.requires(PUBLIC, mn));
+
+            requires.stream()
+                .filter(m -> !requiresPublic.contains(m))
+                .filter(m -> !m.name().equals(JAVA_BASE))
+                .map(Module::name)
+                .forEach(mn -> builder.requires(mn));
+
+            return builder.build();
+        }
+
+        ModuleDescriptor reduced() {
+            Graph.Builder<Module> bd = new Graph.Builder<>();
+            requiresPublic.stream()
+                .forEach(m -> {
+                    bd.addNode(m);
+                    bd.addEdge(root, m);
+                });
+
+            // requires public graph
+            Graph<Module> rbg = bd.build().reduce();
+
+            // transitive reduction
+            Graph<Module> newGraph = buildGraph(requires).reduce(rbg);
+            if (DEBUG) {
+                System.err.println("after transitive reduction: ");
+                newGraph.printGraph(log);
+            }
+
+            return descriptor(requiresPublic, newGraph.adjacentNodes(root));
+        }
+
+
+        /**
+         * Apply transitive reduction on the resulting graph and reports
+         * recommended requires.
+         */
+        private void analyzeDeps() {
+            Graph.Builder<Module> builder = new Graph.Builder<>();
+            requiresPublic.stream()
+                .forEach(m -> {
+                    builder.addNode(m);
+                    builder.addEdge(root, m);
+                });
+
+            // requires public graph
+            Graph<Module> rbg = buildGraph(requiresPublic).reduce();
+
+            // transitive reduction
+            Graph<Module> newGraph = buildGraph(requires).reduce(builder.build().reduce());
+            if (DEBUG) {
+                System.err.println("after transitive reduction: ");
+                newGraph.printGraph(log);
+            }
+
+            printModuleDescriptor(log, root);
+
+            ModuleDescriptor analyzedDescriptor = descriptor();
+            if (!matches(root.descriptor(), analyzedDescriptor)) {
+                log.format("  [Suggested module descriptor for %s]%n", root.name());
+                analyzedDescriptor.requires()
+                    .stream()
+                    .sorted(Comparator.comparing(ModuleDescriptor.Requires::name))
+                    .forEach(req -> log.format("    requires %s;%n", req));
+            }
+
+            ModuleDescriptor reduced = reduced();
+            if (!matches(root.descriptor(), reduced)) {
+                log.format("  [Transitive reduced graph for %s]%n", root.name());
+                reduced.requires()
+                    .stream()
+                    .sorted(Comparator.comparing(ModuleDescriptor.Requires::name))
+                    .forEach(req -> log.format("    requires %s;%n", req));
+            }
+
+            checkQualifiedExports();
+            log.println();
+        }
+
+        private void checkQualifiedExports() {
+            // detect any qualified exports not used by the target module
+            unusedQualifiedExports = unusedQualifiedExports();
+            if (!unusedQualifiedExports.isEmpty())
+                log.format("  [Unused qualified exports in %s]%n", root.name());
+
+            unusedQualifiedExports.keySet().stream()
+                .sorted()
+                .forEach(pn -> log.format("    exports %s to %s%n", pn,
+                    unusedQualifiedExports.get(pn).stream()
+                        .sorted()
+                        .collect(joining(","))));
+        }
+
+        private void printModuleDescriptor(PrintWriter out, Module module) {
+            ModuleDescriptor descriptor = module.descriptor();
+            out.format("%s (%s)%n", descriptor.name(), module.location());
+
+            if (descriptor.name().equals(JAVA_BASE))
+                return;
+
+            out.println("  [Module descriptor]");
+            descriptor.requires()
+                .stream()
+                .sorted(Comparator.comparing(ModuleDescriptor.Requires::name))
+                .forEach(req -> out.format("    requires %s;%n", req));
+        }
+
+
+        /**
+         * Returns a graph of modules required by the specified module.
+         *
+         * Requires public edges of the dependences are added to the graph.
+         */
+        private Graph<Module> buildGraph(Set<Module> deps) {
+            Graph.Builder<Module> builder = new Graph.Builder<>();
+            builder.addNode(root);
+            Set<Module> visited = new HashSet<>();
+            visited.add(root);
+            Deque<Module> deque = new LinkedList<>();
+            deps.stream()
+                .forEach(m -> {
+                    deque.add(m);
+                    builder.addEdge(root, m);
+                });
+
+            // read requires public from ModuleDescription
+            Module source;
+            while ((source = deque.poll()) != null) {
+                if (visited.contains(source))
+                    continue;
+
+                visited.add(source);
+                builder.addNode(source);
+                Module from = source;
+                source.descriptor().requires().stream()
+                    .filter(req -> req.modifiers().contains(PUBLIC))
+                    .map(ModuleDescriptor.Requires::name)
+                    .map(configuration::findModule)
+                    .flatMap(Optional::stream)
+                    .forEach(m -> {
+                        deque.add(m);
+                        builder.addEdge(from, m);
+                    });
+            }
+            return builder.build();
+        }
+
+        /**
+         * Detects any qualified exports not used by the target module.
+         */
+        private Map<String, Set<String>> unusedQualifiedExports() {
+            Map<String, Set<String>> unused = new HashMap<>();
+
+            // build the qualified exports map
+            Map<String, Set<String>> qualifiedExports =
+                root.exports().entrySet().stream()
+                    .filter(e -> !e.getValue().isEmpty())
+                    .map(Map.Entry::getKey)
+                    .collect(toMap(Function.identity(), _k -> new HashSet<>()));
+
+            Set<Module> mods = new HashSet<>();
+            root.exports().values()
+                .stream()
+                .flatMap(Set::stream)
+                .forEach(target -> configuration.findModule(target)
+                    .ifPresentOrElse(mods::add,
+                        () -> log.format("Warning: %s not found%n", target))
+                );
+
+            // parse all target modules
+            dependencyFinder.parse(mods.stream());
+
+            // adds to the qualified exports map if a module references it
+            mods.stream().forEach(m ->
+                m.getDependencies()
+                    .map(Dependency.Location::getPackageName)
+                    .filter(qualifiedExports::containsKey)
+                    .forEach(pn -> qualifiedExports.get(pn).add(m.name())));
+
+            // compare with the exports from ModuleDescriptor
+            Set<String> staleQualifiedExports =
+                qualifiedExports.keySet().stream()
+                    .filter(pn -> !qualifiedExports.get(pn).equals(root.exports().get(pn)))
+                    .collect(toSet());
+
+            if (!staleQualifiedExports.isEmpty()) {
+                for (String pn : staleQualifiedExports) {
+                    Set<String> targets = new HashSet<>(root.exports().get(pn));
+                    targets.removeAll(qualifiedExports.get(pn));
+                    unused.put(pn, targets);
+                }
+            }
+            return unused;
         }
     }
 
-    /**
-     * Apply transitive reduction on the resulting graph and reports
-     * recommended requires.
-     */
-    private void analyzeDeps() {
-        String moduleName = root.name();
+    private boolean matches(ModuleDescriptor md, ModuleDescriptor other) {
+        // build requires public from ModuleDescriptor
+        Set<ModuleDescriptor.Requires> reqPublic = md.requires().stream()
+            .filter(req -> req.modifiers().contains(PUBLIC))
+            .collect(toSet());
+        Set<ModuleDescriptor.Requires> otherReqPublic = other.requires().stream()
+            .filter(req -> req.modifiers().contains(PUBLIC))
+            .collect(toSet());
 
-        Graph.Builder<String> builder = new Graph.Builder<>();
-        requiresPublic.stream()
-                .forEach(mn -> {
-                    builder.addNode(mn);
-                    builder.addEdge(moduleName, mn);
-                });
-        // requires public graph
-        Graph<String> rbg = builder.build().reduce();
-
-        // convert the dependence graph from Module to name
-        Set<String> nodes = this.graph.nodes().stream()
-                .map(Module::name)
-                .collect(Collectors.toSet());
-        Map<String, Set<String>> edges = new HashMap<>();
-        this.graph.edges().keySet().stream()
-                .forEach(m -> {
-                    String mn = m.name();
-                    Set<String> es = edges.computeIfAbsent(mn, _k -> new HashSet<String>());
-                    this.graph.edges().get(m).stream()
-                            .map(Module::name)
-                            .forEach(es::add);
-                });
-
-        // transitive reduction
-        Graph<String> newGraph = new Graph<>(nodes, edges).reduce(rbg);
-        if (traceOn) {
-            System.out.println("after transitive reduction");
-            newGraph.printGraph(System.out);
-        };
-
-        Set<String> reducedRequires = newGraph.adjacentNodes(moduleName);
-        if (matches(root.descriptor(), requires, requiresPublic) &&
-                matches(root.descriptor(), reducedRequires, requiresPublic)) {
-            System.out.println("--- Analysis result: no change for " + root.name());
-        } else {
-            System.out.println("--- Analysis result: suggested requires for " + root.name());
-            System.out.format("module %s%n", root.name());
-                requires.stream()
-                        .sorted()
-                        .forEach(dn -> System.out.format("  requires %s%s;%n",
-                                requiresPublic.contains(dn) ? "public " : "", dn));
-            if (!requires.equals(reducedRequires) && !reducedRequires.isEmpty()) {
-                System.out.format("%nmodule %s (reduced)%n", root.name());
-                newGraph.adjacentNodes(moduleName)
-                     .stream()
-                     .sorted()
-                     .forEach(dn -> System.out.format("  requires %s%s;%n",
-                                requiresPublic.contains(dn) ? "public " : "", dn));
-            }
-            System.out.println("\n---  Module descriptor");
-            Graph<Module> mdGraph = graph(modulePaths, root);
-            mdGraph.reverse(m -> printModuleDescriptor(System.out, m.descriptor()));
-        }
-    }
-
-    /**
-     * Detects any qualified exports not used by the target module.
-     */
-    private void checkQualifiedExports() throws IOException {
-        Analyzer analyzer = new Analyzer(Analyzer.Type.CLASS, filter);
-        analyzer.run(dependencyFinder.roots());
-
-        // build the qualified exports map
-        Map<String, Set<String>> qualifiedExports =
-            root.exports().entrySet().stream()
-                .filter(e -> !e.getValue().isEmpty())
-                .map(Map.Entry::getKey)
-                .collect(Collectors.toMap(Function.identity(), _k -> new HashSet<>()));
-
-        // adds to the qualified exports map if a module references it
-        for (Module m : exportTargets) {
-            analyzer.dependences(m).stream()
-                    .map(this::toPackageName)
-                    .filter(qualifiedExports::containsKey)
-                    .forEach(pn -> qualifiedExports.get(pn).add(m.name()));
-        }
-
-        // compare with the exports from ModuleDescriptor
-        Set<String> staleQualifiedExports =
-            qualifiedExports.keySet().stream()
-                .filter(pn -> !qualifiedExports.get(pn).equals(root.exports().get(pn)))
-                .collect(Collectors.toSet());
-
-        if (!staleQualifiedExports.isEmpty()) {
-            System.out.println("--- Unused qualified exports in " + root.name());
-            for (String pn : staleQualifiedExports) {
-                Set<String> unused = new HashSet<>(root.exports().get(pn));
-                unused.removeAll(qualifiedExports.get(pn));
-                System.out.format("  exports %s to %s%n", pn,
-                                  unused.stream().collect(Collectors.joining(",")));
-            }
-        }
-    }
-
-    private String toPackageName(String cn) {
-        int i = cn.lastIndexOf('.');
-        return i > 0 ? cn.substring(0, i) : "";
-    }
-
-    private boolean matches(ModuleDescriptor md, Set<String> requires, Set<String> requiresPublic) {
-        Set<String> reqPublic = md.requires().stream()
-                .filter(req -> req.modifiers().contains(PUBLIC))
-                .map(ModuleDescriptor.Requires::name)
-                .collect(Collectors.toSet());
-        if (!requiresPublic.equals(reqPublic)) {
+        if (!reqPublic.equals(otherReqPublic)) {
             trace("mismatch requires public: %s%n", reqPublic);
             return false;
         }
-        // java.base is not in requires
-        int javaBase = md.name().equals(JAVA_BASE.name()) ? 0 : 1;
-        if (requires.size()+javaBase != md.requires().size()) {
-            trace("mismatch requires: %d != %d%n", requires.size()+1, md.requires().size());
-            return false;
-        }
 
-        Set<String> unused = md.requires().stream()
-                 .map(ModuleDescriptor.Requires::name)
-                 .filter(req -> !requires.contains(req) && !req.equals(JAVA_BASE.name()))
-                 .collect(Collectors.toSet());
+        Set<ModuleDescriptor.Requires> unused = md.requires().stream()
+            .filter(req -> !other.requires().contains(req))
+            .collect(Collectors.toSet());
+
         if (!unused.isEmpty()) {
             trace("mismatch requires: %s%n", unused);
             return false;
@@ -302,371 +389,50 @@
         return true;
     }
 
-    private void printModuleDescriptor(PrintStream out, ModuleDescriptor descriptor) {
-        if (descriptor.name().equals("java.base"))
-            return;
-
-        out.format("module %s%n", descriptor.name());
-        descriptor.requires()
-                .stream()
-                .sorted(Comparator.comparing(ModuleDescriptor.Requires::name))
-                .forEach(req -> out.format("  requires %s;%n", req));
+    /**
+     * Generate dotfile from module descriptor
+     *
+     * @param dir output directory
+     */
+    public boolean genDotFiles(Path dir) throws IOException {
+        Files.createDirectories(dir);
+        for (Module m : modules.keySet()) {
+            genDotFile(dir, m.name());
+        }
+        return true;
     }
 
-    /**
-     * Returns a graph of modules required by the specified module.
-     *
-     * Requires public edges of the dependences are added to the graph.
-     */
-    private Graph<Module> buildGraph(Analyzer analyzer, Module module) {
-        Graph.Builder<Module> builder = new Graph.Builder<>();
-        builder.addNode(module);
-        Set<Module> visited = new HashSet<>();
-        visited.add(module);
-        Deque<Module> deque = new LinkedList<>();
-        analyzer.requires(module)
-                .map(Archive::getModule)
-                .filter(m -> m != JAVA_BASE)
-                .forEach(m -> {
-                    deque.add(m);
-                    builder.addEdge(module, m);
-                });
 
-        // read requires public from ModuleDescription
-        Module source;
-        while ((source = deque.poll()) != null) {
-            if (visited.contains(source))
-                continue;
-            visited.add(source);
-            builder.addNode(source);
-            Module from = source;
-            source.descriptor().requires().stream()
-                    .filter(req -> req.modifiers().contains(PUBLIC))
-                    .map(ModuleDescriptor.Requires::name)
-                    .map(req -> modulePaths.getModules().get(req))
-                    .filter(m -> m != JAVA_BASE)
-                    .forEach(m -> {
-                        deque.add(m);
-                        builder.addEdge(from, m);
-                    });
-        }
-        return builder.build();
-    }
-
-    static class Graph<T> {
-        private final Set<T> nodes;
-        private final Map<T, Set<T>> edges;
-
-        private Graph(Set<T> nodes, Map<T, Set<T>> edges) {
-            this.nodes = nodes;
-            this.edges = edges;
-        }
-
-        public Set<T> nodes() {
-            return nodes;
-        }
-
-        public Map<T, Set<T>> edges() {
-            return edges;
-        }
-
-        public Set<T> adjacentNodes(T u) {
-            return edges.get(u);
-        }
-
-        /**
-         * Returns a new Graph after transitive reduction
-         */
-        public Graph<T> reduce() {
-            Graph.Builder<T> builder = new Builder<>();
-            nodes.stream()
-                    .forEach(u -> {
-                        builder.addNode(u);
-                        edges.get(u).stream()
-                                .filter(v -> !pathExists(u, v, false))
-                                .forEach(v -> builder.addEdge(u, v));
-                    });
-            return builder.build();
-        }
-
-        /**
-         * Returns a new Graph after transitive reduction.  All edges in
-         * the given g takes precedence over this graph.
-         *
-         * @throw IllegalArgumentException g must be a subgraph this graph
-         */
-        public Graph<T> reduce(Graph<T> g) {
-            boolean subgraph = nodes.containsAll(g.nodes) && g.edges.keySet().stream()
-                    .allMatch(u -> adjacentNodes(u).containsAll(g.adjacentNodes(u)));
-            if (!subgraph) {
-                throw new IllegalArgumentException(g + " is not a subgraph of " + this);
-            }
-
-            Graph.Builder<T> builder = new Builder<>();
-            nodes.stream()
-                    .forEach(u -> {
-                        builder.addNode(u);
-                        // filter the edge if there exists a path from u to v in the given g
-                        // or there exists another path from u to v in this graph
-                        edges.get(u).stream()
-                                .filter(v -> !g.pathExists(u, v) && !pathExists(u, v, false))
-                                .forEach(v -> builder.addEdge(u, v));
-                    });
-
-            // add the overlapped edges from this graph and the given g
-            g.edges().keySet().stream()
-                    .forEach(u -> g.adjacentNodes(u).stream()
-                                    .filter(v -> isAdjacent(u, v))
-                                    .forEach(v -> builder.addEdge(u, v)));
-            return builder.build();
-        }
-
-        /**
-         * Returns nodes sorted in topological order.
-         */
-        public Stream<T> orderedNodes() {
-            TopoSorter<T> sorter = new TopoSorter<>(this);
-            return sorter.result.stream();
-        }
-
-        /**
-         * Iterates the nodes sorted in topological order and performs the
-         * given action.
-         */
-        public void ordered(Consumer<T> action) {
-            TopoSorter<T> sorter = new TopoSorter<>(this);
-            sorter.ordered(action);
-        }
-
-        /**
-         * Iterates the nodes sorted in reverse topological order and
-         * performs the given action.
-         */
-        public void reverse(Consumer<T> action) {
-            TopoSorter<T> sorter = new TopoSorter<>(this);
-            sorter.reverse(action);
-        }
-
-        private boolean isAdjacent(T u, T v) {
-            return edges.containsKey(u) && edges.get(u).contains(v);
-        }
-
-        private boolean pathExists(T u, T v) {
-            return pathExists(u, v, true);
-        }
-
-        /**
-         * Returns true if there exists a path from u to v in this graph.
-         * If includeAdjacent is false, it returns true if there exists
-         * another path from u to v of distance > 1
-         */
-        private boolean pathExists(T u, T v, boolean includeAdjacent) {
-            if (!nodes.contains(u) || !nodes.contains(v)) {
-                return false;
-            }
-            if (includeAdjacent && isAdjacent(u, v)) {
-                return true;
-            }
-            Deque<T> stack = new LinkedList<>();
-            Set<T> visited = new HashSet<>();
-            stack.push(u);
-            while (!stack.isEmpty()) {
-                T node = stack.pop();
-                if (node.equals(v)) {
-                    return true;
-                }
-                if (!visited.contains(node)) {
-                    visited.add(node);
-                    edges.get(node).stream()
-                            .filter(e -> includeAdjacent || !node.equals(u) || !e.equals(v))
-                            .forEach(e -> stack.push(e));
-                }
-            }
-            assert !visited.contains(v);
-            return false;
-        }
-
-        void printGraph(PrintStream out) {
-            out.println("graph for " + nodes);
-            nodes.stream()
-                 .forEach(u -> adjacentNodes(u).stream()
-                                   .forEach(v -> out.format("%s -> %s%n", u, v)));
-        }
-
-        @Override
-        public String toString() {
-            return nodes.toString();
-        }
-
-        static class Builder<T> {
-            final Set<T> nodes = new HashSet<>();
-            final Map<T, Set<T>> edges = new HashMap<>();
-
-            public void addNode(T node) {
-                if (nodes.contains(node)) {
-                    return;
-                }
-                nodes.add(node);
-                edges.computeIfAbsent(node, _e -> new HashSet<>());
-            }
-
-            public void addEdge(T u, T v) {
-                addNode(u);
-                addNode(v);
-                edges.get(u).add(v);
-            }
-
-            public Graph<T> build() {
-                return new Graph<>(nodes, edges);
-            }
-
-            void print(PrintStream out) {
-                out.println(nodes);
-                nodes.stream()
-                        .forEach(u -> edges.get(u).stream()
-                                        .forEach(v -> out.format("%s -> %s%n", u, v)));
-            }
-        }
-    }
-
-    static class TopoSorter<T> {
-        final Deque<T> result = new LinkedList<>();
-        final Deque<T> nodes;
-        final Graph<T> graph;
-        TopoSorter(Graph<T> graph) {
-            this.graph = graph;
-            this.nodes = new LinkedList<>(graph.nodes);
-            sort();
-        }
-
-        public void ordered(Consumer<T> action) {
-            result.iterator().forEachRemaining(action);
-        }
-
-        public void reverse(Consumer<T> action) {
-            result.descendingIterator().forEachRemaining(action);
-        }
-
-        private void sort() {
-            Deque<T> visited = new LinkedList<>();
-            Deque<T> done = new LinkedList<>();
-            T node;
-            while ((node = nodes.poll()) != null) {
-                if (!visited.contains(node)) {
-                    visit(node, visited, done);
-                }
-            }
-        }
-
-        private void visit(T node, Deque<T> visited, Deque<T> done) {
-            if (visited.contains(node)) {
-                if (!done.contains(node)) {
-                    throw new IllegalArgumentException("Cyclic detected: " +
-                            node + " " + graph.edges().get(node));
-                }
-                return;
-            }
-            visited.add(node);
-            graph.edges().get(node).stream()
-                 .forEach(x -> visit(x, visited, done));
-            done.add(node);
-            result.addLast(node);
-        }
-    }
-
-    static class DotGraph {
-        static final String ORANGE = "#e76f00";
-        static final String BLUE = "#437291";
-        static final String GRAY = "#dddddd";
-
-        static final String REEXPORTS = "";
-        static final String REQUIRES = "style=\"dashed\"";
-        static final String REQUIRES_BASE = "color=\"" + GRAY + "\"";
-
-        static final Set<String> javaModules = modules(name ->
-                (name.startsWith("java.") && !name.equals("java.smartcardio")));
-        static final Set<String> jdkModules = modules(name ->
-                (name.startsWith("java.") ||
-                        name.startsWith("jdk.") ||
-                        name.startsWith("javafx.")) && !javaModules.contains(name));
-
-        private static Set<String> modules(Predicate<String> predicate) {
-            return ModuleFinder.ofSystem().findAll()
-                               .stream()
-                               .map(ModuleReference::descriptor)
-                               .map(ModuleDescriptor::name)
-                               .filter(predicate)
-                               .collect(Collectors.toSet());
-        }
-
-        static void printAttributes(PrintStream out) {
-            out.format("  size=\"25,25\";%n");
-            out.format("  nodesep=.5;%n");
-            out.format("  ranksep=1.5;%n");
-            out.format("  pencolor=transparent;%n");
-            out.format("  node [shape=plaintext, fontname=\"DejaVuSans\", fontsize=36, margin=\".2,.2\"];%n");
-            out.format("  edge [penwidth=4, color=\"#999999\", arrowhead=open, arrowsize=2];%n");
-        }
-
-        static void printNodes(PrintStream out, Graph<String> graph) {
-            out.format("  subgraph se {%n");
-            graph.nodes().stream()
-                 .filter(javaModules::contains)
-                 .forEach(mn -> out.format("  \"%s\" [fontcolor=\"%s\", group=%s];%n",
-                                           mn, ORANGE, "java"));
-            out.format("  }%n");
-            graph.nodes().stream()
-                 .filter(jdkModules::contains)
-                 .forEach(mn -> out.format("    \"%s\" [fontcolor=\"%s\", group=%s];%n",
-                                              mn, BLUE, "jdk"));
-
-            graph.nodes().stream()
-                    .filter(mn -> !javaModules.contains(mn) && !jdkModules.contains(mn))
-                    .forEach(mn -> out.format("  \"%s\";%n", mn));
-        }
-
-        static void printEdges(PrintStream out, Graph<String> graph,
-                               String node, Set<String> requiresPublic) {
-            graph.adjacentNodes(node).forEach(dn -> {
-                String attr = dn.equals("java.base") ? REQUIRES_BASE
-                        : (requiresPublic.contains(dn) ? REEXPORTS : REQUIRES);
-                out.format("  \"%s\" -> \"%s\" [%s];%n", node, dn, attr);
-            });
-        }
-    }
-
-    public void genDotFile(Path dir) throws IOException {
-        String name = root.name();
-        try (PrintStream out
-                     = new PrintStream(Files.newOutputStream(dir.resolve(name + ".dot")))) {
-            Configuration cf = modulePaths.configuration(name);
+    private void genDotFile(Path dir, String name) throws IOException {
+        try (OutputStream os = Files.newOutputStream(dir.resolve(name + ".dot"));
+             PrintWriter out = new PrintWriter(os)) {
+            Set<Module> modules = configuration.resolve(Set.of(name))
+                .collect(Collectors.toSet());
 
             // transitive reduction
-            Graph<String> graph = gengraph(cf);
+            Graph<String> graph = gengraph(modules);
 
             out.format("digraph \"%s\" {%n", name);
             DotGraph.printAttributes(out);
             DotGraph.printNodes(out, graph);
 
-            cf.modules().stream()
-                    .map(ResolvedModule::reference)
-                    .map(ModuleReference::descriptor)
-                    .sorted(Comparator.comparing(ModuleDescriptor::name))
-                    .forEach(md -> {
-                String mn = md.name();
-                Set<String> requiresPublic = md.requires().stream()
+            modules.stream()
+                .map(Module::descriptor)
+                .sorted(Comparator.comparing(ModuleDescriptor::name))
+                .forEach(md -> {
+                    String mn = md.name();
+                    Set<String> requiresPublic = md.requires().stream()
                         .filter(d -> d.modifiers().contains(PUBLIC))
                         .map(d -> d.name())
-                        .collect(Collectors.toSet());
+                        .collect(toSet());
 
-                DotGraph.printEdges(out, graph, mn, requiresPublic);
-            });
+                    DotGraph.printEdges(out, graph, mn, requiresPublic);
+                });
 
             out.println("}");
         }
     }
 
-
     /**
      * Returns a Graph of the given Configuration after transitive reduction.
      *
@@ -675,12 +441,12 @@
      * (e.g. U -> V) from being reduced by a path (U -> X -> Y -> V)
      * in which  V would not be re-exported from U.
      */
-    private Graph<String> gengraph(Configuration cf) {
+    private Graph<String> gengraph(Set<Module> modules) {
         // build a Graph containing only requires public edges
         // with transitive reduction.
         Graph.Builder<String> rpgbuilder = new Graph.Builder<>();
-        for (ResolvedModule resolvedModule : cf.modules()) {
-            ModuleDescriptor md = resolvedModule.reference().descriptor();
+        for (Module module : modules) {
+            ModuleDescriptor md = module.descriptor();
             String mn = md.name();
             md.requires().stream()
                     .filter(d -> d.modifiers().contains(PUBLIC))
@@ -692,12 +458,12 @@
 
         // build the readability graph
         Graph.Builder<String> builder = new Graph.Builder<>();
-        for (ResolvedModule resolvedModule : cf.modules()) {
-            ModuleDescriptor md = resolvedModule.reference().descriptor();
+        for (Module module : modules) {
+            ModuleDescriptor md = module.descriptor();
             String mn = md.name();
             builder.addNode(mn);
-            resolvedModule.reads().stream()
-                    .map(ResolvedModule::name)
+            configuration.reads(module)
+                    .map(Module::name)
                     .forEach(d -> builder.addEdge(mn, d));
         }
 
@@ -705,4 +471,25 @@
         return builder.build().reduce(rpg);
     }
 
+    // ---- for testing purpose
+    public ModuleDescriptor[] descriptors(String name) {
+        ModuleDeps moduleDeps = modules.keySet().stream()
+            .filter(m -> m.name().equals(name))
+            .map(modules::get)
+            .findFirst().get();
+
+        ModuleDescriptor[] descriptors = new ModuleDescriptor[3];
+        descriptors[0] = moduleDeps.root.descriptor();
+        descriptors[1] = moduleDeps.descriptor();
+        descriptors[2] = moduleDeps.reduced();
+        return descriptors;
+    }
+
+    public Map<String, Set<String>> unusedQualifiedExports(String name) {
+        ModuleDeps moduleDeps = modules.keySet().stream()
+            .filter(m -> m.name().equals(name))
+            .map(modules::get)
+            .findFirst().get();
+        return moduleDeps.unusedQualifiedExports;
+    }
 }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java	Thu May 19 19:47:04 2016 +0000
@@ -24,15 +24,24 @@
  */
 package com.sun.tools.jdeps;
 
-import static com.sun.tools.jdeps.Analyzer.Type.CLASS;
+import static com.sun.tools.jdeps.JdepsTask.*;
 import static com.sun.tools.jdeps.Analyzer.NOT_FOUND;
-import static com.sun.tools.jdeps.Module.trace;
+import static com.sun.tools.jdeps.JdepsFilter.DEFAULT_FILTER;
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleFinder;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
@@ -40,168 +49,159 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+
 public class ModuleInfoBuilder {
-    final ModulePaths modulePaths;
+    final JdepsConfiguration configuration;
+    final Path outputdir;
+
     final DependencyFinder dependencyFinder;
-    final JdepsFilter filter;
     final Analyzer analyzer;
-    final Map<Module, Module> strictModules = new HashMap<>();
-    ModuleInfoBuilder(ModulePaths modulePaths, DependencyFinder finder) {
-        this.modulePaths = modulePaths;
-        this.dependencyFinder = finder;
-        this.filter = new JdepsFilter.Builder().filter(true, true).build();
-        this.analyzer = new Analyzer(CLASS, filter);
+    final Map<Module, Module> strictModules;
+    public ModuleInfoBuilder(JdepsConfiguration configuration,
+                             List<String> args,
+                             Path outputdir) {
+        this.configuration = configuration;
+        this.outputdir = outputdir;
+
+        this.dependencyFinder = new DependencyFinder(configuration, DEFAULT_FILTER);
+        this.analyzer = new Analyzer(configuration, Analyzer.Type.CLASS, DEFAULT_FILTER);
+
+        // add targets to modulepath if it has module-info.class
+        List<Path> paths = args.stream()
+            .map(fn -> Paths.get(fn))
+            .collect(Collectors.toList());
+
+        // automatic module to convert to strict module
+        this.strictModules = ModuleFinder.of(paths.toArray(new Path[0]))
+                .findAll().stream()
+                .map(configuration::toModule)
+                .collect(Collectors.toMap(Function.identity(), Function.identity()));
+
+        Optional<Module> om = strictModules.keySet().stream()
+                                    .filter(m -> !m.descriptor().isAutomatic())
+                                    .findAny();
+        if (om.isPresent()) {
+            throw new UncheckedBadArgs(new BadArgs("err.genmoduleinfo.not.jarfile",
+                                                   om.get().getPathName()));
+        }
+        if (strictModules.isEmpty()) {
+            throw new UncheckedBadArgs(new BadArgs("err.invalid.path", args));
+        }
     }
 
-    private Stream<Module> automaticModules() {
-        return modulePaths.getModules().values()
-                .stream()
-                .filter(Module::isAutomatic);
+    public boolean run() throws IOException {
+        try {
+            // pass 1: find API dependencies
+            Map<Archive, Set<Archive>> requiresPublic = computeRequiresPublic();
+
+            // pass 2: analyze all class dependences
+            dependencyFinder.parse(automaticModules().stream());
+
+            analyzer.run(automaticModules(), dependencyFinder.locationToArchive());
+
+            // computes requires and requires public
+            automaticModules().forEach(m -> {
+                Map<String, Boolean> requires;
+                if (requiresPublic.containsKey(m)) {
+                    requires = requiresPublic.get(m).stream()
+                        .map(Archive::getModule)
+                        .collect(Collectors.toMap(Module::name, (v) -> Boolean.TRUE));
+                } else {
+                    requires = new HashMap<>();
+                }
+                analyzer.requires(m)
+                    .map(Archive::getModule)
+                    .forEach(d -> requires.putIfAbsent(d.name(), Boolean.FALSE));
+
+                strictModules.put(m, m.toStrictModule(requires));
+            });
+
+            // generate module-info.java
+            descriptors().forEach(md -> writeModuleInfo(outputdir, md));
+
+            // find any missing dependences
+            return automaticModules().stream()
+                        .flatMap(analyzer::requires)
+                        .allMatch(m -> !m.equals(NOT_FOUND));
+        } finally {
+            dependencyFinder.shutdown();
+        }
+    }
+
+    /**
+     * Returns the stream of resulting modules
+     */
+    Stream<Module> modules() {
+        return strictModules.values().stream();
+    }
+
+    /**
+     * Returns the stream of resulting ModuleDescriptors
+     */
+    public Stream<ModuleDescriptor> descriptors() {
+        return strictModules.values().stream().map(Module::descriptor);
+    }
+
+    void visitMissingDeps(Analyzer.Visitor visitor) {
+        automaticModules().stream()
+            .filter(m -> analyzer.requires(m).anyMatch(d -> d.equals(NOT_FOUND)))
+            .forEach(m -> {
+                analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE);
+            });
+    }
+    void writeModuleInfo(Path dir, ModuleDescriptor descriptor) {
+        String mn = descriptor.name();
+        Path srcFile = dir.resolve(mn).resolve("module-info.java");
+        try {
+            Files.createDirectories(srcFile.getParent());
+            System.out.println("writing to " + srcFile);
+            try (PrintWriter pw = new PrintWriter(Files.newOutputStream(srcFile))) {
+                printModuleInfo(pw, descriptor);
+            }
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    private void printModuleInfo(PrintWriter writer, ModuleDescriptor descriptor) {
+        writer.format("module %s {%n", descriptor.name());
+
+        Map<String, Module> modules = configuration.getModules();
+        // first print the JDK modules
+        descriptor.requires().stream()
+                  .filter(req -> !req.name().equals("java.base"))   // implicit requires
+                  .sorted(Comparator.comparing(Requires::name))
+                  .forEach(req -> writer.format("    requires %s;%n", req));
+
+        descriptor.exports().stream()
+                  .peek(exp -> {
+                      if (exp.targets().size() > 0)
+                          throw new InternalError(descriptor.name() + " qualified exports: " + exp);
+                  })
+                  .sorted(Comparator.comparing(Exports::source))
+                  .forEach(exp -> writer.format("    exports %s;%n", exp.source()));
+
+        descriptor.provides().values().stream()
+                    .sorted(Comparator.comparing(Provides::service))
+                    .forEach(p -> p.providers().stream()
+                        .sorted()
+                        .forEach(impl -> writer.format("    provides %s with %s;%n", p.service(), impl)));
+
+        writer.println("}");
+    }
+
+
+    private Set<Module> automaticModules() {
+        return strictModules.keySet();
     }
 
     /**
      * Compute 'requires public' dependences by analyzing API dependencies
      */
-    Map<Module, Set<Module>> computeRequiresPublic() throws IOException {
-        dependencyFinder.findDependencies(filter, true /* api only */, 1);
-        Analyzer pass1 = new Analyzer(Analyzer.Type.CLASS, filter);
+    private Map<Archive, Set<Archive>> computeRequiresPublic() throws IOException {
+        // parse the input modules
+        dependencyFinder.parseExportedAPIs(automaticModules().stream());
 
-        pass1.run(dependencyFinder.archives());
-
-        return automaticModules().collect(Collectors.toMap(Function.identity(),
-                source -> pass1.requires(source)
-                               .map(Archive::getModule)
-                               .collect(Collectors.toSet())));
-    }
-
-    boolean run(Analyzer.Type verbose, boolean quiet) throws IOException {
-        // add all automatic modules to the root set
-        automaticModules().forEach(dependencyFinder::addRoot);
-
-        // pass 1: find API dependencies
-        Map<Module, Set<Module>> requiresPublic = computeRequiresPublic();
-
-        // pass 2: analyze all class dependences
-        dependencyFinder.findDependencies(filter, false /* all classes */, 1);
-        analyzer.run(dependencyFinder.archives());
-
-        // computes requires and requires public
-        automaticModules().forEach(m -> {
-            Map<String, Boolean> requires;
-            if (requiresPublic.containsKey(m)) {
-                requires = requiresPublic.get(m)
-                        .stream()
-                        .collect(Collectors.toMap(Archive::getName, (v) -> Boolean.TRUE));
-            } else {
-                requires = new HashMap<>();
-            }
-            analyzer.requires(m)
-                    .forEach(d -> requires.putIfAbsent(d.getName(), Boolean.FALSE));
-
-            trace("strict module %s requires %s%n", m.name(), requires);
-            strictModules.put(m, m.toStrictModule(requires));
-        });
-
-        // find any missing dependences
-        Optional<Module> missingDeps = automaticModules()
-                .filter(this::missingDep)
-                .findAny();
-        if (missingDeps.isPresent()) {
-            automaticModules()
-                    .filter(this::missingDep)
-                    .forEach(m -> {
-                        System.err.format("Missing dependencies from %s%n", m.name());
-                        analyzer.visitDependences(m,
-                                new Analyzer.Visitor() {
-                                    @Override
-                                    public void visitDependence(String origin, Archive originArchive,
-                                                                String target, Archive targetArchive) {
-                                        if (targetArchive == NOT_FOUND)
-                                            System.err.format("   %-50s -> %-50s %s%n",
-                                                    origin, target, targetArchive.getName());
-                                    }
-                                }, verbose);
-                        System.err.println();
-                    });
-
-            System.err.println("ERROR: missing dependencies (check \"requires NOT_FOUND;\")");
-        }
-        return missingDeps.isPresent() ? false : true;
-    }
-
-    private boolean missingDep(Archive m) {
-        return analyzer.requires(m).filter(a -> a.equals(NOT_FOUND))
-                       .findAny().isPresent();
-    }
-
-    void build(Path dir) throws IOException {
-        ModuleInfoWriter writer = new ModuleInfoWriter(dir);
-        writer.generateOutput(strictModules.values(), analyzer);
-    }
-
-    private class ModuleInfoWriter {
-        private final Path outputDir;
-        ModuleInfoWriter(Path dir) {
-            this.outputDir = dir;
-        }
-
-        void generateOutput(Iterable<Module> modules, Analyzer analyzer) throws IOException {
-            // generate module-info.java file for each archive
-            for (Module m : modules) {
-                if (m.packages().contains("")) {
-                    System.err.format("ERROR: %s contains unnamed package.  " +
-                                      "module-info.java not generated%n", m.getPathName());
-                    continue;
-                }
-
-                String mn = m.getName();
-                Path srcFile = outputDir.resolve(mn).resolve("module-info.java");
-                Files.createDirectories(srcFile.getParent());
-                System.out.println("writing to " + srcFile);
-                try (PrintWriter pw = new PrintWriter(Files.newOutputStream(srcFile))) {
-                    printModuleInfo(pw, m);
-                }
-            }
-        }
-
-        private void printModuleInfo(PrintWriter writer, Module m) {
-            writer.format("module %s {%n", m.name());
-
-            Map<String, Module> modules = modulePaths.getModules();
-            Map<String, Boolean> requires = m.requires();
-            // first print the JDK modules
-            requires.keySet().stream()
-                    .filter(mn -> !mn.equals("java.base"))   // implicit requires
-                    .filter(mn -> modules.containsKey(mn) && modules.get(mn).isJDK())
-                    .sorted()
-                    .forEach(mn -> {
-                        String modifier = requires.get(mn) ? "public " : "";
-                        writer.format("    requires %s%s;%n", modifier, mn);
-                    });
-
-            // print requires non-JDK modules
-            requires.keySet().stream()
-                    .filter(mn -> !modules.containsKey(mn) || !modules.get(mn).isJDK())
-                    .sorted()
-                    .forEach(mn -> {
-                        String modifier = requires.get(mn) ? "public " : "";
-                        writer.format("    requires %s%s;%n", modifier, mn);
-                    });
-
-            m.packages().stream()
-                    .sorted()
-                    .forEach(pn -> writer.format("    exports %s;%n", pn));
-
-            m.provides().entrySet().stream()
-                    .sorted(Map.Entry.comparingByKey())
-                    .forEach(e -> {
-                        String service = e.getKey();
-                        e.getValue().stream()
-                                .sorted()
-                                .forEach(impl -> writer.format("    provides %s with %s;%n", service, impl));
-                    });
-
-            writer.println("}");
-        }
+        return dependencyFinder.dependences();
     }
 }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModulePaths.java	Thu May 19 17:48:04 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2012, 2016, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 com.sun.tools.jdeps;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.lang.module.Configuration;
-import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReference;
-import java.lang.module.ResolvedModule;
-import java.net.URI;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystemNotFoundException;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.ProviderNotFoundException;
-import java.util.*;
-import java.util.stream.Collectors;
-
-import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
-
-public class ModulePaths {
-    final ModuleFinder finder;
-    final Map<String, Module> modules = new LinkedHashMap<>();
-
-    public ModulePaths(String upgradeModulePath, String modulePath) {
-        this(upgradeModulePath, modulePath, Collections.emptyList());
-    }
-
-    public ModulePaths(String upgradeModulePath, String modulePath, List<Path> jars) {
-        ModuleFinder finder = ModuleFinder.ofSystem();
-        if (upgradeModulePath != null) {
-            finder = ModuleFinder.compose(createModulePathFinder(upgradeModulePath), finder);
-        }
-        if (jars.size() > 0) {
-            finder = ModuleFinder.compose(finder, ModuleFinder.of(jars.toArray(new Path[0])));
-        }
-        if (modulePath != null) {
-            finder = ModuleFinder.compose(finder, createModulePathFinder(modulePath));
-        }
-        this.finder = finder;
-
-        // add modules from modulepaths
-        finder.findAll().stream().forEach(mref ->
-            modules.computeIfAbsent(mref.descriptor().name(), mn -> toModule(mn, mref))
-        );
-    }
-
-    /**
-     * Returns the list of Modules that can be found in the specified
-     * module paths.
-     */
-    Map<String, Module> getModules() {
-        return modules;
-    }
-
-    Set<Module> dependences(String... roots) {
-        Configuration cf = configuration(roots);
-        return cf.modules().stream()
-                .map(ResolvedModule::name)
-                .map(modules::get)
-                .collect(Collectors.toSet());
-    }
-
-    Configuration configuration(String... roots) {
-        return Configuration.empty().resolveRequires(finder, ModuleFinder.empty(), Set.of(roots));
-    }
-
-    private static ModuleFinder createModulePathFinder(String mpaths) {
-        if (mpaths == null) {
-            return null;
-        } else {
-            String[] dirs = mpaths.split(File.pathSeparator);
-            Path[] paths = new Path[dirs.length];
-            int i = 0;
-            for (String dir : dirs) {
-                paths[i++] = Paths.get(dir);
-            }
-            return ModuleFinder.of(paths);
-        }
-    }
-
-    private static Module toModule(String mn, ModuleReference mref) {
-        return SystemModulePath.find(mn)
-                               .orElse(toModule(new Module.Builder(mn), mref));
-    }
-
-    private static Module toModule(Module.Builder builder, ModuleReference mref) {
-        ModuleDescriptor md = mref.descriptor();
-        builder.descriptor(md);
-        for (ModuleDescriptor.Requires req : md.requires()) {
-            builder.require(req.name(), req.modifiers().contains(PUBLIC));
-        }
-        for (ModuleDescriptor.Exports exp : md.exports()) {
-            builder.export(exp.source(), exp.targets());
-        }
-        builder.packages(md.packages());
-
-        try {
-            URI location = mref.location()
-                               .orElseThrow(FileNotFoundException::new);
-            builder.location(location);
-            builder.classes(getClassReader(location, md.name()));
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
-        }
-        return builder.build();
-    }
-
-    static class SystemModulePath {
-        final static Module JAVA_BASE;
-
-        private final static FileSystem fs;
-        private final static Path root;
-        private final static Map<String, Module> installed = new HashMap<>();
-        static {
-            if (isJrtAvailable()) {
-                // jrt file system
-                fs = FileSystems.getFileSystem(URI.create("jrt:/"));
-                root = fs.getPath("/modules");
-            } else {
-                // exploded image
-                String javahome = System.getProperty("java.home");
-                fs = FileSystems.getDefault();
-                root = Paths.get(javahome, "modules");
-            }
-
-            ModuleFinder.ofSystem().findAll().stream()
-                 .forEach(mref ->
-                     installed.computeIfAbsent(mref.descriptor().name(),
-                                               mn -> toModule(new Module.Builder(mn, true), mref))
-                 );
-            JAVA_BASE = installed.get("java.base");
-
-            Profile.init(installed);
-        }
-
-        private static boolean isJrtAvailable() {
-            try {
-                FileSystems.getFileSystem(URI.create("jrt:/"));
-                return true;
-            } catch (ProviderNotFoundException | FileSystemNotFoundException e) {
-                return false;
-            }
-        }
-
-        public static Optional<Module> find(String mn) {
-            return installed.containsKey(mn) ? Optional.of(installed.get(mn))
-                                             : Optional.empty();
-        }
-
-        public static boolean contains(Module m) {
-            return installed.containsValue(m);
-        }
-
-        public static ClassFileReader getClassReader(String modulename) throws IOException {
-            Path mp = root.resolve(modulename);
-            if (Files.exists(mp) && Files.isDirectory(mp)) {
-                return ClassFileReader.newInstance(fs, mp);
-            } else {
-                throw new FileNotFoundException(mp.toString());
-            }
-        }
-    }
-
-    /**
-     * Returns a ModuleClassReader that only reads classes for the given modulename.
-     */
-    public static ClassFileReader getClassReader(URI location, String modulename)
-            throws IOException {
-        if (location.getScheme().equals("jrt")) {
-            return SystemModulePath.getClassReader(modulename);
-        } else {
-            Path path = Paths.get(location);
-            return ClassFileReader.newInstance(path);
-        }
-    }
-}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java	Thu May 19 19:47:04 2016 +0000
@@ -26,9 +26,13 @@
 package com.sun.tools.jdeps;
 
 import java.io.IOException;
+import java.lang.module.ModuleDescriptor;
+import java.util.Arrays;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 
 /**
@@ -44,17 +48,18 @@
     // need a way to determine JRE modules
     SE_JRE("Java SE JRE", 4, "java.se", "jdk.charsets",
                             "jdk.crypto.ec", "jdk.crypto.pkcs11",
-                            "jdk.crypto.mscapi", "jdk.crypto.ucrypto", "jdk.jvmstat",
+                            "jdk.crypto.mscapi", "jdk.crypto.ucrypto",
                             "jdk.localedata", "jdk.scripting.nashorn", "jdk.zipfs"),
     FULL_JRE("Full JRE", 5, "java.se.ee", "jdk.charsets",
                             "jdk.crypto.ec", "jdk.crypto.pkcs11",
                             "jdk.crypto.mscapi", "jdk.crypto.ucrypto", "jdk.jvmstat",
-                            "jdk.localedata", "jdk.scripting.nashorn", "jdk.zipfs");
+                            "jdk.localedata", "jdk.scripting.nashorn",
+                            "jdk.unsupported", "jdk.zipfs");
 
     final String name;
     final int profile;
     final String[] mnames;
-    final Set<Module> modules = new HashSet<>();
+    final Map<String, Module> modules = new HashMap<>();
 
     Profile(String name, int profile, String... mnames) {
         this.name = name;
@@ -75,12 +80,18 @@
         return JDK.isEmpty() ? 0 : Profile.values().length;
     }
 
+    Optional<Module> findModule(String name) {
+        return modules.containsKey(name)
+            ? Optional.of(modules.get(name))
+            : Optional.empty();
+    }
+
     /**
      * Returns the Profile for the given package name; null if not found.
      */
     public static Profile getProfile(String pn) {
         for (Profile p : Profile.values()) {
-            for (Module m : p.modules) {
+            for (Module m : p.modules.values()) {
                 if (m.packages().contains(pn)) {
                     return p;
                 }
@@ -94,7 +105,7 @@
      */
     public static Profile getProfile(Module m) {
         for (Profile p : Profile.values()) {
-            if (p.modules.contains(m)) {
+            if (p.modules.containsValue(m)) {
                 return p;
             }
         }
@@ -102,34 +113,28 @@
     }
 
     private final static Set<Module> JDK = new HashSet<>();
-    static synchronized void init(Map<String, Module> installed) {
-        for (Profile p : Profile.values()) {
-            for (String mn : p.mnames) {
-                // this includes platform-dependent module that may not exist
-                Module m = installed.get(mn);
-                if (m != null) {
-                    p.addModule(installed, m);
-                }
-            }
-        }
+    static synchronized void init(Map<String, Module> systemModules) {
+        Arrays.stream(Profile.values()).forEach(p ->
+            // this includes platform-dependent module that may not exist
+            Arrays.stream(p.mnames)
+                  .filter(systemModules::containsKey)
+                  .map(systemModules::get)
+                  .forEach(m -> p.addModule(systemModules, m)));
 
         // JDK modules should include full JRE plus other jdk.* modules
         // Just include all installed modules.  Assume jdeps is running
         // in JDK image
-        JDK.addAll(installed.values());
+        JDK.addAll(systemModules.values());
     }
 
-    private void addModule(Map<String, Module> installed, Module m) {
-        modules.add(m);
-        for (String n : m.requires().keySet()) {
-            Module d = installed.get(n);
-            if (d == null) {
-                throw new InternalError("module " + n + " required by " +
-                        m.name() + " doesn't exist");
-            }
-            modules.add(d);
-        }
+    private void addModule(Map<String, Module> systemModules, Module module) {
+        modules.put(module.name(), module);
+        module.descriptor().requires().stream()
+              .map(ModuleDescriptor.Requires::name)
+              .map(systemModules::get)
+              .forEach(m -> modules.put(m.name(), m));
     }
+
     // for debugging
     public static void main(String[] args) throws IOException {
         // find platform modules
@@ -139,14 +144,6 @@
         for (Profile p : Profile.values()) {
             String profileName = p.name;
             System.out.format("%2d: %-10s  %s%n", p.profile, profileName, p.modules);
-            for (Module m: p.modules) {
-                System.out.format("module %s%n", m.name());
-                System.out.format("   requires %s%n", m.requires());
-                for (Map.Entry<String,Set<String>> e: m.exports().entrySet()) {
-                    System.out.format("   exports %s %s%n", e.getKey(),
-                        e.getValue().isEmpty() ? "" : "to " + e.getValue());
-                }
-            }
         }
         System.out.println("All JDK modules:-");
         JDK.stream().sorted(Comparator.comparing(Module::name))
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Thu May 19 19:47:04 2016 +0000
@@ -1,12 +1,10 @@
 main.usage.summary=\
-Usage: {0} <options> [-m <module-name> | <classes...>]\n\
+Usage: {0} <options> <path ...>]\n\
 use -h, -? or -help for a list of possible options
 
 main.usage=\
-Usage: {0} <options> [-m <module-name> | <classes...>]\n\
-If -m <module-name> is specified, the specified module will be analyzed\n\
-otherwise, <classes> can be a pathname to a .class file, a directory,\n\
-a JAR file, or a fully-qualified class name.\n\
+Usage: {0} <options> <path ...>]\n\
+<path> can be a pathname to a .class file, a directory, a JAR file.\n\
 \n\
 Possible options include:
 
@@ -14,134 +12,156 @@
 warn.prefix=Warning:
 
 main.opt.h=\
-\  -h -?        -help                   Print this usage message
+\  -h -?        -help                Print this usage message
 
 main.opt.version=\
-\  -version                             Version information
+\  -version                          Version information
 
 main.opt.v=\
-\  -v           -verbose                Print all class level dependencies\n\
-\                                       Equivalent to -verbose:class -filter:none.\n\
-\  -verbose:package                     Print package-level dependencies excluding\n\
-\                                       dependencies within the same package by default\n\
-\  -verbose:class                       Print class-level dependencies excluding\n\
-\                                       dependencies within the same package by default
+\  -v           -verbose             Print all class level dependencies\n\
+\                                    Equivalent to -verbose:class -filter:none.\n\
+\  -verbose:package                  Print package-level dependencies excluding\n\
+\                                    dependencies within the same package by default\n\
+\  -verbose:class                    Print class-level dependencies excluding\n\
+\                                    dependencies within the same package by default
+
+main.opt.s=\
+\  -s           -summary             Print dependency summary only.
 
 main.opt.f=\
-\  -f <regex>  -filter <regex>          Filter dependences matching the given pattern\n\
-\                                       If given multiple times, the last one will be used.\n\
-\  -filter:package                      Filter dependences within the same package (default)\n\
-\  -filter:module                       Filter dependences within the same module\n\
-\  -filter:archive                      Filter dependences within the same archive\n\
-\  -filter:none                         No -filter:package and -filter:archive filtering\n\
-\                                       Filtering specified via the -filter option still applies.
+\  -f <regex>  -filter <regex>       Filter dependences matching the given\n\
+\                                    pattern. If given multiple times, the last\n\
+\                                    one will be used.\n\
+\  -filter:package                   Filter dependences within the same package.\n\
+\                                    This is the default.\n\
+\  -filter:archive                   Filter dependences within the same archive.\n\
+\  -filter:module                    Filter dependences within the same module.\n\
+\  -filter:none                      No -filter:package and -filter:archive\n\
+\                                    filtering.  Filtering specified via the\n\
+\                                    -filter option still applies.\n\
 
-main.opt.s=\
-\  -s           -summary                Print dependency summary only.\n\
-\                                       If -s option is used with -m, the module descriptor of\n\
-\                                       the given module will be read to generate the graph.
-
-main.opt.p=\
-\  -p <pkgname>                         Finds dependences matching the given package name\n\
-\  -package <pkgname>                   (may be given multiple times).
+main.opt.p=\n\
+\Options to filter dependencies:\n\
+\  -p <pkgname> -package <pkgname>   Finds dependences matching the given package\n\
+\                                    name (may be given multiple times).
 
 main.opt.e=\
-\  -e <regex>\n\
-\  -regex <regex>                       Finds dependences matching the given pattern.
+\  -e <regex> -regex <regex>         Finds dependences matching the given pattern.
 
-main.opt.module=\
-\  -module <module-name>                Finds dependences matching the given module name\n\
-\                                       (may be given multiple times).\n\
-\                                       -package, -regex, -requires are mutual exclusive.
+main.opt.requires=\
+\  -requires <module-name>           Finds dependences matching the given module\n\
+\                                    name (may be given multiple times).\n\
+\                                    -package, -regex, -requires are mutual exclusive.
 
-main.opt.include=\
-\  -include <regex>                     Restrict analysis to classes matching pattern\n\
-\                                       This option filters the list of classes to\n\
-\                                       be analyzed.  It can be used together with\n\
-\                                       -p and -e which apply pattern to the dependences
+main.opt.include=\n\
+ \Options to filter classes to be analyzed:\n\
+\  -include <regex>                  Restrict analysis to classes matching pattern\n\
+\                                    This option filters the list of classes to\n\
+\                                    be analyzed.  It can be used together with\n\
+\                                    -p and -e which apply pattern to the dependences
 
 main.opt.P=\
-\  -P           -profile                Show profile containing a package
-
-main.opt.M=\
-\  -M                                   Show module containing a package
+\  -P           -profile             Show profile containing a package
 
 main.opt.cp=\
-\  -cp <path>   -classpath <path>       Specify where to find class files
+\  -cp <path>   -classpath <path>    Specify where to find class files
 
 main.opt.mp=\
 \  -mp <module path>...\n\
-\  -modulepath <module path>...         Specify module path
+\  -modulepath <module path>...      Specify module path
 
 main.opt.upgrademodulepath=\
 \  -upgrademodulepath <module path>...  Specify upgrade module path
 
+main.opt.system=\
+\  -system <java-home>               Specify an alternate system module path
+
+main.opt.addmods=\
+\  -addmods <module-name>[,<module-name>...]\n\
+\                                    Adds modules to the root set for analysis
+
 main.opt.m=\
-\  -m <module-name>                     Specify the name of the module and its transitive\n\
-\                                       dependences to be analyzed.
+\  -m <module-name>                  Specify the root module for analysis
 
 main.opt.R=\
-\  -R           -recursive              Recursively traverse all run-time dependencies.\n\
-\                                       The -R option implies -filter:none.  If -p, -e, -f\n\
-\                                       option is specified, only the matching dependences\n\
-\                                       are analyzed.
+\  -R           -recursive           Recursively traverse all run-time dependencies.\n\
+\                                    The -R option implies -filter:none.  If -p,\n\
+\                                    -e, -foption is specified, only the matching\n\
+\                                    dependences are analyzed.
+
+main.opt.I=\
+\  -I           -inverse             Analyzes the dependences per other given options\n\
+\                                    and then find all artifacts that directly\n\
+\                                    and indirectly depend on the matching nodes.\n\
+\                                    This is equivalent to the inverse of\n\
+\                                    compile-time view analysis and print\n\
+\                                    dependency summary.  This option must use\n\
+\                                    with -requires, -package or -regex option.
 
 main.opt.ct=\
-\  -ct          -compile-time           Compile-time view of transitive dependencies\n\
-\                                       i.e. compile-time view of -R option.  If a dependence\n\
-\                                       is found from a directory, a JAR file or a module,\n\
-\                                       all class files in that containing archive are analyzed.
+\  -ct          -compile-time        Compile-time view of transitive dependencies\n\
+\                                    i.e. compile-time view of -R option.\n\
+\                                    Analyzes the dependences per other given options\n\
+\                                    If a dependence is found from a directory,\n\
+\                                    a JAR file or a module, all classes in that \n\
+\                                    containing archive are analyzed.
 
 main.opt.apionly=\
-\  -apionly                             Restrict analysis to APIs i.e. dependences\n\
-\                                       from the signature of public and protected\n\
-\                                       members of public classes including field\n\
-\                                       type, method parameter types, returned type,\n\
-\                                       checked exception types etc
+\  -apionly                          Restrict analysis to APIs i.e. dependences\n\
+\                                    from the signature of public and protected\n\
+\                                    members of public classes including field\n\
+\                                    type, method parameter types, returned type,\n\
+\                                    checked exception types etc.
 
 main.opt.genmoduleinfo=\
-\  -genmoduleinfo <dir>                 Generate module-info.java under the specified directory.\n\
-\                                       The specified JAR files will be analyzed.\n\
-\                                       This option cannot be used with -dotoutput or -cp.
+\  -genmoduleinfo <dir>              Generate module-info.java under the specified\n\
+\                                    directory. The specified JAR files will be\n\
+\                                    analyzed. This option cannot be used with\n\
+\                                    -dotoutput or -cp.
 
 main.opt.check=\
-\  -check                               Analyze the dependence of a given module specified via\n\
-\                                       -m option.  It prints out the resulting module dependency\n\
-\                                       graph after transition reduction and also identifies any\n\
-\                                       unused qualified exports.
+\  -check <module-name>[,<module-name>...\n\
+\                                    Analyze the dependence of the specified modules\n\
+\                                    It prints the module descriptor, the resulting\n\
+\                                    module dependences after analysis and the\n\
+\                                    graph after transition reduction.  It also\n\
+\                                    identifies any unused qualified exports.
 
 
 main.opt.dotoutput=\
-\  -dotoutput <dir>                     Destination directory for DOT file output
+\  -dotoutput <dir>                  Destination directory for DOT file output
 
 main.opt.jdkinternals=\
-\  -jdkinternals                        Finds class-level dependences on JDK internal APIs.\n\
-\                                       By default, it analyzes all classes on -classpath\n\
-\                                       and input files unless -include option is specified.\n\
-\                                       This option cannot be used with -p, -e and -s options.\n\
-\                                       WARNING: JDK internal APIs may not be accessible in\n\
-\                                       the next release.
+\  -jdkinternals                     Finds class-level dependences on JDK internal\n\
+\                                    APIs. By default, it analyzes all classes\n\
+\                                    on -classpath and input files unless -include\n\
+\                                    option is specified. This option cannot be\n\
+\                                    used with -p, -e and -s options.\n\
+\                                    WARNING: JDK internal APIs are inaccessible.
 
 main.opt.depth=\
-\  -depth=<depth>                       Specify the depth of the transitive\n\
-\                                       dependency analysis
+\  -depth=<depth>                    Specify the depth of the transitive\n\
+\                                    dependency analysis
 
 main.opt.q=\
-\  -q           -quiet                  Do not show missing dependencies from -genmoduleinfo output.
+\  -q           -quiet               Do not show missing dependencies from \n\
+\                                    -genmoduleinfo output.
 
 err.unknown.option=unknown option: {0}
 err.missing.arg=no value given for {0}
 err.invalid.arg.for.option=invalid argument for option: {0}
 err.option.after.class=option must be specified before classes: {0}
-err.genmoduleinfo.not.jarfile={0} not valid for -genmoduleinfo option (must be JAR file)
+err.genmoduleinfo.not.jarfile={0} not valid for -genmoduleinfo option (must be non-modular JAR file)
 err.profiles.msg=No profile information
 err.exception.message={0}
 err.invalid.path=invalid path: {0}
-err.invalid.module.option=-m {0} is set but {1} is specified.
+err.invalid.module.option=Cannot set {0} with {1} option.
 err.invalid.filters=Only one of -package (-p), -regex (-e), -requires option can be set
 err.module.not.found=module not found: {0}
-err.root.module.not.set=-m is not set
-warn.invalid.arg=Invalid classname or pathname not exist: {0}
+err.root.module.not.set=root module set empty
+err.invalid.inverse.option={0} cannot be used with -inverse option
+err.inverse.filter.not.set={0} cannot be used with -inverse option
+warn.invalid.arg=Path not exist: {0}
 warn.split.package=package {0} defined in {1} {2}
 warn.replace.useJDKInternals=\
 JDK internal APIs are unsupported and private to JDK implementation that are\n\
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdkinternals.properties	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdkinternals.properties	Thu May 19 19:47:04 2016 +0000
@@ -1,6 +1,5 @@
-// No translation needed
+# No translation needed
 com.sun.crypto.provider.SunJCE=Use java.security.Security.getProvider(provider-name) @since 1.3
-com.sun.image.codec=Use javax.imageio @since 1.4
 com.sun.org.apache.xml.internal.security=Use java.xml.crypto @since 1.6
 com.sun.org.apache.xml.internal.security.utils.Base64=Use java.util.Base64 @since 1.8
 com.sun.org.apache.xml.internal.resolver=Use javax.xml.catalog @since 9
@@ -9,17 +8,34 @@
 com.sun.rowset=Use javax.sql.rowset.RowSetProvider @since 1.7
 com.sun.tools.javac.tree=Use com.sun.source @since 1.6
 com.sun.tools.javac=Use javax.tools and javax.lang.model @since 1.6
+java.awt.peer=Should not use. See https://bugs.openjdk.java.net/browse/JDK-8037739
+java.awt.dnd.peer=Should not use. See https://bugs.openjdk.java.net/browse/JDK-8037739
+jdk.internal.ref.Cleaner=Use java.lang.ref.PhantomReference @since 1.2 or java.lang.ref.Cleaner @since 9
 sun.awt.image.codec=Use javax.imageio @since 1.4
-sun.misc.BASE64Encoder=Use java.util.Base64 @since 1.8
-sun.misc.BASE64Decoder=Use java.util.Base64 @since 1.8
-sun.misc.Cleaner=Use java.lang.ref.PhantomReference @since 1.2 or java.lang.ref.Cleaner @since 9
-sun.misc.Service=Use java.util.ServiceLoader @since 1.6
+sun.awt.CausedFocusEvent=Use java.awt.event.FocusEvent::getCause @since 9
+sun.font.FontUtilities=See java.awt.Font.textRequiresLayout	@since 9
+sun.reflect.Reflection=See StackWalker API @since 9
+sun.reflect.ReflectionFactory=See http://openjdk.java.net/jeps/260
+sun.misc.Unsafe=See http://openjdk.java.net/jeps/260
+sun.misc.Signal=See http://openjdk.java.net/jeps/260
+sun.misc.SignalHandler=See http://openjdk.java.net/jeps/260
 sun.security.action=Use java.security.PrivilegedAction @since 1.1
 sun.security.krb5=Use com.sun.security.jgss
 sun.security.provider.PolicyFile=Use java.security.Policy.getInstance("JavaPolicy", new URIParameter(uri)) @since 1.6
 sun.security.provider.Sun=Use java.security.Security.getProvider(provider-name) @since 1.3
 sun.security.util.SecurityConstants=Use appropriate java.security.Permission subclass @since 1.1
 sun.security.x509.X500Name=Use javax.security.auth.x500.X500Principal @since 1.4
-sun.tools.jar=Use java.util.jar or jar tool @since 1.2
-jdk.internal.ref.Cleaner=Use java.lang.ref.PhantomReference @since 1.2 or java.lang.ref.Cleaner @since 9
+sun.tools.jar=Use java.util.jar or jar tool @since 1.2\
+# Internal APIs removed in JDK 9
+com.apple.eawt=Use java.awt.desktop and JEP 272 @since 9
+com.apple.concurrent=Removed. See https://bugs.openjdk.java.net/browse/JDK-8148187
+com.sun.image.codec=Use javax.imageio @since 1.4
+sun.misc.BASE64Encoder=Use java.util.Base64 @since 1.8
+sun.misc.BASE64Decoder=Use java.util.Base64 @since 1.8
+sun.misc.Cleaner=Use java.lang.ref.PhantomReference @since 1.2 or java.lang.ref.Cleaner @since 9
+sun.misc.Service=Use java.util.ServiceLoader @since 1.6
+sun.misc=Removed. See http://openjdk.java.net/jeps/260
+sun.reflect=Removed. See http://openjdk.java.net/jeps/260
 
+
+
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Thu May 19 19:47:04 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -25,7 +25,6 @@
 
 package jdk.internal.jshell.tool;
 
-import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
 import jdk.jshell.SourceCodeAnalysis.QualifiedNames;
 import jdk.jshell.SourceCodeAnalysis.Suggestion;
 
@@ -36,6 +35,7 @@
 import java.io.UncheckedIOException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -44,6 +44,9 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Supplier;
+import java.util.prefs.BackingStoreException;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import jdk.internal.jline.NoInterruptUnixTerminal;
 import jdk.internal.jline.Terminal;
@@ -54,10 +57,13 @@
 import jdk.internal.jline.console.KeyMap;
 import jdk.internal.jline.console.UserInterruptException;
 import jdk.internal.jline.console.completer.Completer;
+import jdk.internal.jline.extra.EditingHistory;
 import jdk.internal.jshell.tool.StopDetectingInputStream.State;
 
 class ConsoleIOContext extends IOContext {
 
+    private static final String HISTORY_LINE_PREFIX = "HISTORY_LINE_";
+
     final JShellTool repl;
     final StopDetectingInputStream input;
     final ConsoleReader in;
@@ -80,9 +86,14 @@
         in = new ConsoleReader(cmdin, cmdout, term);
         in.setExpandEvents(false);
         in.setHandleUserInterrupt(true);
-        in.setHistory(history = new EditingHistory(repl.prefs) {
-            @Override protected CompletionInfo analyzeCompletion(String input) {
-                return repl.analysis.analyzeCompletion(input);
+        List<String> persistenHistory = Stream.of(repl.prefs.keys())
+                                              .filter(key -> key.startsWith(HISTORY_LINE_PREFIX))
+                                              .sorted()
+                                              .map(key -> repl.prefs.get(key, null))
+                                              .collect(Collectors.toList());
+        in.setHistory(history = new EditingHistory(in, persistenHistory) {
+            @Override protected boolean isComplete(CharSequence input) {
+                return repl.analysis.analyzeCompletion(input.toString()).completeness.isComplete;
             }
         });
         in.setBellEnabled(true);
@@ -150,8 +161,6 @@
             }
         });
         bind(DOCUMENTATION_SHORTCUT, (ActionListener) evt -> documentation(repl));
-        bind(CTRL_UP, (ActionListener) evt -> moveHistoryToSnippet(((EditingHistory) in.getHistory())::previousSnippet));
-        bind(CTRL_DOWN, (ActionListener) evt -> moveHistoryToSnippet(((EditingHistory) in.getHistory())::nextSnippet));
         for (FixComputer computer : FIX_COMPUTERS) {
             for (String shortcuts : SHORTCUT_FIXES) {
                 bind(shortcuts + computer.shortcut, (ActionListener) evt -> fixes(computer));
@@ -181,7 +190,24 @@
 
     @Override
     public void close() throws IOException {
-        history.save();
+        //save history:
+        try {
+            for (String key : repl.prefs.keys()) {
+                if (key.startsWith(HISTORY_LINE_PREFIX))
+                    repl.prefs.remove(key);
+            }
+            Collection<? extends String> savedHistory = history.save();
+            if (!savedHistory.isEmpty()) {
+                int len = (int) Math.ceil(Math.log10(savedHistory.size()+1));
+                String format = HISTORY_LINE_PREFIX + "%0" + len + "d";
+                int index = 0;
+                for (String historyLine : savedHistory) {
+                    repl.prefs.put(String.format(format, index++), historyLine);
+                }
+            }
+        } catch (BackingStoreException ex) {
+            throw new IllegalStateException(ex);
+        }
         in.shutdown();
         try {
             in.getTerminal().restore();
@@ -190,30 +216,6 @@
         }
     }
 
-    private void moveHistoryToSnippet(Supplier<Boolean> action) {
-        if (!action.get()) {
-            try {
-                in.beep();
-            } catch (IOException ex) {
-                throw new IllegalStateException(ex);
-            }
-        } else {
-            try {
-                //could use:
-                //in.resetPromptLine(in.getPrompt(), in.getHistory().current().toString(), -1);
-                //but that would mean more re-writing on the screen, (and prints an additional
-                //empty line), so using setBuffer directly:
-                Method setBuffer = in.getClass().getDeclaredMethod("setBuffer", String.class);
-
-                setBuffer.setAccessible(true);
-                setBuffer.invoke(in, in.getHistory().current().toString());
-                in.flush();
-            } catch (ReflectiveOperationException | IOException ex) {
-                throw new IllegalStateException(ex);
-            }
-        }
-    }
-
     private void bind(String shortcut, Object action) {
         KeyMap km = in.getKeys();
         for (int i = 0; i < shortcut.length(); i++) {
@@ -227,8 +229,6 @@
     }
 
     private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
-    private static final String CTRL_UP = "\033\133\061\073\065\101"; //Ctrl-UP
-    private static final String CTRL_DOWN = "\033\133\061\073\065\102"; //Ctrl-DOWN
     private static final String[] SHORTCUT_FIXES = {
         "\033\015", //Alt-Enter (Linux)
         "\033\133\061\067\176", //F6/Alt-F1 (Mac)
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditingHistory.java	Thu May 19 17:48:04 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,382 +0,0 @@
-/*
- * Copyright (c) 2015, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 jdk.internal.jshell.tool;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Set;
-import java.util.prefs.BackingStoreException;
-import java.util.prefs.Preferences;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import jdk.internal.jline.console.history.History;
-import jdk.internal.jline.console.history.History.Entry;
-import jdk.internal.jline.console.history.MemoryHistory;
-import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
-
-/*Public for tests (HistoryTest).
- */
-public abstract class EditingHistory implements History {
-
-    private final Preferences prefs;
-    private final History fullHistory;
-    private History currentDelegate;
-
-    protected EditingHistory(Preferences prefs) {
-        this.prefs = prefs;
-        this.fullHistory = new MemoryHistory();
-        this.currentDelegate = fullHistory;
-        load();
-    }
-
-    @Override
-    public int size() {
-        return currentDelegate.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-        return currentDelegate.isEmpty();
-    }
-
-    @Override
-    public int index() {
-        return currentDelegate.index();
-    }
-
-    @Override
-    public void clear() {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        currentDelegate.clear();
-    }
-
-    @Override
-    public CharSequence get(int index) {
-        return currentDelegate.get(index);
-    }
-
-    @Override
-    public void add(CharSequence line) {
-        NarrowingHistoryLine currentLine = null;
-        int origIndex = fullHistory.index();
-        int fullSize;
-        try {
-            fullHistory.moveToEnd();
-            fullSize = fullHistory.index();
-            if (currentDelegate == fullHistory) {
-                if (origIndex < fullHistory.index()) {
-                    for (Entry entry : fullHistory) {
-                        if (!(entry.value() instanceof NarrowingHistoryLine))
-                            continue;
-                        int[] cluster = ((NarrowingHistoryLine) entry.value()).span;
-                        if (cluster[0] == origIndex && cluster[1] > cluster[0]) {
-                            currentDelegate = new MemoryHistory();
-                            for (int i = cluster[0]; i <= cluster[1]; i++) {
-                                currentDelegate.add(fullHistory.get(i));
-                            }
-                        }
-                    }
-                }
-            }
-            fullHistory.moveToEnd();
-            while (fullHistory.previous()) {
-                CharSequence c = fullHistory.current();
-                if (c instanceof NarrowingHistoryLine) {
-                    currentLine = (NarrowingHistoryLine) c;
-                    break;
-                }
-            }
-        } finally {
-            fullHistory.moveTo(origIndex);
-        }
-        if (currentLine == null || currentLine.span[1] != (-1)) {
-            line = currentLine = new NarrowingHistoryLine(line, fullSize);
-        }
-        StringBuilder complete = new StringBuilder();
-        for (int i = currentLine.span[0]; i < fullSize; i++) {
-            complete.append(fullHistory.get(i));
-        }
-        complete.append(line);
-        if (analyzeCompletion(complete.toString()).completeness.isComplete) {
-            currentLine.span[1] = fullSize; //TODO: +1?
-            currentDelegate = fullHistory;
-        }
-        fullHistory.add(line);
-    }
-
-    protected abstract CompletionInfo analyzeCompletion(String input);
-
-    @Override
-    public void set(int index, CharSequence item) {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        currentDelegate.set(index, item);
-    }
-
-    @Override
-    public CharSequence remove(int i) {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        return currentDelegate.remove(i);
-    }
-
-    @Override
-    public CharSequence removeFirst() {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        return currentDelegate.removeFirst();
-    }
-
-    @Override
-    public CharSequence removeLast() {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        return currentDelegate.removeLast();
-    }
-
-    @Override
-    public void replace(CharSequence item) {
-        if (currentDelegate != fullHistory)
-            throw new IllegalStateException("narrowed");
-        currentDelegate.replace(item);
-    }
-
-    @Override
-    public ListIterator<Entry> entries(int index) {
-        return currentDelegate.entries(index);
-    }
-
-    @Override
-    public ListIterator<Entry> entries() {
-        return currentDelegate.entries();
-    }
-
-    @Override
-    public Iterator<Entry> iterator() {
-        return currentDelegate.iterator();
-    }
-
-    @Override
-    public CharSequence current() {
-        return currentDelegate.current();
-    }
-
-    @Override
-    public boolean previous() {
-        return currentDelegate.previous();
-    }
-
-    @Override
-    public boolean next() {
-        return currentDelegate.next();
-    }
-
-    @Override
-    public boolean moveToFirst() {
-        return currentDelegate.moveToFirst();
-    }
-
-    @Override
-    public boolean moveToLast() {
-        return currentDelegate.moveToLast();
-    }
-
-    @Override
-    public boolean moveTo(int index) {
-        return currentDelegate.moveTo(index);
-    }
-
-    @Override
-    public void moveToEnd() {
-        currentDelegate.moveToEnd();
-    }
-
-    public boolean previousSnippet() {
-        for (int i = index() - 1; i >= 0; i--) {
-            if (get(i) instanceof NarrowingHistoryLine) {
-                moveTo(i);
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    public boolean nextSnippet() {
-        for (int i = index() + 1; i < size(); i++) {
-            if (get(i) instanceof NarrowingHistoryLine) {
-                moveTo(i);
-                return true;
-            }
-        }
-
-        if (index() < size()) {
-            moveToEnd();
-            return true;
-        }
-
-        return false;
-    }
-
-    private static final String HISTORY_LINE_PREFIX = "HISTORY_LINE_";
-    private static final String HISTORY_SNIPPET_START = "HISTORY_SNIPPET";
-
-    public final void load() {
-        try {
-            Set<Integer> snippetsStart = new HashSet<>();
-            for (String start : prefs.get(HISTORY_SNIPPET_START, "").split(";")) {
-                if (!start.isEmpty())
-                    snippetsStart.add(Integer.parseInt(start));
-            }
-            List<String> keys = Stream.of(prefs.keys()).sorted().collect(Collectors.toList());
-            NarrowingHistoryLine currentHistoryLine = null;
-            int currentLine = 0;
-            for (String key : keys) {
-                if (!key.startsWith(HISTORY_LINE_PREFIX))
-                    continue;
-                CharSequence line = prefs.get(key, "");
-                if (snippetsStart.contains(currentLine)) {
-                    class PersistentNarrowingHistoryLine extends NarrowingHistoryLine implements PersistentEntryMarker {
-                        public PersistentNarrowingHistoryLine(CharSequence delegate, int start) {
-                            super(delegate, start);
-                        }
-                    }
-                    line = currentHistoryLine = new PersistentNarrowingHistoryLine(line, currentLine);
-                } else {
-                    class PersistentLine implements CharSequence, PersistentEntryMarker {
-                        private final CharSequence delegate;
-                        public PersistentLine(CharSequence delegate) {
-                            this.delegate = delegate;
-                        }
-                        @Override public int length() {
-                            return delegate.length();
-                        }
-                        @Override public char charAt(int index) {
-                            return delegate.charAt(index);
-                        }
-                        @Override public CharSequence subSequence(int start, int end) {
-                            return delegate.subSequence(start, end);
-                        }
-                        @Override public String toString() {
-                            return delegate.toString();
-                        }
-                    }
-                    line = new PersistentLine(line);
-                }
-                if (currentHistoryLine != null)
-                    currentHistoryLine.span[1] = currentLine;
-                currentLine++;
-                fullHistory.add(line);
-            }
-            currentLine = 0;
-        } catch (BackingStoreException ex) {
-            throw new IllegalStateException(ex);
-        }
-    }
-
-    public void save() {
-        try {
-            for (String key : prefs.keys()) {
-                if (key.startsWith(HISTORY_LINE_PREFIX))
-                    prefs.remove(key);
-            }
-            Iterator<Entry> entries = fullHistory.iterator();
-            if (entries.hasNext()) {
-                int len = (int) Math.ceil(Math.log10(fullHistory.size()+1));
-                String format = HISTORY_LINE_PREFIX + "%0" + len + "d";
-                StringBuilder snippetStarts = new StringBuilder();
-                String snippetStartDelimiter = "";
-                while (entries.hasNext()) {
-                    Entry entry = entries.next();
-                    prefs.put(String.format(format, entry.index()), entry.value().toString());
-                    if (entry.value() instanceof NarrowingHistoryLine) {
-                        snippetStarts.append(snippetStartDelimiter);
-                        snippetStarts.append(entry.index());
-                        snippetStartDelimiter = ";";
-                    }
-                }
-                prefs.put(HISTORY_SNIPPET_START, snippetStarts.toString());
-            }
-        } catch (BackingStoreException ex) {
-            throw new IllegalStateException(ex);
-        }
-    }
-
-    public List<String> currentSessionEntries() {
-        List<String> result = new ArrayList<>();
-
-        for (Entry e : fullHistory) {
-            if (!(e.value() instanceof PersistentEntryMarker)) {
-                result.add(e.value().toString());
-            }
-        }
-
-        return result;
-    }
-
-    void fullHistoryReplace(String source) {
-        fullHistory.replace(source);
-    }
-
-    private class NarrowingHistoryLine implements CharSequence {
-        private final CharSequence delegate;
-        private final int[] span;
-
-        public NarrowingHistoryLine(CharSequence delegate, int start) {
-            this.delegate = delegate;
-            this.span = new int[] {start, -1};
-        }
-
-        @Override
-        public int length() {
-            return delegate.length();
-        }
-
-        @Override
-        public char charAt(int index) {
-            return delegate.charAt(index);
-        }
-
-        @Override
-        public CharSequence subSequence(int start, int end) {
-            return delegate.subSequence(start, end);
-        }
-
-        @Override
-        public String toString() {
-            return delegate.toString();
-        }
-
-    }
-
-    private interface PersistentEntryMarker {}
-}
-
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java	Thu May 19 19:47:04 2016 +0000
@@ -47,6 +47,9 @@
     // Patern for substituted fields within a customized format string
     private static final Pattern FIELD_PATTERN = Pattern.compile("\\{(.*?)\\}");
 
+    // Internal field name for truncation length
+    private static final String TRUNCATION_FIELD = "<truncation>";
+
     // Current mode
     private Mode mode = new Mode("", false); // initial value placeholder during start-up
 
@@ -103,6 +106,10 @@
         return new Setter(messageHandler, at).setFormat();
     }
 
+    public boolean setTruncation(MessageHandler messageHandler, ArgTokenizer at) {
+        return new Setter(messageHandler, at).setTruncation();
+    }
+
     public boolean setNewMode(MessageHandler messageHandler, ArgTokenizer at) {
         return new Setter(messageHandler, at).setNewMode();
     }
@@ -251,13 +258,42 @@
             return sb.toString();
         }
 
+        // Compute the display output given full context and values
         String format(FormatCase fc, FormatAction fa, FormatWhen fw,
                     FormatResolve fr, FormatUnresolved fu, FormatErrors fe,
                     String name, String type, String value, String unresolved, List<String> errorLines) {
+            // Convert the context into a bit representation used as selectors for store field formats
             long bits = bits(fc, fa, fw, fr, fu, fe);
             String fname = name==null? "" : name;
             String ftype = type==null? "" : type;
-            String fvalue = value==null? "" : value;
+            // Compute the representation of value
+            String fvalue;
+            if (value==null) {
+                fvalue = "";
+            } else {
+                // Retrieve the truncation length
+                String truncField = format(TRUNCATION_FIELD, bits);
+                if (truncField.isEmpty()) {
+                    // No truncation set, use whole value
+                    fvalue = value;
+                } else {
+                    // Convert truncation length to int
+                    // this is safe since it has been tested before it is set
+                    int trunc = Integer.parseUnsignedInt(truncField);
+                    if (value.length() > trunc) {
+                        if (trunc <= 5) {
+                            // Very short truncations have no room for "..."
+                            fvalue = value.substring(0, trunc);
+                        } else {
+                            // Normal truncation, make total length equal truncation length
+                            fvalue = value.substring(0, trunc - 4) + " ...";
+                        }
+                    } else {
+                        // Within truncation length, use whole value
+                        fvalue = value;
+                    }
+                }
+            }
             String funresolved = unresolved==null? "" : unresolved;
             String errors = errorLines.stream()
                     .map(el -> String.format(
@@ -564,7 +600,7 @@
             return valid;
         }
 
-        // For /set newmode <new-mode> [command|quiet [<old-mode>]]
+        // For /set newmode <new-mode> [-command|-quiet [<old-mode>]]
         boolean setNewMode() {
             String umode = at.next();
             if (umode == null) {
@@ -575,8 +611,8 @@
                 errorat("jshell.err.feedback.expected.mode.name", umode);
                 valid = false;
             }
-            String[] fluffOpt = at.next("command", "quiet");
-            boolean fluff = fluffOpt == null || fluffOpt.length != 1 || "command".equals(fluffOpt[0]);
+            String[] fluffOpt = at.next("-command", "-quiet");
+            boolean fluff = fluffOpt == null || fluffOpt.length != 1 || "-command".equals(fluffOpt[0]);
             if (fluffOpt != null && fluffOpt.length != 1) {
                 errorat("jshell.err.feedback.command.quiet");
                 valid = false;
@@ -619,7 +655,32 @@
                 errorat("jshell.err.feedback.expected.field");
                 valid = false;
             }
-            String format = valid? nextFormat() : null;
+            String format = valid ? nextFormat() : null;
+            return installFormat(m, field, format, "/help /set format");
+        }
+
+        // For /set truncation <mode> <length> <selector>...
+        boolean setTruncation() {
+            Mode m = nextMode();
+            String length = at.next();
+            if (length == null) {
+                errorat("jshell.err.truncation.expected.length");
+                valid = false;
+            } else {
+                try {
+                    // Assure that integer format is correct
+                    Integer.parseUnsignedInt(length);
+                } catch (NumberFormatException ex) {
+                    errorat("jshell.err.truncation.length.not.integer", length);
+                    valid = false;
+                }
+            }
+            // install length into an internal format field
+            return installFormat(m, TRUNCATION_FIELD, length, "/help /set truncation");
+        }
+
+        // install the format of a field under parsed selectors
+        boolean installFormat(Mode m, String field, String format, String help) {
             String slRaw;
             List<SelectorList> slList = new ArrayList<>();
             while (valid && (slRaw = at.next()) != null) {
@@ -629,8 +690,10 @@
             }
             if (valid) {
                 if (slList.isEmpty()) {
+                    // No selectors specified, then always the format
                     m.set(field, ALWAYS, format);
                 } else {
+                    // Set the format of the field for specified selector
                     slList.stream()
                             .forEach(sl -> m.set(field,
                                 sl.cases.getSet(), sl.actions.getSet(), sl.whens.getSet(),
@@ -638,7 +701,7 @@
                                 format));
                 }
             } else {
-                fluffmsg("jshell.msg.see", "/help /set format");
+                fluffmsg("jshell.msg.see", help);
             }
             return valid;
         }
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Thu May 19 19:47:04 2016 +0000
@@ -113,7 +113,7 @@
     private static final String LINE_SEP = System.getProperty("line.separator");
     private static final Pattern LINEBREAK = Pattern.compile("\\R");
     private static final Pattern HISTORY_ALL_START_FILENAME = Pattern.compile(
-            "((?<cmd>(all|history|start))(\\z|\\p{javaWhitespace}+))?(?<filename>.*)");
+            "((?<cmd>(-all|-history|-start))(\\z|\\p{javaWhitespace}+))?(?<filename>.*)");
     private static final String RECORD_SEPARATOR = "\u241E";
     private static final String RB_NAME_PREFIX  = "jdk.internal.jshell.tool.resources";
     private static final String VERSION_RB_NAME = RB_NAME_PREFIX + ".version";
@@ -879,8 +879,8 @@
     }
 
     private static final CompletionProvider EMPTY_COMPLETION_PROVIDER = new FixedCompletionProvider();
-    private static final CompletionProvider KEYWORD_COMPLETION_PROVIDER = new FixedCompletionProvider("all ", "start ", "history ");
-    private static final CompletionProvider RELOAD_OPTIONS_COMPLETION_PROVIDER = new FixedCompletionProvider("restore", "quiet");
+    private static final CompletionProvider KEYWORD_COMPLETION_PROVIDER = new FixedCompletionProvider("-all ", "-start ", "-history ");
+    private static final CompletionProvider RELOAD_OPTIONS_COMPLETION_PROVIDER = new FixedCompletionProvider("-restore", "-quiet");
     private static final CompletionProvider FILE_COMPLETION_PROVIDER = fileCompletions(p -> true);
     private final Map<String, Command> commands = new LinkedHashMap<>();
     private void registerCommand(Command cmd) {
@@ -917,11 +917,10 @@
                                     p.getFileName().toString().endsWith(".jar"));
     }
 
-    private CompletionProvider editCompletion() {
+    private CompletionProvider snippetCompletion(Supplier<List<? extends Snippet>> snippetsSupplier) {
         return (prefix, cursor, anchor) -> {
             anchor[0] = 0;
-            return state.snippets()
-                        .stream()
+            return snippetsSupplier.get()                        .stream()
                         .flatMap(k -> (k instanceof DeclarationSnippet)
                                 ? Stream.of(String.valueOf(k.id()), ((DeclarationSnippet) k).name())
                                 : Stream.of(String.valueOf(k.id())))
@@ -931,11 +930,11 @@
         };
     }
 
-    private CompletionProvider editKeywordCompletion() {
+    private CompletionProvider snippetKeywordCompletion(Supplier<List<? extends Snippet>> snippetsSupplier) {
         return (code, cursor, anchor) -> {
             List<Suggestion> result = new ArrayList<>();
             result.addAll(KEYWORD_COMPLETION_PROVIDER.completionSuggestions(code, cursor, anchor));
-            result.addAll(editCompletion().completionSuggestions(code, cursor, anchor));
+            result.addAll(snippetCompletion(snippetsSupplier).completionSuggestions(code, cursor, anchor));
             return result;
         };
     }
@@ -963,18 +962,51 @@
         };
     }
 
+    // Snippet lists
+
+    List<Snippet> allSnippets() {
+        return state.snippets();
+    }
+
+    List<Snippet> dropableSnippets() {
+        return state.snippets().stream()
+                .filter(sn -> state.status(sn).isActive)
+                .collect(toList());
+    }
+
+    List<VarSnippet> allVarSnippets() {
+        return state.snippets().stream()
+                .filter(sn -> sn.kind() == Snippet.Kind.VAR)
+                .map(sn -> (VarSnippet) sn)
+                .collect(toList());
+    }
+
+    List<MethodSnippet> allMethodSnippets() {
+        return state.snippets().stream()
+                .filter(sn -> sn.kind() == Snippet.Kind.METHOD)
+                .map(sn -> (MethodSnippet) sn)
+                .collect(toList());
+    }
+
+    List<TypeDeclSnippet> allTypeSnippets() {
+        return state.snippets().stream()
+                .filter(sn -> sn.kind() == Snippet.Kind.TYPE_DECL)
+                .map(sn -> (TypeDeclSnippet) sn)
+                .collect(toList());
+    }
+
     // Table of commands -- with command forms, argument kinds, helpKey message, implementation, ...
 
     {
         registerCommand(new Command("/list",
                 arg -> cmdList(arg),
-                editKeywordCompletion()));
+                snippetKeywordCompletion(this::allSnippets)));
         registerCommand(new Command("/edit",
                 arg -> cmdEdit(arg),
-                editCompletion()));
+                snippetCompletion(this::allSnippets)));
         registerCommand(new Command("/drop",
                 arg -> cmdDrop(arg),
-                editCompletion(),
+                snippetCompletion(this::dropableSnippets),
                 CommandKind.REPLAY));
         registerCommand(new Command("/save",
                 arg -> cmdSave(arg),
@@ -983,14 +1015,14 @@
                 arg -> cmdOpen(arg),
                 FILE_COMPLETION_PROVIDER));
         registerCommand(new Command("/vars",
-                arg -> cmdVars(),
-                EMPTY_COMPLETION_PROVIDER));
+                arg -> cmdVars(arg),
+                snippetKeywordCompletion(this::allVarSnippets)));
         registerCommand(new Command("/methods",
-                arg -> cmdMethods(),
-                EMPTY_COMPLETION_PROVIDER));
-        registerCommand(new Command("/classes",
-                arg -> cmdClasses(),
-                EMPTY_COMPLETION_PROVIDER));
+                arg -> cmdMethods(arg),
+                snippetKeywordCompletion(this::allMethodSnippets)));
+        registerCommand(new Command("/types",
+                arg -> cmdTypes(arg),
+                snippetKeywordCompletion(this::allTypeSnippets)));
         registerCommand(new Command("/imports",
                 arg -> cmdImports(),
                 EMPTY_COMPLETION_PROVIDER));
@@ -1019,7 +1051,7 @@
                 EMPTY_COMPLETION_PROVIDER));
         registerCommand(new Command("/set",
                 arg -> cmdSet(arg),
-                new FixedCompletionProvider("format", "feedback", "prompt", "newmode", "start", "editor")));
+                new FixedCompletionProvider(SET_SUBCOMMANDS)));
         registerCommand(new Command("/?",
                 "help.quest",
                 arg -> cmdHelp(arg),
@@ -1094,7 +1126,7 @@
     // --- Command implementations ---
 
     private static final String[] SET_SUBCOMMANDS = new String[]{
-        "format", "feedback", "newmode", "prompt", "editor", "start"};
+        "format", "truncation", "feedback", "newmode", "prompt", "editor", "start"};
 
     final boolean cmdSet(String arg) {
         ArgTokenizer at = new ArgTokenizer("/set ", arg.trim());
@@ -1105,6 +1137,8 @@
         switch (which) {
             case "format":
                 return feedback.setFormat(this, at);
+            case "truncation":
+                return feedback.setTruncation(this, at);
             case "feedback":
                 return feedback.setFeedback(this, at);
             case "newmode":
@@ -1310,7 +1344,7 @@
     /**
      * Avoid parameterized varargs possible heap pollution warning.
      */
-    private interface SnippetPredicate extends Predicate<Snippet> { }
+    private interface SnippetPredicate<T extends Snippet> extends Predicate<T> { }
 
     /**
      * Apply filters to a stream until one that is non-empty is found.
@@ -1320,10 +1354,11 @@
      * @param filters Filters to attempt
      * @return The non-empty filtered Stream, or null
      */
-    private static Stream<Snippet> nonEmptyStream(Supplier<Stream<Snippet>> supplier,
-            SnippetPredicate... filters) {
-        for (SnippetPredicate filt : filters) {
-            Iterator<Snippet> iterator = supplier.get().filter(filt).iterator();
+    @SafeVarargs
+    private static <T extends Snippet> Stream<T> nonEmptyStream(Supplier<Stream<T>> supplier,
+            SnippetPredicate<T>... filters) {
+        for (SnippetPredicate<T> filt : filters) {
+            Iterator<T> iterator = supplier.get().filter(filt).iterator();
             if (iterator.hasNext()) {
                 return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
             }
@@ -1352,24 +1387,40 @@
      * Convert a user argument to a Stream of snippets referenced by that argument
      * (or lack of argument).
      *
-     * @param arg The user's argument to the command, maybe be the empty string
+     * @param snippets the base list of possible snippets
+     * @param arg the user's argument to the command, maybe be the empty string
+     * @param allowAll if true, allow the use of '-all' and '-start'
      * @return a Stream of referenced snippets or null if no matches to specific arg
      */
-    private Stream<Snippet> argToSnippets(String arg, boolean allowAll) {
-        List<Snippet> snippets = state.snippets();
-        if (allowAll && arg.equals("all")) {
+    private <T extends Snippet> Stream<T> argToSnippets(List<T> snippets, String arg, boolean allowAll) {
+        return argToSnippets(snippets, this::mainActive, arg, allowAll);
+    }
+
+    /**
+     * Convert a user argument to a Stream of snippets referenced by that argument
+     * (or lack of argument).
+     *
+     * @param snippets the base list of possible snippets
+     * @param defFilter the filter to apply to the arguments if no argument
+     * @param arg the user's argument to the command, maybe be the empty string
+     * @param allowAll if true, allow the use of '-all' and '-start'
+     * @return a Stream of referenced snippets or null if no matches to specific arg
+     */
+    private <T extends Snippet> Stream<T> argToSnippets(List<T> snippets,
+            Predicate<Snippet> defFilter, String arg, boolean allowAll) {
+        if (allowAll && arg.equals("-all")) {
             // all snippets including start-up, failed, and overwritten
             return snippets.stream();
-        } else if (allowAll && arg.equals("start")) {
+        } else if (allowAll && arg.equals("-start")) {
             // start-up snippets
             return snippets.stream()
                     .filter(this::inStartUp);
         } else if (arg.isEmpty()) {
             // Default is all active user snippets
             return snippets.stream()
-                    .filter(this::mainActive);
+                    .filter(defFilter);
         } else {
-            Stream<Snippet> result =
+            Stream<T> result =
                     nonEmptyStream(
                             () -> snippets.stream(),
                             // look for active user declarations matching the name
@@ -1383,12 +1434,39 @@
         }
     }
 
+    /**
+     * Convert a user argument to a Stream of snippets referenced by that
+     * argument, printing an informative message if no matches. Allow '-all' and
+     * '-start'.
+     *
+     * @param snippets the base list of possible snippets
+     * @param defFilter the filter to apply to the arguments if no argument
+     * @param arg the user's argument to the command, maybe be the empty string
+     * @param cmd the name of the command (for use in a help message
+     * @return a Stream of referenced snippets or null if no matches to specific
+     * arg
+     */
+    private <T extends Snippet> Stream<T> argToSnippetsWithMessage(List<T> snippets,
+            Predicate<Snippet> defFilter, String arg, String cmd) {
+        Stream<T> stream = argToSnippets(snippets, defFilter, arg, true);
+        if (stream == null) {
+            errormsg("jshell.err.def.or.id.not.found", arg);
+            // Check if there are any definitions at all
+            if (argToSnippets(snippets, "", false).iterator().hasNext()) {
+                fluffmsg("jshell.msg.try.command.without.args", cmd);
+            } else {
+                hardmsg("jshell.msg.no.active");
+            }
+        }
+        return stream;
+    }
+
     private boolean cmdDrop(String arg) {
         if (arg.isEmpty()) {
             errormsg("jshell.err.drop.arg");
             return false;
         }
-        Stream<Snippet> stream = argToSnippets(arg, false);
+        Stream<Snippet> stream = argToSnippets(dropableSnippets(), arg, false);
         if (stream == null) {
             errormsg("jshell.err.def.or.id.not.found", arg);
             fluffmsg("jshell.msg.see.classes.etc");
@@ -1415,10 +1493,9 @@
     }
 
     private boolean cmdEdit(String arg) {
-        Stream<Snippet> stream = argToSnippets(arg, true);
+        Stream<Snippet> stream = argToSnippetsWithMessage(state.snippets(),
+                this::mainActive, arg, "/edit");
         if (stream == null) {
-            errormsg("jshell.err.def.or.id.not.found", arg);
-            fluffmsg("jshell.msg.see.classes.etc");
             return false;
         }
         Set<String> srcSet = new LinkedHashSet<>();
@@ -1518,18 +1595,12 @@
     }
 
     private boolean cmdList(String arg) {
-        if (arg.equals("history")) {
+        if (arg.equals("-history")) {
             return cmdHistory();
         }
-        Stream<Snippet> stream = argToSnippets(arg, true);
+        Stream<Snippet> stream = argToSnippetsWithMessage(state.snippets(),
+                this::mainActive, arg, "/list");
         if (stream == null) {
-            errormsg("jshell.err.def.or.id.not.found", arg);
-            // Check if there are any definitions at all
-            if (argToSnippets("", false).iterator().hasNext()) {
-                fluffmsg("jshell.msg.try.list.without.args");
-            } else {
-                hardmsg("jshell.msg.no.active");
-            }
             return false;
         }
 
@@ -1601,13 +1672,13 @@
         Iterable<String> history = replayableHistory;
         boolean echo = true;
         if (arg.length() > 0) {
-            if ("restore".startsWith(arg)) {
+            if ("-restore".startsWith(arg)) {
                 if (replayableHistoryPrevious == null) {
                     errormsg("jshell.err.reload.no.previous");
                     return false;
                 }
                 history = replayableHistoryPrevious;
-            } else if ("quiet".startsWith(arg)) {
+            } else if ("-quiet".startsWith(arg)) {
                 echo = false;
             } else {
                 errormsg("jshell.err.arg", "/reload", arg);
@@ -1634,13 +1705,13 @@
         boolean saveStart = false;
         String cmd = mat.group("cmd");
         if (cmd != null) switch (cmd) {
-            case "all":
-                saveAll = "all";
+            case "-all":
+                saveAll = "-all";
                 break;
-            case "history":
+            case "-history":
                 useHistory = true;
                 break;
-            case "start":
+            case "-start":
                 saveStart = true;
                 break;
         }
@@ -1660,7 +1731,7 @@
             } else if (saveStart) {
                 writer.append(DEFAULT_STARTUP);
             } else {
-                Stream<Snippet> stream = argToSnippets(saveAll, true);
+                Stream<Snippet> stream = argToSnippets(state.snippets(), saveAll, true);
                 if (stream != null) {
                     for (Snippet sn : stream.collect(toList())) {
                         writer.write(sn.source());
@@ -1678,25 +1749,42 @@
         return true;
     }
 
-    private boolean cmdVars() {
-        for (VarSnippet vk : state.variables()) {
+    private boolean cmdVars(String arg) {
+        Stream<VarSnippet> stream = argToSnippetsWithMessage(allVarSnippets(),
+                this::isActive, arg, "/vars");
+        if (stream == null) {
+            return false;
+        }
+        stream.forEachOrdered(vk ->
+        {
             String val = state.status(vk) == Status.VALID
                     ? state.varValue(vk)
                     : "jshell.msg.vars.not.active";
             hard("  %s %s = %s", vk.typeName(), vk.name(), val);
-        }
+        });
         return true;
     }
 
-    private boolean cmdMethods() {
-        for (MethodSnippet mk : state.methods()) {
-            hard("  %s %s", mk.name(), mk.signature());
+    private boolean cmdMethods(String arg) {
+        Stream<MethodSnippet> stream = argToSnippetsWithMessage(allMethodSnippets(),
+                this::isActive, arg, "/methods");
+        if (stream == null) {
+            return false;
         }
+        stream.forEachOrdered(mk
+                -> hard("  %s %s", mk.name(), mk.signature())
+        );
         return true;
     }
 
-    private boolean cmdClasses() {
-        for (TypeDeclSnippet ck : state.types()) {
+    private boolean cmdTypes(String arg) {
+        Stream<TypeDeclSnippet> stream = argToSnippetsWithMessage(allTypeSnippets(),
+                this::isActive, arg, "/types");
+        if (stream == null) {
+            return false;
+        }
+        stream.forEachOrdered(ck
+        -> {
             String kind;
             switch (ck.subKind()) {
                 case INTERFACE_SUBKIND:
@@ -1717,7 +1805,7 @@
                     break;
             }
             hard("  %s %s", kind, ck.name());
-        }
+        });
         return true;
     }
 
--- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Thu May 19 17:48:04 2016 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Thu May 19 19:47:04 2016 +0000
@@ -34,11 +34,11 @@
 
 jshell.msg.terminated =\
 State engine terminated.\n\
-Restore definitions with: /reload restore
+Restore definitions with: /reload -restore
 
 jshell.msg.use.one.of = Use one of: {0}
-jshell.err.def.or.id.not.found = No definition or id found named: {0}
-jshell.msg.see.classes.etc = See /classes, /methods, /vars, or /list
+jshell.err.def.or.id.not.found = No applicable definition or id found named: {0}
+jshell.msg.see.classes.etc = See /types, /methods, /vars, or /list
 jshell.err.arg = Invalid ''{0}'' argument: {1}
 jshell.msg.see = See {0} for help.
 
@@ -57,7 +57,7 @@
 jshell.err.cant.launch.editor = Cannot launch editor -- unexpected exception: {0}
 jshell.msg.try.set.editor = Try /set editor to use external editor.
 
-jshell.msg.try.list.without.args = Try ''/list'' without arguments.
+jshell.msg.try.command.without.args = Try ''{0}'' without arguments.
 jshell.msg.no.active = There are no active definitions.
 
 jshell.msg.resetting = Resetting...
@@ -102,7 +102,7 @@
 
 jshell.err.feedback.expected.new.feedback.mode = Expected new feedback mode -- {0}
 jshell.err.feedback.expected.mode.name = Expected a new feedback mode name. ''{0}'' is a known feedback mode -- {1}
-jshell.err.feedback.command.quiet = Specify either ''command'' or ''quiet'' -- {0}
+jshell.err.feedback.command.quiet = Specify either ''-command'' or ''-quiet'' -- {0}
 jshell.err.feedback.expected.field = Expected field name missing -- {0}
 jshell.err.feedback.expected.mode = Expected a feedback mode -- {0}
 jshell.err.feedback.does.not.match.mode = Does not match any current feedback mode: {0} -- {1}
@@ -117,6 +117,9 @@
 jshell.msg.feedback.mode = Feedback mode: {0}
 jshell.msg.feedback.mode.following = The feedback mode should be one of the following:
 
+jshell.err.truncation.expected.length = Expected truncation length -- {0}
+jshell.err.truncation.length.not.integer = Truncation length must be an integer: {0} -- {1}
+
 jshell.console.see.more = <press tab to see more>
 jshell.console.do.nothing = Do nothing
 jshell.console.choice = Choice: \
@@ -148,15 +151,15 @@
 \    -version             Version information\n
 
 help.list.summary = list the source you have typed
-help.list.args = [all|start|<name or id>]
+help.list.args = [<name or id>|-all|-start]
 help.list =\
 Show the source of snippets, prefaced with the snippet id.\n\
 \n\
 /list\n\t\
     List the currently active snippets of code that you typed or read with /open\n\n\
-/list start\n\t\
+/list -start\n\t\
     List the automatically evaluated start-up snippets\n\n\
-/list all\n\t\
+/list -all\n\t\
     List all snippets including failed, overwritten, dropped, and start-up\n\n\
 /list <name>\n\t\
     List snippets with the specified name (preference for active snippets)\n\n\
@@ -188,18 +191,18 @@
     Drop the snippet with the specified snippet id
 
 help.save.summary = Save snippet source to a file.
-help.save.args = [all|history|start] <file>
+help.save.args = [-all|-history|-start] <file>
 help.save =\
 Save the specified snippets and/or commands to the specified file.\n\
 \n\
 /save <file>\n\t\
     Save the source of current active snippets to the file.\n\n\
-/save all <file>\n\t\
+/save -all <file>\n\t\
     Save the source of all snippets to the file.\n\t\
     Includes source including overwritten, failed, and start-up code.\n\n\
-/save history <file>\n\t\
+/save -history <file>\n\t\
     Save the sequential history of all commands and snippets entered since jshell was launched.\n\n\
-/save start <file>\n\t\
+/save -start <file>\n\t\
     Save the default start-up definitions to the file.
 
 help.open.summary = open a file as source input
@@ -211,19 +214,52 @@
     Read the specified file as jshell input.
 
 help.vars.summary = list the declared variables and their values
-help.vars.args =
+help.vars.args = [<name or id>|-all|-start]
 help.vars =\
-List the type, name, and value of the current active jshell variables.
+List the type, name, and value of jshell variables.\n\
+\n\
+/vars\n\t\
+    List the type, name, and value of the current active jshell variables\n\n\
+/vars <name>\n\t\
+    List jshell variables with the specified name (preference for active variables)\n\n\
+/vars <id>\n\t\
+    List the jshell variable with the specified snippet id\n\n\
+/vars -start\n\t\
+    List the automatically added start-up jshell variables\n\n\
+/vars -all\n\t\
+    List all jshell variables including failed, overwritten, dropped, and start-up
 
 help.methods.summary = list the declared methods and their signatures
-help.methods.args =
+help.methods.args = [<name or id>|-all|-start]
 help.methods =\
-List the name, parameter types, and return type of the current active jshell methods.
+List the name, parameter types, and return type of jshell methods.\n\
+\n\
+/methods\n\t\
+    List the name, parameter types, and return type of the current active jshell methods\n\n\
+/methods <name>\n\t\
+    List jshell methods with the specified name (preference for active methods)\n\n\
+/methods <id>\n\t\
+    List the jshell method with the specified snippet id\n\n\
+/methods -start\n\t\
+    List the automatically added start-up jshell methods\n\n\
+/methods -all\n\t\
+    List all snippets including failed, overwritten, dropped, and start-up
 
-help.classes.summary = list the declared classes
-help.classes.args =
-help.classes =\
-List the current active jshell classes, interfaces, and enums.
+help.types.summary = list the declared types
+help.types.args =[<name or id>|-all|-start]
+help.types =\
+List jshell classes, interfaces, and enums.\n\
+\n\
+/types\n\t\
+    List the current active jshell classes, interfaces, and enums.\n\n\
+/types <name>\n\t\
+    List jshell types with the specified name (preference for active types)\n\n\
+/types <id>\n\t\
+    List the jshell type with the specified snippet id\n\n\
+/types -start\n\t\
+    List the automatically added start-up jshell types\n\n\
+/types -all\n\t\
+    List all jshell types including failed, overwritten, dropped, and start-up
 
 help.imports.summary = list the imported items
 help.imports.args =
@@ -247,8 +283,8 @@
 Tool settings are maintained, as set with: /set ...\n\
 Save any work before using this command
 
-help.reload.summary = reset and replay relevant history -- current or previous (restore)
-help.reload.args = [restore] [quiet]
+help.reload.summary = reset and replay relevant history -- current or previous (-restore)
+help.reload.args = [-restore] [-quiet]
 help.reload =\
 Reset the jshell tool code and execution state then replay each\n\
 jshell valid command and valid snippet in the order they were entered.\n\
@@ -257,13 +293,13 @@
      Reset and replay the valid history since jshell was entered, or\n\t\
      a /reset, or /reload command was executed -- whichever is most\n\t\
      recent.\n\n\
-/reload restore\n\t\
+/reload -restore\n\t\
      Reset and replay the valid history between the previous and most\n\t\
      recent time that jshell was entered, or a /reset, or /reload\n\t\
      command was executed. This can thus be used to restore a previous\n\t\
      jshell tool sesson.\n\n\
-/reload [restore] quiet\n\t\
-     With the 'quiet' argument the replay is not shown.  Errors will display.
+/reload [-restore] -quiet\n\t\
+     With the '-quiet' argument the replay is not shown.  Errors will display.
 
 help.classpath.summary = add a path to the classpath
 help.classpath.args = <path>
@@ -301,7 +337,7 @@
      Display information about the specified help subject. Example: /help intro
 
 help.set.summary = set jshell configuration information
-help.set.args = editor|start|feedback|newmode|prompt|format ...
+help.set.args = editor|start|feedback|newmode|prompt|truncation|format ...
 help.set =\
 Set jshell configuration information, including:\n\
 the external editor to use, the start-up definitions to use, a new feedback mode,\n\
@@ -314,10 +350,12 @@
      The contents of the specified <file> become the default start-up snippets and commands.\n\n\
 /set feedback <mode>\n\t\
      Set the feedback mode describing displayed feedback for entered snippets and commands.\n\n\
-/set newmode <new-mode> [command|quiet [<old-mode>]]\n\t\
+/set newmode <new-mode> [-command|-quiet [<old-mode>]]\n\t\
      Create a user-defined feedback mode, optionally copying from an existing mode.\n\n\
 /set prompt <mode> "<prompt>" "<continuation-prompt>"\n\t\
      Set the displayed prompts for a given feedback mode.\n\n\
+/set truncation <mode> <length> <selector>...\n\t\
+     Set the maximum length of a displayed value\n\t\
 /set format <mode> <field> "<format>" <selector>...\n\t\
      Configure a feedback mode by setting the format of a field when the selector matchs.\n\n\
 To get more information about one of these forms, use /help with the form specified.\n\
@@ -462,6 +500,37 @@
 /set format myformat display '{pre}{action} variable {name}, reset to null{post}' replaced-vardecl,varinit-ok-update\n\n\
 Note that subsequent selectors for a field may overwrite some or all of previous used selectors -- last one wins\n
 
+help.set.truncation = \
+Set the max length a displayed value.\n\
+\n\t\
+/set truncation <mode> <length> <selector>...\n\
+\n\
+Where <mode> is the name of a previously defined feedback mode -- see '/help /set newmode'.\n\
+Where <length> is an unsigned integer representing a maximum length.\n\
+Where <format> is a quoted string which will be the value of the field if one of\n\
+Where <selector> is only needed if you wish to fine-tune value truncation length\n\
+by context, <selector> is the context in which the truncation is applied.\n\
+The structure of selector is a hyphen separated list of selector kind lists.\n\
+A selector kind list is a comma separated list of values of one selector kind.\n\
+A selector matches if each selector kind list matches; A selector kind list\n\
+matches if one of the values matches.\n\n\
+Below are the relevant selector kinds for truncation.\n\n\
+The case selector kind describes the kind of snippet.  The values are:\n\t\
+   vardecl    -- variable declaration without init\n\t\
+   varinit    -- variable declaration with init\n\t\
+   expression -- expression -- note: {name}==scratch-variable-name\n\t\
+   varvalue   -- variable value expression\n\t\
+   assignment -- assign variable\n\t\
+The action selector kind describes what happened to the snippet.  The values are:\n\t\
+   added     -- snippet has been added\n\t\
+   modified  -- an existing snippet has been modified\n\t\
+   replaced  -- an existing snippet has been replaced with a new snippet\n\
+Examples:\n\t\
+/set trunc mymode 80\n\t\
+/set truncation mymode 45 expression\n\t\
+/set truncation mymode 0 vardecl-modified,replaced\n\n\
+Note that subsequent selectors for a field may overwrite some or all of previous used selectors -- last one wins\n
+
 help.set.feedback = \
 Set the feedback mode describing displayed feedback for entered snippets and commands.\n\
 \n\t\
@@ -475,12 +544,12 @@
 help.set.newmode = \
 Create a user-defined feedback mode, optionally copying from an existing mode.\n\
 \n\t\
-/set newmode <new-mode> [command|quiet [<old-mode>]]\n\
+/set newmode <new-mode> [-command|-quiet [<old-mode>]]\n\
 \n\
 Where <new-mode> is the name of a mode you wish to create.\n\
 Where <old-mode> is the name of a previously defined feedback mode.\n\
 If <old-mode> is present, its settings are copied to the new mode.\n\
-'command' vs 'quiet' determines if informative/verifying command feedback is displayed.\n\
+'-command' vs '-quiet' determines if informative/verifying command feedback is displayed.\n\
 \n\
 Once the new mode is created, use '/set format' and '/set prompt' to configure it.\n\
 Use '/set feedback' to use the new mode.\n\
@@ -514,7 +583,7 @@
 which are run when the jshell tool is started or reset.
 
 startup.feedback = \
-/set newmode verbose command    \n\
+/set newmode verbose -command    \n\
 \n\
 /set prompt verbose '\\njshell> '   '   ...> '    \n\
 \n\
@@ -578,11 +647,14 @@
 /set format verbose display '{pre}attempted to use {typeKind} {name}{resolve}{post}'         used-class,interface,enum,annotation    \n\
 /set format verbose display '{pre}attempted to call method {name}({type}){resolve}{post}'    used-method    \n\
 \n\
-/set newmode normal command verbose    \n\
+/set truncation verbose 80\n\
+/set truncation verbose 500                                                                  varvalue\n\
+\n\
+/set newmode normal -command verbose    \n\
 /set format normal display ''                                                               added,modified,replaced,overwrote,dropped-update    \n\
 /set format normal display '{pre}{action} variable {name}, reset to null{post}'             replaced-vardecl,varinit-ok-update    \n\
 /set format normal display '{result}'                                                       added,modified,replaced-expression,varvalue,assignment,varinit,vardecl-ok-primary    \n\
-/set newmode concise quiet normal    \n\
+/set newmode concise -quiet normal    \n\
 \n\
 /set prompt concise 'jshell> '   '   ...> '    \n\
 \n\
@@ -590,7 +662,7 @@
 \n\
 /set feedback normal    \n\
 \n\
-/set newmode silent quiet    \n\
+/set newmode silent -quiet    \n\
 /set prompt silent '-> ' '>> '    \n\
 /set format silent pre '|  '    \n\
 /set format silent post '%n'    \n\
--- a/test/ProblemList.txt	Thu May 19 17:48:04 2016 +0000
+++ b/test/ProblemList.txt	Thu May 19 19:47:04 2016 +0000
@@ -66,7 +66,6 @@
 # javac
 
 tools/javac/Paths/AbsolutePathTest.java                                         8055768    generic-all    ToolBox does not close opened files
-tools/javac/Paths/MineField.sh                                                  8149599	   generic-all    needs rewrite
 tools/javac/annotations/typeAnnotations/failures/CantAnnotatePackages.java      8057679    generic-all    clarify error messages trying to annotate scoping
 tools/javac/annotations/typeAnnotations/failures/CantAnnotateScoping.java       8057679    generic-all    clarify error messages trying to annotate scoping
 tools/javac/annotations/typeAnnotations/failures/CantAnnotateStaticClass2.java  8057679    generic-all    clarify error messages trying to annotate scoping
@@ -95,6 +94,3 @@
 #
 # jdeps 
 
-tools/jdeps/modules/GenModuleInfo.java                                          8152502,8153481    generic-all    fails to clean up files, java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
-tools/jdeps/modules/ModuleTest.java                                             8153481    generic-all    java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
-
--- a/test/jdk/jshell/CommandCompletionTest.java	Thu May 19 17:48:04 2016 +0000
+++ b/test/jdk/jshell/CommandCompletionTest.java	Thu May 19 19:47:04 2016 +0000
@@ -53,18 +53,18 @@
 
     public void testCommand() {
         assertCompletion("/deb|", false);
-        assertCompletion("/c|", false, "/classes ", "/classpath ");
+        assertCompletion("/re|", false, "/reload ", "/reset ");
         assertCompletion("/h|", false, "/help ", "/history ");
     }
 
     public void testList() {
         test(false, new String[] {"-nostartup"},
                 a -> assertCompletion(a, "/l|", false, "/list "),
-                a -> assertCompletion(a, "/list |", false, "all ", "history ", "start "),
-                a -> assertCompletion(a, "/list h|", false, "history "),
+                a -> assertCompletion(a, "/list |", false, "-all ", "-history ", "-start "),
+                a -> assertCompletion(a, "/list -h|", false, "-history "),
                 a -> assertCompletion(a, "/list q|", false),
                 a -> assertVariable(a, "int", "xray"),
-                a -> assertCompletion(a, "/list |", false, "1", "all ", "history ", "start ", "xray"),
+                a -> assertCompletion(a, "/list |", false, "-all ", "-history ", "-start ", "1", "xray"),
                 a -> assertCompletion(a, "/list x|", false, "xray")
         );
     }
@@ -108,7 +108,7 @@
         Compiler compiler = new Compiler();
         assertCompletion("/s|", false, "/save ", "/set ");
         List<String> p1 = listFiles(Paths.get(""));
-        Collections.addAll(p1, "all ", "history ", "start ");
+        Collections.addAll(p1, "-all ", "-history ", "-start ");
         FileSystems.getDefault().getRootDirectories().forEach(s -> p1.add(s.toString()));
         Collections.sort(p1);
         assertCompletion("/save |", false, p1.toArray(new String[p1.size()]));
@@ -116,7 +116,7 @@
         List<String> p2 = listFiles(classDir);
         assertCompletion("/save " + classDir + "/|",
                 false, p2.toArray(new String[p2.size()]));
-        assertCompletion("/save all " + classDir + "/|",
+        assertCompletion("/save -all " + classDir + "/|",
                 false, p2.toArray(new String[p2.size()]));
     }
 
--- a/test/jdk/jshell/EditorTestBase.java	Thu May 19 17:48:04 2016 +0000
+++ b/test/jdk/jshell/EditorTestBase.java	Thu May 19 19:47:04 2016 +0000
@@ -142,7 +142,7 @@
                     exit();
                     loadClass(true, "enum A {}", "enum", "A");
                 }),
-                a -> assertCommandCheckOutput(a, "/classes", assertClasses())
+                a -> assertCommandCheckOutput(a, "/types", assertClasses())
         );
     }
 
@@ -161,7 +161,7 @@
                     exit();
                     loadClass(true, "enum A {}", "enum", "A");
                 }),
-                a -> assertCommandCheckOutput(a, "/classes", assertClasses())
+                a -> assertCommandCheckOutput(a, "/types", assertClasses())
         );
     }
 
--- a/test/jdk/jshell/HistoryTes