changeset 4067:69a7ccfb20e0

Merge
author alanb
date Thu, 26 May 2016 12:32:24 +0100
parents 0e0dfba618f6 0f81cdd51b42
children 3fbac077dc0a
files src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleWrappers.java src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModulePaths.java src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteResolutionException.java src/jdk.jshell/share/classes/jdk/internal/jshell/tool/EditingHistory.java src/jdk.jshell/share/classes/jdk/jshell/ClassTracker.java src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java src/jdk.jshell/share/classes/jdk/jshell/JDIConnection.java src/jdk.jshell/share/classes/jdk/jshell/JDIEnv.java src/jdk.jshell/share/classes/jdk/jshell/JDIEventHandler.java src/jdk.jshell/share/classes/jdk/jshell/JDINotConnectedException.java test/tools/jdeps/CompilerUtils.java
diffstat 258 files changed, 14289 insertions(+), 6000 deletions(-) [+]
line wrap: on
line diff
--- a/make/build.properties	Tue May 24 11:59:42 2016 -0700
+++ b/make/build.properties	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/make/build.xml	Thu May 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/make/intellij/workspace.xml	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/make/tools/crules/AssertCheckAnalyzer.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/make/tools/crules/MutableFieldsAnalyzer.java	Thu May 26 12:32:24 2016 +0100
@@ -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) {
@@ -98,12 +99,14 @@
         ignoreFields("com.sun.tools.javac.code.Type", "moreInfo");
         ignoreFields("com.sun.tools.javac.util.SharedNameTable", "freelist");
         ignoreFields("com.sun.tools.javac.util.Log", "useRawMessages");
-        ignoreFields("com.sun.tools.javac.util.ModuleWrappers$ModuleFinderHelper",
-                "moduleFinderInterface", "ofMethod", "emptyMethod");
-        ignoreFields("com.sun.tools.javac.util.ModuleWrappers$ConfigurationHelper",
+        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$ModuleFinder",
+                "moduleFinderClass", "ofMethod");
+        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$Configuration",
                 "configurationClass", "resolveRequiresAndUsesMethod");
-        ignoreFields("com.sun.tools.javac.util.ModuleWrappers$LayerHelper",
+        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$Layer",
                 "layerClass", "bootMethod", "defineModulesWithOneLoaderMethod", "configurationMethod");
+        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$ServiceLoaderHelper",
+                "loadMethod");
         ignoreFields("com.sun.tools.javac.util.ModuleHelper",
                 "addExportsMethod", "getUnnamedModuleMethod", "getModuleMethod");
     }
--- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java	Tue May 24 11:59:42 2016 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java	Thu May 26 12:32:24 2016 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -55,7 +55,7 @@
      * 1.6: no changes
      * 1.7: diamond syntax, try-with-resources, etc.
      * 1.8: lambda expressions and default methods
-     * 9: To be determined
+     *   9: modules, small cleanups to 1.7 and 1.8 changes
      */
 
     /**
@@ -145,6 +145,9 @@
      * The version recognized by the Java Platform, Standard Edition
      * 9.
      *
+     * Additions in this release include modules and removal of a
+     * single underscore from the set of legal identifier names.
+     *
      * @since 9
      */
      RELEASE_9;
@@ -233,10 +236,10 @@
     }
 
     /**
-     *  Returns whether or not {@code name} is a syntactically valid
-     *  qualified name in the latest source version.  Unlike {@link
-     *  #isIdentifier isIdentifier}, this method returns {@code false}
-     *  for keywords and literals.
+     * Returns whether or not {@code name} is a syntactically valid
+     * qualified name in the latest source version.  Unlike {@link
+     * #isIdentifier isIdentifier}, this method returns {@code false}
+     * for keywords, boolean literals, and the null literal.
      *
      * @param name the string to check
      * @return {@code true} if this string is a
@@ -244,45 +247,115 @@
      * @jls 6.2 Names and Identifiers
      */
     public static boolean isName(CharSequence name) {
+        return isName(name, latest());
+    }
+
+    /**
+     * Returns whether or not {@code name} is a syntactically valid
+     * qualified name in the given source version.  Unlike {@link
+     * #isIdentifier isIdentifier}, this method returns {@code false}
+     * for keywords, boolean literals, and the null literal.
+     *
+     * @param name the string to check
+     * @param version the version to use
+     * @return {@code true} if this string is a
+     * syntactically valid name, {@code false} otherwise.
+     * @jls 6.2 Names and Identifiers
+     * @since 9
+     */
+    public static boolean isName(CharSequence name, SourceVersion version) {
         String id = name.toString();
 
         for(String s : id.split("\\.", -1)) {
-            if (!isIdentifier(s) || isKeyword(s))
+            if (!isIdentifier(s) || isKeyword(s, version))
                 return false;
         }
         return true;
     }
 
-    private final static Set<String> keywords;
-    static {
-        Set<String> s = new HashSet<>();
-        String [] kws = {
-            "abstract", "continue",     "for",          "new",          "switch",
-            "assert",   "default",      "if",           "package",      "synchronized",
-            "boolean",  "do",           "goto",         "private",      "this",
-            "break",    "double",       "implements",   "protected",    "throw",
-            "byte",     "else",         "import",       "public",       "throws",
-            "case",     "enum",         "instanceof",   "return",       "transient",
-            "catch",    "extends",      "int",          "short",        "try",
-            "char",     "final",        "interface",    "static",       "void",
-            "class",    "finally",      "long",         "strictfp",     "volatile",
-            "const",    "float",        "native",       "super",        "while",
-            // literals
-            "null",     "true",         "false"
-        };
-        for(String kw : kws)
-            s.add(kw);
-        keywords = Collections.unmodifiableSet(s);
+    /**
+     * Returns whether or not {@code s} is a keyword, boolean literal,
+     * or null literal in the latest source version.
+     *
+     * @param s the string to check
+     * @return {@code true} if {@code s} is a keyword, or boolean
+     * literal, or null literal, {@code false} otherwise.
+     * @jls 3.9 Keywords
+     * @jls 3.10.3 Boolean Literals
+     * @jls 3.10.7 The Null Literal
+     */
+    public static boolean isKeyword(CharSequence s) {
+        return isKeyword(s, latest());
     }
 
     /**
-     *  Returns whether or not {@code s} is a keyword or literal in the
-     *  latest source version.
+     * Returns whether or not {@code s} is a keyword, boolean literal,
+     * or null literal in the given source version.
      *
      * @param s the string to check
-     * @return {@code true} if {@code s} is a keyword or literal, {@code false} otherwise.
+     * @param version the version to use
+     * @return {@code true} if {@code s} is a keyword, or boolean
+     * literal, or null literal, {@code false} otherwise.
+     * @jls 3.9 Keywords
+     * @jls 3.10.3 Boolean Literals
+     * @jls 3.10.7 The Null Literal
+     * @since 9
      */
-    public static boolean isKeyword(CharSequence s) {
-        return keywords.contains(s.toString());
+    public static boolean isKeyword(CharSequence s, SourceVersion version) {
+        String id = s.toString();
+        switch(id) {
+            // A trip through history
+        case "strictfp":
+            return version.compareTo(RELEASE_2) >= 0;
+
+        case "assert":
+            return version.compareTo(RELEASE_4) >= 0;
+
+        case "enum":
+            return version.compareTo(RELEASE_5) >= 0;
+
+        case "_":
+            return version.compareTo(RELEASE_9) >= 0;
+
+            // Keywords common across versions
+
+            // Modifiers
+        case "public":    case "protected": case "private":
+        case "abstract":  case "static":    case "final":
+        case "transient": case "volatile":  case "synchronized":
+        case "native":
+
+            // Declarations
+        case "class":     case "interface": case "extends":
+        case "package":   case "throws":    case "implements":
+
+            // Primitive types and void
+        case "boolean":   case "byte":      case "char":
+        case "short":     case "int":       case "long":
+        case "float":     case "double":
+        case "void":
+
+            // Control flow
+        case "if":      case "else":
+        case "try":     case "catch":    case "finally":
+        case "do":      case "while":
+        case "for":     case "continue":
+        case "switch":  case "case":     case "default":
+        case "break":   case "throw":    case "return":
+
+            // Other keywords
+        case  "this":   case "new":      case "super":
+        case "import":  case "instanceof":
+
+            // Forbidden!
+        case "goto":        case "const":
+
+            // literals
+        case "null":         case "true":       case "false":
+            return true;
+
+        default:
+            return false;
+        }
     }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu May 26 12:32:24 2016 +0100
@@ -2666,7 +2666,7 @@
             @Override
             public boolean compatible(Type found, Type req, Warner warn) {
                 //return type must be compatible in both current context and assignment context
-                return chk.basicHandler.compatible(found, inferenceContext().asUndetVar(req), warn);
+                return chk.basicHandler.compatible(inferenceContext().asUndetVar(found), inferenceContext().asUndetVar(req), warn);
             }
 
             @Override
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Thu May 26 12:32:24 2016 +0100
@@ -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;
@@ -196,7 +194,7 @@
                 //inject return constraints earlier
                 doIncorporation(inferenceContext, warn); //propagation
 
-                boolean shouldPropagate = resultInfo.checkContext.inferenceContext().free(resultInfo.pt);
+                boolean shouldPropagate = shouldPropagate(mt.getReturnType(), resultInfo, inferenceContext);
 
                 InferenceContext minContext = shouldPropagate ?
                         inferenceContext.min(roots(mt, deferredAttrContext), true, warn) :
@@ -257,6 +255,13 @@
         }
     }
     //where
+        private boolean shouldPropagate(Type restype, Attr.ResultInfo target, InferenceContext inferenceContext) {
+            return target.checkContext.inferenceContext() != emptyContext && //enclosing context is a generic method
+                        inferenceContext.free(restype) && //return type contains inference vars
+                        (!inferenceContext.inferencevars.contains(restype) || //no eager instantiation is required (as per 18.5.2)
+                                !needsEagerInstantiation((UndetVar)inferenceContext.asUndetVar(restype), target.pt, inferenceContext));
+        }
+
         private List<Type> roots(MethodType mt, DeferredAttrContext deferredAttrContext) {
             ListBuffer<Type> roots = new ListBuffer<>();
             roots.add(mt.getReturnType());
@@ -311,7 +316,7 @@
                  */
                 saved_undet = inferenceContext.save();
                 if (allowGraphInference && !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) {
-                    boolean shouldPropagate = resultInfo.checkContext.inferenceContext().free(resultInfo.pt);
+                    boolean shouldPropagate = shouldPropagate(getReturnType(), resultInfo, inferenceContext);
 
                     InferenceContext minContext = shouldPropagate ?
                             inferenceContext.min(roots(asMethodType(), null), false, warn) :
@@ -396,8 +401,9 @@
             to = from.isPrimitive() ? from : syms.objectType;
         } else if (qtype.hasTag(UNDETVAR)) {
             if (resultInfo.pt.isReference()) {
-                to = generateReturnConstraintsUndetVarToReference(
-                        tree, (UndetVar)qtype, to, resultInfo, inferenceContext);
+                if (needsEagerInstantiation((UndetVar)qtype, to, inferenceContext)) {
+                    to = generateReferenceToTargetConstraint(tree, (UndetVar)qtype, to, resultInfo, inferenceContext);
+                }
             } else {
                 if (to.isPrimitive()) {
                     to = generateReturnConstraintsPrimitive(tree, (UndetVar)qtype, to,
@@ -441,9 +447,7 @@
         return types.boxedClass(to).type;
     }
 
-    private Type generateReturnConstraintsUndetVarToReference(JCTree tree,
-            UndetVar from, Type to, Attr.ResultInfo resultInfo,
-            InferenceContext inferenceContext) {
+    private boolean needsEagerInstantiation(UndetVar from, Type to, InferenceContext inferenceContext) {
         Type captureOfTo = types.capture(to);
         /* T is a reference type, but is not a wildcard-parameterized type, and either
          */
@@ -454,8 +458,7 @@
             for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) {
                 Type captureOfBound = types.capture(t);
                 if (captureOfBound != t) {
-                    return generateReferenceToTargetConstraint(tree, from, to,
-                            resultInfo, inferenceContext);
+                    return true;
                 }
             }
 
@@ -469,8 +472,7 @@
                             !inferenceContext.free(aLowerBound) &&
                             !inferenceContext.free(anotherLowerBound) &&
                             commonSuperWithDiffParameterization(aLowerBound, anotherLowerBound)) {
-                        return generateReferenceToTargetConstraint(tree, from, to,
-                            resultInfo, inferenceContext);
+                        return true;
                     }
                 }
             }
@@ -485,12 +487,11 @@
             for (Type t : from.getBounds(InferenceBound.EQ, InferenceBound.LOWER)) {
                 Type sup = types.asSuper(t, to.tsym);
                 if (sup != null && sup.isRaw()) {
-                    return generateReferenceToTargetConstraint(tree, from, to,
-                            resultInfo, inferenceContext);
+                    return true;
                 }
             }
         }
-        return to;
+        return false;
     }
 
     private boolean commonSuperWithDiffParameterization(Type t, Type s) {
@@ -1477,21 +1478,16 @@
                     //not a throws undet var
                     return false;
                 }
-                if (t.getBounds(InferenceBound.EQ, InferenceBound.LOWER, InferenceBound.UPPER)
-                            .diff(t.getDeclaredBounds()).nonEmpty()) {
-                    //not an unbounded undet var
-                    return false;
-                }
                 Infer infer = inferenceContext.infer;
-                for (Type db : t.getDeclaredBounds()) {
+                for (Type db : t.getBounds(InferenceBound.UPPER)) {
                     if (t.isInterface()) continue;
-                    if (infer.types.asSuper(infer.syms.runtimeExceptionType, db.tsym) != null) {
-                        //declared bound is a supertype of RuntimeException
-                        return true;
+                    if (infer.types.asSuper(infer.syms.runtimeExceptionType, db.tsym) == null) {
+                        //upper bound is not a supertype of RuntimeException - give up
+                        return false;
                     }
                 }
-                //declared bound is more specific then RuntimeException - give up
-                return false;
+
+                return true;
             }
 
             @Override
@@ -1655,12 +1651,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 +1665,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 +1714,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 +1728,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 +1786,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 +1804,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 +1823,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 +1841,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 +1861,8 @@
             /** the nodes in the inference graph */
             ArrayList<Node> nodes;
 
-            InferenceGraph(Map<Type, Set<Type>> optDeps) {
-                initNodes(optDeps);
+            InferenceGraph() {
+                initNodes();
             }
 
             /**
@@ -1946,7 +1904,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 +1913,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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java	Thu May 26 12:32:24 2016 +0100
@@ -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/JavacFileManager.java	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Thu May 26 12:32:24 2016 +0100
@@ -74,10 +74,10 @@
 import com.sun.tools.javac.util.DefinedBy.Api;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.ListBuffer;
-import com.sun.tools.javac.util.ModuleWrappers.Configuration;
-import com.sun.tools.javac.util.ModuleWrappers.Layer;
-import com.sun.tools.javac.util.ModuleWrappers.ModuleFinder;
-import com.sun.tools.javac.util.ModuleWrappers.ServiceLoaderHelper;
+import com.sun.tools.javac.util.JDK9Wrappers.Configuration;
+import com.sun.tools.javac.util.JDK9Wrappers.Layer;
+import com.sun.tools.javac.util.JDK9Wrappers.ModuleFinder;
+import com.sun.tools.javac.util.JDK9Wrappers.ServiceLoaderHelper;
 
 import static java.nio.file.FileVisitOption.FOLLOW_LINKS;
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java	Thu May 26 12:32:24 2016 +0100
@@ -1062,7 +1062,7 @@
                     return null;
                 }
 
-                if (p.getFileName().toString().endsWith(".jar")) {
+                if (p.getFileName().toString().endsWith(".jar") && fsInfo.exists(p)) {
                     try (FileSystem fs = FileSystems.newFileSystem(p, null)) {
                         Path moduleInfoClass = fs.getPath("module-info.class");
                         if (Files.exists(moduleInfoClass)) {
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu May 26 12:32:24 2016 +0100
@@ -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
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java	Thu May 26 12:32:24 2016 +0100
@@ -0,0 +1,255 @@
+/*
+ * 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
+ * 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.javac.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.ServiceLoader;
+
+/**
+ *  This class provides wrappers for classes and methods that are new in JDK 9, and which are not
+ *  available on older versions of the platform on which javac may be compiled and run.
+ *  In future releases, when javac is always compiled on JDK 9 or later, the use of these wrappers
+ *  can be replaced by use of the real underlying classes.
+ *
+ *  <p>Wrapper classes provide a subset of the API of the wrapped classes, as needed for use
+ *  in javac. Wrapper objects contain an {@code Object} reference to the underlying runtime object,
+ *  and {@code Class} and {@code Method} objects for obtaining or using such instances via
+ *  runtime reflection.  The {@code Class} and {@code Method} objects are set up on a per-class
+ *  basis, by an {@code init} method, which is called from static methods on the wrapper class,
+ *  or in the constructor, when instances are created.
+ *  <p>
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class JDK9Wrappers {
+
+    /**
+     * Helper class for new method in java.util.ServiceLoader.
+     */
+    public static final class ServiceLoaderHelper {
+        @SuppressWarnings("unchecked")
+        public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) {
+            try {
+                init();
+                Object result = loadMethod.invoke(null, layer.theRealLayer, service);
+                return (ServiceLoader<S>)result;
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                    | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        // -----------------------------------------------------------------------------------------
+
+        private static Method loadMethod = null;
+
+        private static void init() {
+            if (loadMethod == null) {
+                try {
+                    Class<?> layerClass = Layer.layerClass;
+                    loadMethod = ServiceLoader.class.getDeclaredMethod("load", layerClass, Class.class);
+                } catch (NoSuchMethodException | SecurityException ex) {
+                    throw new Abort(ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Wrapper class for java.lang.module.ModuleFinder.
+     */
+    public static class ModuleFinder {
+        private final Object theRealModuleFinder;
+
+        private ModuleFinder(Object moduleFinder) {
+            this.theRealModuleFinder = moduleFinder;
+            init();
+        }
+
+        public static ModuleFinder of(Path... dirs) {
+            try {
+                init();
+                Object result = ofMethod.invoke(null, (Object)dirs);
+                ModuleFinder mFinder = new ModuleFinder(result);
+                return mFinder;
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                    | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        // -----------------------------------------------------------------------------------------
+
+        private static Class<?> moduleFinderClass = null;
+        private static Method ofMethod;
+
+        static final Class<?> getModuleFinderClass() {
+            init();
+            return moduleFinderClass;
+        }
+
+        private static void init() {
+            if (moduleFinderClass == null) {
+                try {
+                    moduleFinderClass = Class.forName("java.lang.module.ModuleFinder", false, null);
+                    ofMethod = moduleFinderClass.getDeclaredMethod("of", Path[].class);
+                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
+                    throw new Abort(ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Wrapper class for java.lang.module.Configuration.
+     */
+    public static final class Configuration {
+        private final Object theRealConfiguration;
+
+        private Configuration(Object configuration) {
+            this.theRealConfiguration = configuration;
+            init();
+        }
+
+        public Configuration resolveRequiresAndUses(
+                ModuleFinder beforeFinder,
+                ModuleFinder afterFinder,
+                Collection<String> roots) {
+            try {
+                Object result = resolveRequiresAndUsesMethod.invoke(theRealConfiguration,
+                                    beforeFinder.theRealModuleFinder,
+                                    afterFinder.theRealModuleFinder,
+                                    roots
+                                );
+                Configuration configuration = new Configuration(result);
+                return configuration;
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                    | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        // -----------------------------------------------------------------------------------------
+
+        private static Class<?> configurationClass = null;
+        private static Method resolveRequiresAndUsesMethod;
+
+        static final Class<?> getConfigurationClass() {
+            init();
+            return configurationClass;
+        }
+
+        private static void init() {
+            if (configurationClass == null) {
+                try {
+                    configurationClass = Class.forName("java.lang.module.Configuration", false, null);
+                    Class<?> moduleFinderInterface = ModuleFinder.getModuleFinderClass();
+                    resolveRequiresAndUsesMethod = configurationClass.getDeclaredMethod("resolveRequiresAndUses",
+                                moduleFinderInterface,
+                                moduleFinderInterface,
+                                Collection.class
+                    );
+                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
+                    throw new Abort(ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Wrapper class for java.lang.module.Layer.
+     */
+    public static final class Layer {
+        private final Object theRealLayer;
+
+        private Layer(Object layer) {
+            this.theRealLayer = layer;
+        }
+
+        public static Layer boot() {
+            try {
+                init();
+                Object result = bootMethod.invoke(null);
+                Layer layer = new Layer(result);
+                return layer;
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                    | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        public Configuration configuration() {
+            try {
+                Object result = configurationMethod.invoke(theRealLayer);
+                Configuration configuration = new Configuration(result);
+                return configuration;
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                    | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        public Layer defineModulesWithOneLoader(Configuration configuration, ClassLoader parentClassLoader) {
+            try {
+                Object result = defineModulesWithOneLoaderMethod.invoke(
+                        theRealLayer, configuration.theRealConfiguration, parentClassLoader);
+                Layer layer = new Layer(result);
+                return layer;
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                    | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        // -----------------------------------------------------------------------------------------
+
+        private static Class<?> layerClass = null;
+        private static Method bootMethod;
+        private static Method defineModulesWithOneLoaderMethod;
+        private static Method configurationMethod;
+
+        private static void init() {
+            if (layerClass == null) {
+                try {
+                    layerClass = Class.forName("java.lang.reflect.Layer", false, null);
+                    bootMethod = layerClass.getDeclaredMethod("boot");
+                    defineModulesWithOneLoaderMethod = layerClass.getDeclaredMethod("defineModulesWithOneLoader",
+                                Configuration.getConfigurationClass(),
+                                ClassLoader.class);
+                    configurationMethod = layerClass.getDeclaredMethod("configuration");
+                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
+                    throw new Abort(ex);
+                }
+            }
+        }
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleWrappers.java	Tue May 24 11:59:42 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,259 +0,0 @@
-/*
- * 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
- * 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.javac.util;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.file.Path;
-import java.util.Collection;
-import java.util.ServiceLoader;
-
-/** This class provides wrappers for classes and methods that are new in JDK 9, and which are not
- *  available on older versions of the platform on which javac may be compiled and run.
- *  In future releases, when javac is always compiled on JDK 9 or later, the use of these wrappers
- *  can be replaced by use of the real underlying classes.
- */
-public class ModuleWrappers {
-    public static final class ServiceLoaderHelper {
-        @SuppressWarnings("unchecked")
-        public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) {
-            try {
-                Class<?> layerClass = LayerHelper.getLayerClass();
-                Method loadMethod = ServiceLoader.class
-                        .getDeclaredMethod("load", layerClass, Class.class);
-                Object result = loadMethod.invoke(ServiceLoader.class, layer.theRealLayer, service);
-                return (ServiceLoader<S>)result;
-            } catch (NoSuchMethodException |
-                    SecurityException |
-                    IllegalArgumentException |
-                    IllegalAccessException |
-                    InvocationTargetException ex) {
-                throw new Abort(ex);
-            }
-        }
-    }
-
-    public static class ModuleFinder {
-        Object theRealModuleFinder;
-
-        private ModuleFinder(Object moduleFinder) {
-            this.theRealModuleFinder = moduleFinder;
-        }
-
-        public static ModuleFinder of(Path... dirs) {
-            try {
-                Object result = ModuleFinderHelper.getOfMethod()
-                        .invoke(ModuleFinderHelper.moduleFinderInterface, (Object)dirs);
-                ModuleFinder mFinder = new ModuleFinder(result);
-                return mFinder;
-            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
-                throw new Abort(ex);
-            }
-        }
-    }
-
-    private static class ModuleFinderHelper {
-        static Method ofMethod = null;
-        static Class<?> moduleFinderInterface;
-
-        static Method getOfMethod() {
-            if (ModuleFinderHelper.ofMethod == null) {
-                try {
-                    getModuleFinderInterface();
-                    ofMethod = moduleFinderInterface.getDeclaredMethod("of", Path[].class);
-                } catch (NoSuchMethodException | SecurityException ex) {
-                    throw new Abort(ex);
-                }
-            }
-            return ofMethod;
-        }
-
-        static Class<?> getModuleFinderInterface() {
-            if (moduleFinderInterface == null) {
-                try {
-                    moduleFinderInterface = Class.forName("java.lang.module.ModuleFinder", false, ClassLoader.getSystemClassLoader());
-                } catch (ClassNotFoundException ex) {
-                    throw new Abort(ex);
-                }
-            }
-            return moduleFinderInterface;
-        }
-    }
-
-    public static final class Configuration {
-        Object theRealConfiguration;
-
-        private Configuration(Object configuration) {
-            this.theRealConfiguration = configuration;
-        }
-
-        public Configuration resolveRequiresAndUses(
-                ModuleFinder beforeFinder,
-                ModuleFinder afterFinder,
-                Collection<String> roots) {
-            try {
-                Object result = ConfigurationHelper.getResolveRequiresAndUses()
-                        .invoke(theRealConfiguration,
-                                    beforeFinder.theRealModuleFinder,
-                                    afterFinder.theRealModuleFinder,
-                                    roots
-                                );
-                Configuration configuration = new Configuration(result);
-                return configuration;
-            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
-                throw new Abort(ex);
-            }
-        }
-    }
-
-    private static class ConfigurationHelper {
-        static Method resolveRequiresAndUsesMethod;
-        static Class<?> configurationClass;
-
-        static Method getResolveRequiresAndUses() {
-            if (resolveRequiresAndUsesMethod == null) {
-                try {
-                    getConfigurationClass();
-                    Class<?> moduleFinderInterface = ModuleFinderHelper.getModuleFinderInterface();
-                    Class<?> configurationClass = ConfigurationHelper.getConfigurationClass();
-                    resolveRequiresAndUsesMethod = configurationClass.getDeclaredMethod("resolveRequiresAndUses",
-                                moduleFinderInterface,
-                                moduleFinderInterface,
-                                Collection.class
-                    );
-                } catch (NoSuchMethodException | SecurityException ex) {
-                    throw new Abort(ex);
-                }
-            }
-            return resolveRequiresAndUsesMethod;
-        }
-
-        static Class<?> getConfigurationClass() {
-            if (configurationClass == null) {
-                try {
-                    configurationClass = Class.forName("java.lang.module.Configuration", false, ClassLoader.getSystemClassLoader());
-                } catch (ClassNotFoundException ex) {
-                    throw new Abort(ex);
-                }
-            }
-            return configurationClass;
-        }
-    }
-
-    public static final class Layer {
-        Object theRealLayer;
-
-        private Layer(Object layer) {
-            this.theRealLayer = layer;
-        }
-
-        public static Layer boot() {
-            try {
-                Object result = LayerHelper.getBootMethod().invoke(LayerHelper.getLayerClass());
-                Layer layer = new Layer(result);
-                return layer;
-            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
-                throw new Abort(ex);
-            }
-        }
-
-        public Configuration configuration() {
-            try {
-                Object result = LayerHelper.getConfigurationMethod().invoke(theRealLayer);
-                Layer layer = new Layer(result);
-                return new Configuration(result);
-            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
-                throw new Abort(ex);
-            }
-        }
-
-        public Layer defineModulesWithOneLoader(Configuration configuration, ClassLoader parentClassLoader) {
-            try {
-                Object result = LayerHelper.getDefineModulesWithOneLoaderMethod()
-                        .invoke(theRealLayer, configuration.theRealConfiguration, parentClassLoader);
-                Layer layer = new Layer(result);
-                return layer;
-            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
-                throw new Abort(ex);
-            }
-        }
-
-    }
-
-    private static class LayerHelper {
-        static Class<?> layerClass;
-        static Method bootMethod;
-        static Method defineModulesWithOneLoaderMethod = null;
-        static Method configurationMethod;
-
-        static Class<?> getLayerClass() {
-            if (layerClass == null) {
-                try {
-                    layerClass = Class.forName("java.lang.reflect.Layer", false, ClassLoader.getSystemClassLoader());
-                } catch (ClassNotFoundException ex) {
-                    throw new Abort(ex);
-                }
-            }
-            return layerClass;
-        }
-
-        static Method getBootMethod() {
-            if (bootMethod == null) {
-                try {
-                    bootMethod = getLayerClass().getDeclaredMethod("boot");
-                } catch (NoSuchMethodException | SecurityException ex) {
-                    throw new Abort(ex);
-                }
-            }
-            return bootMethod;
-        }
-
-        static Method getDefineModulesWithOneLoaderMethod() {
-            if (defineModulesWithOneLoaderMethod == null) {
-                try {
-                    defineModulesWithOneLoaderMethod = getLayerClass().getDeclaredMethod("defineModulesWithOneLoader",
-                                ConfigurationHelper.getConfigurationClass(),
-                                ClassLoader.class
-                    );
-                } catch (NoSuchMethodException | SecurityException ex) {
-                    throw new Abort(ex);
-                }
-            }
-            return defineModulesWithOneLoaderMethod;
-        }
-
-        static Method getConfigurationMethod() {
-            if (configurationMethod == null) {
-                try {
-                    configurationMethod =  getLayerClass().getDeclaredMethod("configuration");
-                } catch (NoSuchMethodException | SecurityException ex) {
-                    throw new Abort(ex);
-                }
-            }
-            return configurationMethod;
-        }
-    }
-}
--- a/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/Configuration.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Configuration.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/MessageRetriever.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Dependencies.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java	Thu May 26 12:32:24 2016 +0100
@@ -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,71 @@
                     target, targetArchive.getName());
         }
     }
+
+    static final JdkInternals REMOVED_JDK_INTERNALS = new JdkInternals();
+
+    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 isJDK() {
+            return true;
+        }
+
+        @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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Archive.java	Thu May 26 12:32:24 2016 +0100
@@ -27,6 +27,7 @@
 
 import com.sun.tools.classfile.Dependency.Location;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.net.URI;
@@ -38,11 +39,12 @@
 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.
  */
-public class Archive {
+public class Archive implements Closeable {
     public static Archive getInstance(Path p) {
         try {
             return new Archive(p, ClassFileReader.newInstance(p));
@@ -86,6 +88,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 +104,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()) {
@@ -164,6 +179,13 @@
     private boolean isJrt() {
         return location != null && location.getScheme().equals("jrt");
     }
+
+    @Override
+    public void close() throws IOException {
+        if (reader != null)
+            reader.close();
+    }
+
     interface Visitor {
         void visit(Location origin, Location target);
     }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Thu May 26 12:32:24 2016 +0100
@@ -29,6 +29,7 @@
 import com.sun.tools.classfile.ConstantPoolException;
 import com.sun.tools.classfile.Dependencies.ClassFileError;
 
+import java.io.Closeable;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -48,17 +49,18 @@
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * ClassFileReader reads ClassFile(s) of a given path that can be
  * a .class file, a directory, or a JAR file.
  */
-public class ClassFileReader {
+public class ClassFileReader implements Closeable {
     /**
      * Returns a ClassFileReader instance of a given path.
      */
     public static ClassFileReader newInstance(Path path) throws IOException {
-        if (!Files.exists(path)) {
+        if (Files.notExists(path)) {
             throw new FileNotFoundException(path.toString());
         }
 
@@ -173,7 +175,11 @@
 
     static boolean isClass(Path file) {
         String fn = file.getFileName().toString();
-        return fn.endsWith(".class") && !fn.equals(MODULE_INFO);
+        return fn.endsWith(".class");
+    }
+
+    @Override
+    public void close() throws IOException {
     }
 
     class FileIterator implements Iterator<ClassFile> {
@@ -218,13 +224,12 @@
         }
 
         protected Set<String> scan() {
-            try {
-                return Files.walk(path, Integer.MAX_VALUE)
-                        .filter(ClassFileReader::isClass)
-                        .map(f -> path.relativize(f))
-                        .map(Path::toString)
-                        .map(p -> p.replace(File.separatorChar, '/'))
-                        .collect(Collectors.toSet());
+            try (Stream<Path> stream = Files.walk(path, Integer.MAX_VALUE)) {
+                return stream.filter(ClassFileReader::isClass)
+                             .map(f -> path.relativize(f))
+                             .map(Path::toString)
+                             .map(p -> p.replace(File.separatorChar, '/'))
+                             .collect(Collectors.toSet());
             } catch (IOException e) {
                 throw new UncheckedIOException(e);
             }
@@ -235,7 +240,7 @@
                 int i = name.lastIndexOf('.');
                 String pathname = name.replace(".", fsSep) + ".class";
                 Path p = path.resolve(pathname);
-                if (!Files.exists(p)) {
+                if (Files.notExists(p)) {
                     p = path.resolve(pathname.substring(0, i) + "$" +
                             pathname.substring(i+1, pathname.length()));
                 }
@@ -261,13 +266,16 @@
         }
 
         class DirectoryIterator implements Iterator<ClassFile> {
-            private List<Path> entries;
+            private final List<Path> entries;
             private int index = 0;
             DirectoryIterator() throws IOException {
-                entries = Files.walk(path, Integer.MAX_VALUE)
-                               .filter(ClassFileReader::isClass)
-                               .collect(Collectors.toList());
-                index = 0;
+                List<Path> paths = null;
+                try (Stream<Path> stream = Files.walk(path, Integer.MAX_VALUE)) {
+                    paths = stream.filter(ClassFileReader::isClass)
+                                  .collect(Collectors.toList());
+                }
+                this.entries = paths;
+                this.index = 0;
             }
 
             public boolean hasNext() {
@@ -303,10 +311,15 @@
             this.jarfile = jf;
         }
 
+        @Override
+        public void close() throws IOException {
+            jarfile.close();
+        }
+
         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 +422,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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java	Thu May 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -0,0 +1,392 @@
+/*
+ * 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,
+        JDK_REMOVED_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 (module == Analyzer.REMOVED_JDK_INTERNALS) {
+                info = Info.JDK_REMOVED_INTERNAL_API;
+            } else 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 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -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 26 12:32:24 2016 +0100
@@ -0,0 +1,620 @@
+/*
+ * 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 implements AutoCloseable {
+    // 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);
+        }
+    }
+
+    /*
+     * Close all archives e.g. JarFile
+     */
+    @Override
+    public void close() throws IOException {
+        for (Archive archive : initialArchives)
+            archive.close();
+        for (Archive archive : classpathArchives)
+            archive.close();
+        for (Module module : nameToModule.values())
+            module.close();
+    }
+
+    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 (Stream<Path> stream = Files.walk(root, 1)) {
+                return stream.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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu May 26 12:32:24 2016 +0100
@@ -25,31 +25,30 @@
 
 package com.sun.tools.jdeps;
 
+import static com.sun.tools.jdeps.Analyzer.NOT_FOUND;
+import static com.sun.tools.jdeps.Analyzer.REMOVED_JDK_INTERNALS;
 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 +57,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 +77,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 +168,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 +178,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 +189,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 +203,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 +287,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 +318,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 +347,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 +366,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 +388,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 +406,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 +416,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 +434,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 +447,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 +458,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 +476,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 +493,216 @@
             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 {
+        try (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))));
 
-        // otherwise analyze the dependencies
-        if (options.genModuleInfo != null) {
-            return genModuleInfo(dependencyFinder);
-        } else {
-            return analyzeDeps(dependencyFinder);
-        }
-    }
+            // -genmoduleinfo
+            if (options.genModuleInfo != null) {
+                return genModuleInfo(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);
+            // -check
+            if (options.checkModuleDeps != null) {
+                return new ModuleAnalyzer(config, log, options.checkModuleDeps).run();
+            }
 
-        // add modules to dependency finder for analysis
-        Map<String, Module> modules = modulePaths.getModules();
-        modules.values().stream()
-               .forEach(dependencyFinder::addModule);
+            if (options.dotOutputDir != null &&
+                (options.verbose == SUMMARY || options.verbose == MODULE) &&
+                !options.addmods.isEmpty() && inputArgs.isEmpty()) {
+                return new ModuleAnalyzer(config, log).genDotFiles(options.dotOutputDir);
+            }
 
-        // 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);
-        }
-
-        // 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());
-        }
-
-        // classpath
-        for (Path p : getClassPaths(options.classpath)) {
-            if (Files.exists(p)) {
-                dependencyFinder.addClassPathArchive(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);
-                    }
-                }
+            if (options.inverse) {
+                return analyzeInverseDeps(config);
+            } else {
+                return analyzeDeps(config);
             }
         }
     }
 
-    private boolean analyzeDeps(DependencyFinder dependencyFinder) throws IOException {
-        JdepsFilter filter = dependencyFilter();
+    private JdepsConfiguration buildConfig() throws IOException {
+        JdepsConfiguration.Builder builder =
+            new JdepsConfiguration.Builder(options.systemModulePath);
 
-        // parse classfiles and find all dependencies
-        findDependencies(dependencyFinder, filter, options.apiOnly);
+        builder.upgradeModulePath(options.upgradeModulePath)
+               .appModulePath(options.modulePath)
+               .addmods(options.addmods);
 
-        // analyze the dependencies collected
-        Analyzer analyzer = new Analyzer(options.verbose, filter);
-        analyzer.run(dependencyFinder.archives());
+        if (options.checkModuleDeps != null) {
+            // check all system modules in the image
+            builder.allModules();
+        }
 
+        if (options.classpath != null)
+            builder.addClassPath(options.classpath);
+
+        // build the root set of archives to be analyzed
+        for (String s : inputArgs) {
+            Path p = Paths.get(s);
+            if (Files.exists(p)) {
+                builder.addRoot(p);
+            }
+        }
+
+        return builder.build();
+    }
+
+    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("ERROR: missing dependencies");
+            builder.visitMissingDeps(
+                new Analyzer.Visitor() {
+                    @Override
+                    public void visitDependence(String origin, Archive originArchive,
+                                                String target, Archive targetArchive) {
+                        if (builder.notFound(targetArchive))
+                            log.format("   %-50s -> %-50s %s%n",
+                                origin, target, targetArchive.getName());
+                    }
+                });
+        }
+        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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsWriter.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java	Thu May 26 12:32:24 2016 +0100
@@ -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(Set.of(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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleAnalyzer.java	Thu May 26 12:32:24 2016 +0100
@@ -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(Set.of(MANDATED), JAVA_BASE);
+
+            requiresPublic.stream()
+                .filter(m -> !m.name().equals(JAVA_BASE))
+                .map(Module::name)
+                .forEach(mn -> builder.requires(Set.of(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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java	Thu May 26 12:32:24 2016 +0100
@@ -24,15 +24,25 @@
  */
 package com.sun.tools.jdeps;
 
-import static com.sun.tools.jdeps.Analyzer.Type.CLASS;
-import static com.sun.tools.jdeps.Analyzer.NOT_FOUND;
-import static com.sun.tools.jdeps.Module.trace;
+import static com.sun.tools.jdeps.JdepsTask.*;
+import static com.sun.tools.jdeps.Analyzer.*;
+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.Collections;
+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 +50,189 @@
 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);
+
+    // an input JAR file (loaded as an automatic module for analysis)
+    // maps to an explicit module to generate module-info.java
+    final Map<Module, Module> automaticToExplicitModule;
+    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, 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 explicit module
+        this.automaticToExplicitModule = ModuleFinder.of(paths.toArray(new Path[0]))
+                .findAll().stream()
+                .map(configuration::toModule)
+                .collect(Collectors.toMap(Function.identity(), Function.identity()));
+
+        Optional<Module> om = automaticToExplicitModule.keySet().stream()
+                                    .filter(m -> !m.descriptor().isAutomatic())
+                                    .findAny();
+        if (om.isPresent()) {
+            throw new UncheckedBadArgs(new BadArgs("err.genmoduleinfo.not.jarfile",
+                                                   om.get().getPathName()));
+        }
+        if (automaticToExplicitModule.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());
+
+            boolean missingDeps = false;
+            for (Module m : automaticModules()) {
+                Set<Archive> apiDeps = requiresPublic.containsKey(m)
+                                            ? requiresPublic.get(m)
+                                            : Collections.emptySet();
+
+                Path file = outputdir.resolve(m.name()).resolve("module-info.java");
+
+                // computes requires and requires public
+                Module explicitModule = toExplicitModule(m, apiDeps);
+                if (explicitModule != null) {
+                    automaticToExplicitModule.put(m, explicitModule);
+
+                    // generate module-info.java
+                    System.out.format("writing to %s%n", file);
+                    writeModuleInfo(file,  explicitModule.descriptor());
+                } else {
+                    // find missing dependences
+                    System.out.format("Missing dependence: %s not generated%n", file);
+                    missingDeps = true;
+                }
+            }
+
+            return !missingDeps;
+        } finally {
+            dependencyFinder.shutdown();
+        }
+    }
+
+    boolean notFound(Archive m) {
+        return m == NOT_FOUND || m == REMOVED_JDK_INTERNALS;
+    }
+
+    private Module toExplicitModule(Module module, Set<Archive> requiresPublic)
+        throws IOException
+    {
+        // done analysis
+        module.close();
+
+        if (analyzer.requires(module).anyMatch(this::notFound)) {
+            // missing dependencies
+            return null;
+        }
+
+        Map<String, Boolean> requires = new HashMap<>();
+        requiresPublic.stream()
+            .map(Archive::getModule)
+            .forEach(m -> requires.put(m.name(), Boolean.TRUE));
+
+        analyzer.requires(module)
+            .map(Archive::getModule)
+            .forEach(d -> requires.putIfAbsent(d.name(), Boolean.FALSE));
+
+        return module.toStrictModule(requires);
+    }
+
+    /**
+     * Returns the stream of resulting modules
+     */
+    Stream<Module> modules() {
+        return automaticToExplicitModule.values().stream();
+    }
+
+    /**
+     * Returns the stream of resulting ModuleDescriptors
+     */
+    public Stream<ModuleDescriptor> descriptors() {
+        return automaticToExplicitModule.entrySet().stream()
+                    .map(Map.Entry::getValue)
+                    .map(Module::descriptor);
+    }
+
+    void visitMissingDeps(Analyzer.Visitor visitor) {
+        automaticModules().stream()
+            .filter(m -> analyzer.requires(m).anyMatch(this::notFound))
+            .forEach(m -> {
+                analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE);
+            });
+    }
+
+    void writeModuleInfo(Path file, ModuleDescriptor descriptor) {
+        try {
+            Files.createDirectories(file.getParent());
+            try (PrintWriter pw = new PrintWriter(Files.newOutputStream(file))) {
+                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 automaticToExplicitModule.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	Tue May 24 11:59:42 2016 -0700
+++ /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.of(), 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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Thu May 26 12:32:24 2016 +0100
@@ -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	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdkinternals.properties	Thu May 26 12:32:24 2016 +0100
@@ -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,11 +8,16 @@
 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
-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
+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.CausedFocusEvent=Use java.awt.event.FocusEvent::getCause @since 9
+sun.font.FontUtilities=See java.awt.Font.textRequiresLayout	@since 9
+sun.reflect.Reflection=Use java.lang.StackWalker @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
@@ -21,5 +25,17 @@
 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
+# 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.jpeg=Use javax.imageio @since 1.4
+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.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/debug/InternalDebugControl.java	Tue May 24 11:59:42 2016 -0700
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/debug/InternalDebugControl.java	Thu May 26 12:32:24 2016 +0100
@@ -23,24 +23,60 @@
 
 package jdk.internal.jshell.debug;
 
+import java.io.PrintStream;
 import java.util.HashMap;
 import java.util.Map;
 import jdk.jshell.JShell;
 
 /**
- * Used to externally control output messages for debugging the implementation
- * of the JShell API.  This is NOT a supported interface,
- * @author Robert Field
+/**
+ * This class is used to externally control output messages for debugging the
+ * implementation of the JShell API.
+ * <p>
+ * This is not part of the SPI, not API.
  */
 public class InternalDebugControl {
-    public static final int DBG_GEN   = 0b0000001;
-    public static final int DBG_FMGR  = 0b0000010;
+
+    /**
+     * This is a static only class; The constructor should never be called.
+     */
+    private InternalDebugControl() {
+    }
+
+    /**
+     * General debugging.
+     */
+    public static final int DBG_GEN = 0b0000001;
+
+    /**
+     * File manager debuging.
+     */
+    public static final int DBG_FMGR = 0b0000010;
+
+    /**
+     * Completion analysis debugging.
+     */
     public static final int DBG_COMPA = 0b0000100;
-    public static final int DBG_DEP   = 0b0001000;
-    public static final int DBG_EVNT  = 0b0010000;
+
+    /**
+     * Dependency debugging.
+     */
+    public static final int DBG_DEP = 0b0001000;
+
+    /**
+     * Event debugging.
+     */
+    public static final int DBG_EVNT = 0b0010000;
 
     private static Map<JShell, Integer> debugMap = null;
 
+    /**
+     * Sets which debug flags are enabled for a given JShell instance. The flags
+     * are or'ed bits as defined in {@code DBG_*}.
+     *
+     * @param state the JShell instance
+     * @param flags the or'ed debug bits
+     */
     public static void setDebugFlags(JShell state, int flags) {
         if (debugMap == null) {
             debugMap = new HashMap<>();
@@ -48,7 +84,14 @@
         debugMap.put(state, flags);
     }
 
-    public static boolean debugEnabled(JShell state, int flag) {
+    /**
+     * Tests if any of the specified debug flags are enabled.
+     *
+     * @param state the JShell instance
+     * @param flag the {@code DBG_*} bits to check
+     * @return true if any of the flags are enabled
+     */
+    public static boolean isDebugEnabled(JShell state, int flag) {
         if (debugMap == null) {
             return false;
         }
@@ -58,4 +101,34 @@
         }
         return (flags & flag) != 0;
     }
+
+    /**
+     * Displays debug info if the specified debug flags are enabled.
+     *
+     * @param state the current JShell instance
+     * @param err the {@code PrintStream} to report on
+     * @param flags {@code DBG_*} flag bits to check
+     * @param format format string for the output
+     * @param args args for the format string
+     */
+    public static void debug(JShell state, PrintStream err, int flags, String format, Object... args) {
+        if (isDebugEnabled(state, flags)) {
+            err.printf(format, args);
+        }
+    }
+
+    /**
+     * Displays a fatal exception as debug info.
+     *
+     * @param state the current JShell instance
+     * @param err the {@code PrintStream} to report on
+     * @param ex the fatal Exception
+     * @param where additional context
+     */
+    public static void debug(JShell state, PrintStream err, Exception ex, String where) {
+        if (isDebugEnabled(state, 0xFFFFFFFF)) {
+            err.printf("Fatal error: %s: %s\n", where, ex.getMessage());
+            ex.printStackTrace(err);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/ClassTracker.java	Thu May 26 12:32:24 2016 +0100
@@ -0,0 +1,129 @@
+/*
+ * 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 jdk.internal.jshell.jdi;
+
+import java.util.HashMap;
+import java.util.Objects;
+import com.sun.jdi.ReferenceType;
+import java.util.List;
+
+/**
+ * Tracks the state of a class.
+ */
+class ClassTracker {
+
+    private final JDIEnv jdiEnv;
+    private final HashMap<String, ClassInfo> map;