Merge
authorprappo
Mon, 19 Dec 2016 16:05:38 +0000
changeset 42766 1bd6808c38fd
parent 42765 2bdc3e9c3a81 (current diff)
parent 42764 5f368ec0cbb4 (diff)
child 42767 8ea2f3d10b8c
Merge
jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java
jdk/src/java.base/share/classes/java/lang/module/ModulePath.java
jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java
jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java
jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java
--- a/jdk/make/copy/Copy-java.base.gmk	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/copy/Copy-java.base.gmk	Mon Dec 19 16:05:38 2016 +0000
@@ -100,8 +100,7 @@
   # Allow override by ALT_JVMCFG_SRC if it exists
   JVMCFG_SRC := $(if $(wildcard $(ALT_JVMCFG_SRC)),$(ALT_JVMCFG_SRC),$(JVMCFG_SRC))
 endif
-JVMCFG_DIR := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR)
-JVMCFG := $(JVMCFG_DIR)/jvm.cfg
+JVMCFG := $(LIB_DST_DIR)/jvm.cfg
 
 # To do: should this also support -zeroshark?
 
--- a/jdk/make/copy/Copy-java.desktop.gmk	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/copy/Copy-java.desktop.gmk	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 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
@@ -64,7 +64,7 @@
   ifeq ($(OPENJDK_TARGET_OS), windows)
     FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype)
   else
-    FREETYPE_TARGET_LIB := $(LIB_DST_DIR)$(OPENJDK_TARGET_CPU_LIBDIR)/$(call SHARED_LIBRARY,freetype).6
+    FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype).6
   endif
 
   # We can't use $(install-file) in this rule because it preserves symbolic links and
--- a/jdk/make/launcher/Launcher-java.base.gmk	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/launcher/Launcher-java.base.gmk	Mon Dec 19 16:05:38 2016 +0000
@@ -74,7 +74,7 @@
 BUILD_JEXEC :=
 BUILD_JEXEC_SRC :=
 BUILD_JEXEC_INC :=
-BUILD_JEXEC_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
+BUILD_JEXEC_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
 
 #
 # UNHANDLED:
@@ -138,7 +138,7 @@
 BUILD_JSPAWNHELPER :=
 BUILD_JSPAWNHELPER_SRC := $(JDK_TOPDIR)/src/java.base/unix/native/jspawnhelper
 JSPAWNHELPER_CFLAGS := -I$(JDK_TOPDIR)/src/java.base/unix/native/libjava
-BUILD_JSPAWNHELPER_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
+BUILD_JSPAWNHELPER_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
 LINK_JSPAWNHELPER_OBJECTS := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjava/childproc.o
 BUILD_JSPAWNHELPER_LDFLAGS :=
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/launcher/Launcher-jdk.aot.gmk	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+include LauncherCommon.gmk
+
+$(eval $(call SetupBuildLauncher, jaotc, \
+    MAIN_CLASS := jdk.tools.jaotc.Main, \
+    JAVA_ARGS := -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI \
+        -XX:+UseAOT \
+        -Djvmci.UseProfilingInformation=false \
+        -Dgraal.UseExceptionProbability=false \
+        -Djvmci.Compiler=graal \
+        --add-modules ALL-DEFAULT \
+    , \
+))
--- a/jdk/make/launcher/LauncherCommon.gmk	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/launcher/LauncherCommon.gmk	Mon Dec 19 16:05:38 2016 +0000
@@ -32,13 +32,13 @@
   ifeq ($(OPENJDK_TARGET_OS), windows)
     DISABLE_MAPFILES := true
   endif
-  ORIGIN_ARG := $(call SET_EXECUTABLE_ORIGIN,/../lib$(OPENJDK_TARGET_CPU_LIBDIR)/jli)
+  ORIGIN_ARG := $(call SET_EXECUTABLE_ORIGIN,/../lib/jli)
 
   # Applications expect to be able to link against libjawt without invoking
   # System.loadLibrary("jawt") first. This was the behaviour described in the
   # devloper documentation of JAWT and what worked with OpenJDK6.
   ifneq ($(findstring $(OPENJDK_TARGET_OS), linux solaris), )
-    ORIGIN_ARG += $(call SET_EXECUTABLE_ORIGIN,/../lib$(OPENJDK_TARGET_CPU_LIBDIR))
+    ORIGIN_ARG += $(call SET_EXECUTABLE_ORIGIN,/../lib)
   endif
 endif
 
@@ -190,9 +190,9 @@
           $$(ORIGIN_ARG) \
           $$($1_LDFLAGS), \
       LDFLAGS_linux := \
-          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
+          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli, \
       LDFLAGS_solaris := $$($1_LDFLAGS_solaris) \
-          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \
+          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli, \
       MAPFILE := $$($1_MAPFILE), \
       LIBS := $(JDKEXE_LIBS) $$($1_LIBS), \
       LIBS_unix := $$($1_LIBS_unix), \
--- a/jdk/make/lib/Awt2dLibraries.gmk	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/lib/Awt2dLibraries.gmk	Mon Dec 19 16:05:38 2016 +0000
@@ -418,6 +418,7 @@
     DISABLED_WARNINGS_gcc := format-nonliteral type-limits misleading-indentation, \
     DISABLED_WARNINGS_clang := tautological-compare, \
     DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \
+    DISABLED_WARNINGS_microsoft := 4819, \
     MAPFILE := $(JDK_TOPDIR)/make/mapfiles/liblcms/mapfile-vers, \
     LDFLAGS := $(LDFLAGS_JDKLIB) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
@@ -681,7 +682,7 @@
     DISABLED_WARNINGS_CXX_solstudio := \
         truncwarn wvarhidenmem wvarhidemem wbadlkginit identexpected \
         hidevf w_novirtualdescr arrowrtn2, \
-    DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146 4334, \
+    DISABLED_WARNINGS_microsoft := 4267 4244 4018 4090 4996 4146 4334 4819, \
     MAPFILE := $(BUILD_LIBFONTMANAGER_MAPFILE), \
     LDFLAGS := $(subst -Wl$(COMMA)-z$(COMMA)defs,,$(LDFLAGS_JDKLIB)) $(LDFLAGS_CXX_JDK) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
--- a/jdk/make/lib/CoreLibraries.gmk	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/lib/CoreLibraries.gmk	Mon Dec 19 16:05:38 2016 +0000
@@ -340,9 +340,6 @@
 
 LIBJLI_CFLAGS += $(addprefix -I, $(LIBJLI_SRC_DIRS))
 
-# Append defines depending on target platform
-LIBJLI_CFLAGS += $(OPENJDK_TARGET_CPU_JLI_CFLAGS)
-
 ifneq ($(USE_EXTERNAL_LIBZ), true)
   LIBJLI_CFLAGS += $(ZLIB_CPPFLAGS)
   LIBJLI_EXTRA_FILES += \
--- a/jdk/make/mapfiles/libjava/mapfile-vers	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/mapfiles/libjava/mapfile-vers	Mon Dec 19 16:05:38 2016 +0000
@@ -150,7 +150,6 @@
 		Java_java_lang_StrictMath_atan;
 		Java_java_lang_StrictMath_atan2;
 		Java_java_lang_StrictMath_cos;
-		Java_java_lang_StrictMath_exp;
 		Java_java_lang_StrictMath_log;
 		Java_java_lang_StrictMath_log10;
 		Java_java_lang_StrictMath_sin;
--- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Mon Dec 19 16:05:38 2016 +0000
@@ -26,6 +26,7 @@
 package build.tools.jigsaw;
 
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
@@ -44,7 +45,8 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.Function;
-import java.util.stream.Collectors;
+
+import static java.util.stream.Collectors.*;
 import static java.lang.module.ModuleDescriptor.Requires.Modifier.TRANSITIVE;
 
 /**
@@ -69,42 +71,25 @@
                                   .map(ModuleReference::descriptor)
                                   .filter(m -> (m.name().startsWith("java.") &&
                                                !m.name().equals("java.smartcardio")))
-                                  .collect(Collectors.toSet()));
+                                  .collect(toSet()));
         Set<ModuleDescriptor> jdkModules
             = new TreeSet<>(finder.findAll().stream()
                                   .map(ModuleReference::descriptor)
                                   .filter(m -> !javaSEModules.contains(m))
-                                  .collect(Collectors.toSet()));
+                                  .collect(toSet()));
 
-        GenGraphs genGraphs = new GenGraphs(javaSEModules, jdkModules);
+        GenGraphs genGraphs = new GenGraphs(dir, javaSEModules, jdkModules);
         Set<String> mods = new HashSet<>();
         for (ModuleReference mref: finder.findAll()) {
-            ModuleDescriptor descriptor = mref.descriptor();
-            String name = descriptor.name();
-            mods.add(name);
-            Configuration cf = Configuration.empty()
-                    .resolveRequires(finder,
-                                     ModuleFinder.of(),
-                                     Set.of(name));
-            genGraphs.genDotFile(dir, name, cf);
+            mods.add(mref.descriptor().name());
+            genGraphs.genDotFile(mref);
         }
 
-        Configuration cf = Configuration.empty()
-                .resolveRequires(finder,
-                                 ModuleFinder.of(),
-                                 mods);
-        genGraphs.genDotFile(dir, "jdk", cf);
+        // all modules
+        genGraphs.genDotFile("jdk", mods);
 
     }
 
-    private final Set<ModuleDescriptor> javaGroup;
-    private final Set<ModuleDescriptor> jdkGroup;
-
-    GenGraphs(Set<ModuleDescriptor> javaGroup, Set<ModuleDescriptor> jdkGroup) {
-        this.javaGroup = Collections.unmodifiableSet(javaGroup);
-        this.jdkGroup = Collections.unmodifiableSet(jdkGroup);
-    }
-
     private static final String ORANGE = "#e76f00";
     private static final String BLUE = "#437291";
     private static final String GRAY = "#dddddd";
@@ -145,23 +130,70 @@
 
     }
 
-    private void genDotFile(Path dir, String name, Configuration cf) throws IOException {
-        try (PrintStream out
-                 = new PrintStream(Files.newOutputStream(dir.resolve(name + ".dot")))) {
+    private final Path dir;
+    private final Set<ModuleDescriptor> javaGroup;
+    private final Set<ModuleDescriptor> jdkGroup;
+
+    GenGraphs(Path dir, Set<ModuleDescriptor> javaGroup, Set<ModuleDescriptor> jdkGroup) {
+        this.dir = dir;
+        this.javaGroup = Collections.unmodifiableSet(javaGroup);
+        this.jdkGroup = Collections.unmodifiableSet(jdkGroup);
+    }
+
+    /**
+     * Generates a dot file for the given module reference as the root.
+     */
+    void genDotFile(ModuleReference mref) throws IOException {
+        String name = mref.descriptor().name();
+        genDotFile(name, Set.of(name));
+    }
+
+    /**
+     * Generates a dot file for the given set of root modules.
+     */
+    void genDotFile(String name, Set<String> roots) throws IOException {
+        Configuration cf =
+            Configuration.empty().resolveRequires(ModuleFinder.ofSystem(),
+                                                  ModuleFinder.of(),
+                                                  roots);
+
+        Set<ModuleDescriptor> mds = cf.modules().stream()
+                .map(ResolvedModule::reference)
+                .map(ModuleReference::descriptor)
+                .collect(toSet());
 
-            Map<String, ModuleDescriptor> nameToModule;
-            if (name.equals("java.se.ee")) {
-                nameToModule = cf.modules().stream()
-                    .map(ResolvedModule::reference)
-                    .map(ModuleReference::descriptor)
-                    .filter(md -> !md.name().startsWith("jdk."))
-                    .collect(Collectors.toMap(ModuleDescriptor::name, Function.identity()));
-            } else {
-                nameToModule = cf.modules().stream()
-                    .map(ResolvedModule::reference)
-                    .map(ModuleReference::descriptor)
-                    .collect(Collectors.toMap(ModuleDescriptor::name, Function.identity()));
+        // generate a dot file for the resolved graph
+        try (OutputStream os = Files.newOutputStream(dir.resolve(name + ".dot"));
+             PrintStream out = new PrintStream(os)) {
+            printGraph(out, name, gengraph(cf),
+                       mds.stream()
+                          .collect(toMap(ModuleDescriptor::name, Function.identity()))
+            );
+        }
+
+        if (name.equals("java.se") || name.equals("java.se.ee")) {
+            // generate a dot file for Java SE module graph
+            try (OutputStream os = Files.newOutputStream(dir.resolve(name + "-spec.dot"));
+                 PrintStream out = new PrintStream(os)) {
+                // transitive reduction on the graph of `requires transitive` edges
+                // filter out jdk.* modules which are implementation dependences
+                Graph<String> graph = requiresTransitiveGraph(cf, true);
+                printGraph(out, name, graph,
+                           mds.stream()
+                              .filter(md -> !md.name().startsWith("jdk.") &&
+                                                graph.nodes().contains(md.name()))
+                              .collect(toMap(ModuleDescriptor::name, Function.identity()))
+                );
             }
+        }
+    }
+
+    private void printGraph(PrintStream out,
+                            String name,
+                            Graph<String> graph,
+                            Map<String, ModuleDescriptor> nameToModule)
+        throws IOException
+    {
             Set<ModuleDescriptor> descriptors = new TreeSet<>(nameToModule.values());
 
             out.format("digraph \"%s\" {%n", name);
@@ -182,13 +214,13 @@
 
             // same ranks
             ranks.stream()
-                .forEach(group -> out.format("{rank=same %s}%n",
-                    descriptors.stream()
-                        .map(ModuleDescriptor::name)
-                        .filter(group::contains)
-                        .map(mn -> "\"" + mn + "\"")
-                        .collect(Collectors.joining(","))
-                ));
+                .map(group -> descriptors.stream()
+                                         .map(ModuleDescriptor::name)
+                                         .filter(group::contains)
+                                         .map(mn -> "\"" + mn + "\"")
+                                         .collect(joining(",")))
+                .filter(group -> group.length() > 0)
+                .forEach(group -> out.format("{rank=same %s}%n", group));
 
             descriptors.stream()
                 .filter(jdkGroup::contains)
@@ -196,30 +228,28 @@
                 .forEach(mn -> out.format("  \"%s\" [fontcolor=\"%s\", group=%s];%n",
                                           mn, BLUE, "jdk"));
 
-            // transitive reduction
-            Graph<String> graph = gengraph(cf);
-            descriptors.forEach(md -> {
-                String mn = md.name();
-                Set<String> requiresTransitive = md.requires().stream()
-                        .filter(d -> d.modifiers().contains(TRANSITIVE))
-                        .map(d -> d.name())
-                        .collect(Collectors.toSet());
+            descriptors.stream()
+                .forEach(md -> {
+                    String mn = md.name();
+                    Set<String> requiresTransitive = md.requires().stream()
+                            .filter(d -> d.modifiers().contains(TRANSITIVE))
+                            .map(d -> d.name())
+                            .collect(toSet());
 
-                graph.adjacentNodes(mn)
-                     .stream()
-                     .filter(nameToModule::containsKey)
-                     .forEach(dn -> {
-                         String attr = dn.equals("java.base") ? REQUIRES_BASE
-                                : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
-                         int w = weightOf(mn, dn);
-                         if (w > 1)
-                             attr += "weight=" + w;
-                         out.format("  \"%s\" -> \"%s\" [%s];%n", mn, dn, attr);
-                     });
-            });
+                    graph.adjacentNodes(mn)
+                         .stream()
+                         .filter(nameToModule::containsKey)
+                         .forEach(dn -> {
+                             String attr = dn.equals("java.base") ? REQUIRES_BASE
+                                    : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
+                             int w = weightOf(mn, dn);
+                             if (w > 1)
+                                 attr += "weight=" + w;
+                             out.format("  \"%s\" -> \"%s\" [%s];%n", mn, dn, attr);
+                         });
+                });
 
             out.println("}");
-        }
     }
 
     /**
@@ -239,7 +269,7 @@
                     .map(ResolvedModule::name)
                     .forEach(target -> builder.addEdge(mn, target));
         }
-        Graph<String> rpg = requiresTransitiveGraph(cf);
+        Graph<String> rpg = requiresTransitiveGraph(cf, false);
         return builder.build().reduce(rpg);
     }
 
@@ -247,13 +277,14 @@
      * Returns a Graph containing only requires transitive edges
      * with transitive reduction.
      */
-    private Graph<String> requiresTransitiveGraph(Configuration cf) {
+    private Graph<String> requiresTransitiveGraph(Configuration cf, boolean includeBase) {
         Graph.Builder<String> builder = new Graph.Builder<>();
         for (ResolvedModule resolvedModule : cf.modules()) {
             ModuleDescriptor descriptor = resolvedModule.reference().descriptor();
             String mn = descriptor.name();
             descriptor.requires().stream()
-                    .filter(d -> d.modifiers().contains(TRANSITIVE))
+                    .filter(d -> d.modifiers().contains(TRANSITIVE)
+                                    || (includeBase && d.name().equals("java.base")))
                     .map(d -> d.name())
                     .forEach(d -> builder.addEdge(mn, d));
         }
--- a/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/macosx/native/libjli/java_md_macosx.c	Mon Dec 19 16:05:38 2016 +0000
@@ -171,8 +171,6 @@
  * Main
  */
 
-#define GetArch() GetArchPath(CURRENT_DATA_MODEL)
-
 /* Store the name of the executable once computed */
 static char *execname = NULL;
 
@@ -184,16 +182,6 @@
     return execname;
 }
 
-const char *
-GetArchPath(int nbits)
-{
-    switch(nbits) {
-        default:
-            return LIBARCHNAME;
-    }
-}
-
-
 /*
  * Exports the JNI interface from libjli
  *
@@ -211,7 +199,7 @@
     if (sExportedJNIFunctions != NULL) return sExportedJNIFunctions;
 
     char jrePath[PATH_MAX];
-    jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE);
+    jboolean gotJREPath = GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE);
     if (!gotJREPath) {
         JLI_ReportErrorMessage("Failed to GetJREPath()");
         return NULL;
@@ -229,7 +217,7 @@
     }
 
     char jvmPath[PATH_MAX];
-    jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), GetArch(), CURRENT_DATA_MODEL);
+    jboolean gotJVMPath = GetJVMPath(jrePath, preferredJVM, jvmPath, sizeof(jvmPath), CURRENT_DATA_MODEL);
     if (!gotJVMPath) {
         JLI_ReportErrorMessage("Failed to GetJVMPath()");
         return NULL;
@@ -390,7 +378,6 @@
 
     /* Check data model flags, and exec process, if needed */
     {
-      char *arch        = (char *)GetArch(); /* like sparc or sparcv9 */
       char * jvmtype    = NULL;
       int  argc         = *pargc;
       char **argv       = *pargv;
@@ -462,7 +449,7 @@
          jvmpath does not exist */
       if (wanted == running) {
         /* Find out where the JRE is that we will be using. */
-        if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
+        if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
           JLI_ReportErrorMessage(JRE_ERROR1);
           exit(2);
         }
@@ -481,7 +468,7 @@
             exit(4);
         }
 
-        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, wanted)) {
+        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, wanted)) {
           JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
           exit(4);
         }
@@ -502,7 +489,7 @@
 #if defined(DUAL_MODE)
         if (running != wanted) {
           /* Find out where the JRE is that we will be using. */
-          if (!GetJREPath(jrepath, so_jrepath, GetArchPath(wanted), JNI_TRUE)) {
+          if (!GetJREPath(jrepath, so_jrepath, JNI_TRUE)) {
             /* give up and let other code report error message */
             JLI_ReportErrorMessage(JRE_ERROR2, wanted);
             exit(1);
@@ -526,7 +513,7 @@
           }
 
           /* exec child can do error checking on the existence of the path */
-          jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, GetArchPath(wanted), wanted);
+          jvmpathExists = GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, wanted);
         }
 #else /* ! DUAL_MODE */
         JLI_ReportErrorMessage(JRE_ERROR2, wanted);
@@ -579,7 +566,7 @@
  */
 static jboolean
 GetJVMPath(const char *jrepath, const char *jvmtype,
-           char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
+           char *jvmpath, jint jvmpathsize, int bitsWanted)
 {
     struct stat s;
 
@@ -613,7 +600,7 @@
  * Find path to JRE based on .exe's location or registry settings.
  */
 static jboolean
-GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
+GetJREPath(char *path, jint pathsize, jboolean speculative)
 {
     char libjava[MAXPATHLEN];
 
@@ -841,7 +828,7 @@
 void* SplashProcAddress(const char* name) {
     if (!hSplashLib) {
         char jrePath[PATH_MAX];
-        if (!GetJREPath(jrePath, sizeof(jrePath), GetArch(), JNI_FALSE)) {
+        if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
             JLI_ReportErrorMessage(JRE_ERROR1);
             return NULL;
         }
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/PackerImpl.java	Mon Dec 19 16:05:38 2016 +0000
@@ -317,7 +317,7 @@
                 this(null, je);
             }
             boolean isClassFile() {
-                if (!name.endsWith(".class")) {
+                if (!name.endsWith(".class") || name.endsWith("module-info.class")) {
                     return false;
                 }
                 for (String prefix = name;;) {
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Mon Dec 19 16:05:38 2016 +0000
@@ -14,15 +14,6 @@
 pack.class.attribute.SourceID = RUH
 pack.class.attribute.CompilationID = RUH
 
-# Module attributes, supported by the tool and not JSR-200
-pack.class.attribute.Module = RUHFHNH[RUHFH]NH[RUHFHNH[RUH]]NH[RUHFHNH[RUH]]NH[RCH]NH[RCHNH[RCH]]
-pack.class.attribute.ModulePackages = NH[RUH]
-pack.class.attribute.ModuleVersion = RUH
-pack.class.attribute.ModuleMainClass = RCH
-pack.class.attribute.ModuleTarget = RUHRUHRUH
-pack.class.attribute.ModuleHashes = RUHNH[RUHNH[B]]
-
-
 # Note:  Zero-length ("marker") attributes do not need to be specified here.
 # They are automatically defined to have an empty layout.
 #pack.class.attribute.Deprecated =
--- a/jdk/src/java.base/share/classes/java/lang/FdLibm.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/FdLibm.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -79,7 +79,8 @@
      */
     private static double __LO(double x, int low) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L)|low );
+        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L) |
+                                       (low    & 0x0000_0000_FFFF_FFFFL));
     }
 
     /**
@@ -96,7 +97,8 @@
      */
     private static double __HI(double x, int high) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL)|( ((long)high)) << 32 );
+        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL) |
+                                       ( ((long)high)) << 32 );
     }
 
     /**
@@ -580,4 +582,152 @@
             return s * z;
         }
     }
+
+    /**
+     * Returns the exponential of x.
+     *
+     * Method
+     *   1. Argument reduction:
+     *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+     *      Given x, find r and integer k such that
+     *
+     *               x = k*ln2 + r,  |r| <= 0.5*ln2.
+     *
+     *      Here r will be represented as r = hi-lo for better
+     *      accuracy.
+     *
+     *   2. Approximation of exp(r) by a special rational function on
+     *      the interval [0,0.34658]:
+     *      Write
+     *          R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+     *      We use a special Reme algorithm on [0,0.34658] to generate
+     *      a polynomial of degree 5 to approximate R. The maximum error
+     *      of this polynomial approximation is bounded by 2**-59. In
+     *      other words,
+     *          R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+     *      (where z=r*r, and the values of P1 to P5 are listed below)
+     *      and
+     *          |                  5          |     -59
+     *          | 2.0+P1*z+...+P5*z   -  R(z) | <= 2
+     *          |                             |
+     *      The computation of exp(r) thus becomes
+     *                             2*r
+     *              exp(r) = 1 + -------
+     *                            R - r
+     *                                 r*R1(r)
+     *                     = 1 + r + ----------- (for better accuracy)
+     *                                2 - R1(r)
+     *      where
+     *                               2       4             10
+     *              R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+     *
+     *   3. Scale back to obtain exp(x):
+     *      From step 1, we have
+     *         exp(x) = 2^k * exp(r)
+     *
+     * Special cases:
+     *      exp(INF) is INF, exp(NaN) is NaN;
+     *      exp(-INF) is 0, and
+     *      for finite argument, only exp(0)=1 is exact.
+     *
+     * Accuracy:
+     *      according to an error analysis, the error is always less than
+     *      1 ulp (unit in the last place).
+     *
+     * Misc. info.
+     *      For IEEE double
+     *          if x >  7.09782712893383973096e+02 then exp(x) overflow
+     *          if x < -7.45133219101941108420e+02 then exp(x) underflow
+     *
+     * Constants:
+     * The hexadecimal values are the intended ones for the following
+     * constants. The decimal values may be used, provided that the
+     * compiler will convert from decimal to binary accurately enough
+     * to produce the hexadecimal values shown.
+     */
+    static class Exp {
+        private static final double one     = 1.0;
+        private static final double[] half = {0.5, -0.5,};
+        private static final double huge    = 1.0e+300;
+        private static final double twom1000=     0x1.0p-1000;             //  9.33263618503218878990e-302 = 2^-1000
+        private static final double o_threshold=  0x1.62e42fefa39efp9;     //  7.09782712893383973096e+02
+        private static final double u_threshold= -0x1.74910d52d3051p9;     // -7.45133219101941108420e+02;
+        private static final double[] ln2HI   ={  0x1.62e42feep-1,         //  6.93147180369123816490e-01
+                                                 -0x1.62e42feep-1};        // -6.93147180369123816490e-01
+        private static final double[] ln2LO   ={  0x1.a39ef35793c76p-33,   //  1.90821492927058770002e-10
+                                                 -0x1.a39ef35793c76p-33};  // -1.90821492927058770002e-10
+        private static final double invln2 =      0x1.71547652b82fep0;     //  1.44269504088896338700e+00
+
+        private static final double P1   =  0x1.555555555553ep-3;  //  1.66666666666666019037e-01
+        private static final double P2   = -0x1.6c16c16bebd93p-9;  // -2.77777777770155933842e-03
+        private static final double P3   =  0x1.1566aaf25de2cp-14; //  6.61375632143793436117e-05
+        private static final double P4   = -0x1.bbd41c5d26bf1p-20; // -1.65339022054652515390e-06
+        private static final double P5   =  0x1.6376972bea4d0p-25; //  4.13813679705723846039e-08
+
+        // should be able to forgo strictfp due to controlled over/underflow
+        public static strictfp double compute(double x) {
+            double y;
+            double hi = 0.0;
+            double lo = 0.0;
+            double c;
+            double t;
+            int k = 0;
+            int xsb;
+            /*unsigned*/ int hx;
+
+            hx  = __HI(x);  /* high word of x */
+            xsb = (hx >> 31) & 1;               /* sign bit of x */
+            hx &= 0x7fffffff;               /* high word of |x| */
+
+            /* filter out non-finite argument */
+            if (hx >= 0x40862E42) {                  /* if |x| >= 709.78... */
+                if (hx >= 0x7ff00000) {
+                    if (((hx & 0xfffff) | __LO(x)) != 0)
+                        return x + x;                /* NaN */
+                    else
+                        return (xsb == 0) ? x : 0.0;    /* exp(+-inf) = {inf, 0} */
+                }
+                if (x > o_threshold)
+                    return huge * huge; /* overflow */
+                if (x < u_threshold) // unsigned compare needed here?
+                    return twom1000 * twom1000; /* underflow */
+            }
+
+            /* argument reduction */
+            if (hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */
+                if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+                    hi = x - ln2HI[xsb];
+                    lo=ln2LO[xsb];
+                    k = 1 - xsb - xsb;
+                } else {
+                    k  = (int)(invln2 * x + half[xsb]);
+                    t  = k;
+                    hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+                    lo = t*ln2LO[0];
+                }
+                x  = hi - lo;
+            } else if (hx < 0x3e300000)  {     /* when |x|<2**-28 */
+                if (huge + x > one)
+                    return one + x; /* trigger inexact */
+            } else {
+                k = 0;
+            }
+
+            /* x is now in primary range */
+            t  = x * x;
+            c  = x - t*(P1 + t*(P2 + t*(P3 + t*(P4 + t*P5))));
+            if (k == 0)
+                return one - ((x*c)/(c - 2.0) - x);
+            else
+                y = one - ((lo - (x*c)/(2.0 - c)) - hi);
+
+            if(k >= -1021) {
+                y = __HI(y, __HI(y) + (k << 20)); /* add k to y's exponent */
+                return y;
+            } else {
+                y = __HI(y, __HI(y) + ((k + 1000) << 20)); /* add k to y's exponent */
+                return y * twom1000;
+            }
+        }
+    }
 }
--- a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java	Mon Dec 19 16:05:38 2016 +0000
@@ -26,10 +26,13 @@
 package java.lang;
 
 import jdk.internal.loader.BuiltinClassLoader;
-import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
 
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.util.HashSet;
@@ -477,13 +480,16 @@
         static Set<String> HASHED_MODULES = hashedModules();
 
         static Set<String> hashedModules() {
-            Module javaBase = Layer.boot().findModule("java.base").get();
-            Optional<ModuleHashes> ohashes =
-                SharedSecrets.getJavaLangModuleAccess()
-                             .hashes(javaBase.getDescriptor());
 
-            if (ohashes.isPresent()) {
-                Set<String> names = new HashSet<>(ohashes.get().names());
+            Optional<ResolvedModule> resolvedModule = Layer.boot()
+                    .configuration()
+                    .findModule("java.base");
+            assert resolvedModule.isPresent();
+            ModuleReference mref = resolvedModule.get().reference();
+            assert mref instanceof ModuleReferenceImpl;
+            ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
+            if (hashes != null) {
+                Set<String> names = new HashSet<>(hashes.names());
                 names.add("java.base");
                 return names;
             }
--- a/jdk/src/java.base/share/classes/java/lang/StrictMath.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/StrictMath.java	Mon Dec 19 16:05:38 2016 +0000
@@ -227,7 +227,9 @@
      * @return  the value <i>e</i><sup>{@code a}</sup>,
      *          where <i>e</i> is the base of the natural logarithms.
      */
-    public static native double exp(double a);
+    public static double exp(double a) {
+        return FdLibm.Exp.compute(a);
+    }
 
     /**
      * Returns the natural logarithm (base <i>e</i>) of a {@code double}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Mon Dec 19 16:05:38 2016 +0000
@@ -172,6 +172,7 @@
      * @throws IllegalAccessException if the access check specified above fails
      * @throws SecurityException if denied by the security manager
      * @since 9
+     * @see Lookup#dropLookupMode
      */
     public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
         SecurityManager sm = System.getSecurityManager();
@@ -691,10 +692,15 @@
          *  A lookup object on a new lookup class
          *  {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
          *  may have some mode bits set to zero.
+         *  Mode bits can also be
+         *  {@linkplain java.lang.invoke.MethodHandles.Lookup#dropLookupMode directly cleared}.
+         *  Once cleared, mode bits cannot be restored from the downgraded lookup object.
          *  The purpose of this is to restrict access via the new lookup object,
          *  so that it can access only names which can be reached by the original
          *  lookup object, and also by the new lookup class.
          *  @return the lookup modes, which limit the kinds of access performed by this lookup object
+         *  @see #in
+         *  @see #dropLookupMode
          */
         public int lookupModes() {
             return allowedModes & ALL_MODES;
@@ -748,7 +754,8 @@
          * which may change due to this operation.
          *
          * @param requestedLookupClass the desired lookup class for the new lookup object
-         * @return a lookup object which reports the desired lookup class
+         * @return a lookup object which reports the desired lookup class, or the same object
+         * if there is no change
          * @throws NullPointerException if the argument is null
          */
         public Lookup in(Class<?> requestedLookupClass) {
@@ -788,6 +795,40 @@
             return new Lookup(requestedLookupClass, newModes);
         }
 
+
+        /**
+         * Creates a lookup on the same lookup class which this lookup object
+         * finds members, but with a lookup mode that has lost the given lookup mode.
+         * The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
+         * MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
+         * {@link #PROTECTED PROTECTED} is always dropped and so the resulting lookup
+         * mode will never have this access capability. When dropping {@code PACKAGE}
+         * then the resulting lookup will not have {@code PACKAGE} or {@code PRIVATE}
+         * access. When dropping {@code MODULE} then the resulting lookup will not
+         * have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code
+         * PUBLIC} is dropped then the resulting lookup has no access.
+         * @param modeToDrop the lookup mode to drop
+         * @return a lookup object which lacks the indicated mode, or the same object if there is no change
+         * @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC},
+         * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED} or {@code PRIVATE}
+         * @since 9
+         * @see MethodHandles#privateLookupIn
+         */
+        public Lookup dropLookupMode(int modeToDrop) {
+            int oldModes = lookupModes();
+            int newModes = oldModes & ~(modeToDrop | PROTECTED);
+            switch (modeToDrop) {
+                case PUBLIC: newModes &= ~(ALL_MODES); break;
+                case MODULE: newModes &= ~(PACKAGE | PRIVATE); break;
+                case PACKAGE: newModes &= ~(PRIVATE); break;
+                case PROTECTED:
+                case PRIVATE: break;
+                default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
+            }
+            if (newModes == oldModes) return this;  // return self if no change
+            return new Lookup(lookupClass(), newModes);
+        }
+
         // Make sure outer class is initialized first.
         static { IMPL_NAMES.getClass(); }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Mon Dec 19 16:05:38 2016 +0000
@@ -29,7 +29,6 @@
 import java.io.IOException;
 import java.io.PrintStream;
 import java.io.UncheckedIOException;
-import java.net.URI;
 import java.nio.ByteBuffer;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -38,7 +37,6 @@
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -52,7 +50,7 @@
 import static java.util.Objects.*;
 
 import jdk.internal.module.Checks;
-import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
 
 
 /**
@@ -123,8 +121,9 @@
 
         private final Set<Modifier> mods;
         private final String name;
+        private final Version compiledVersion;
 
-        private Requires(Set<Modifier> ms, String mn) {
+        private Requires(Set<Modifier> ms, String mn, Version v) {
             if (ms.isEmpty()) {
                 ms = Collections.emptySet();
             } else {
@@ -132,11 +131,13 @@
             }
             this.mods = ms;
             this.name = mn;
+            this.compiledVersion = v;
         }
 
-        private Requires(Set<Modifier> ms, String mn, boolean unused) {
+        private Requires(Set<Modifier> ms, String mn, Version v, boolean unused) {
             this.mods = ms;
             this.name = mn;
+            this.compiledVersion = v;
         }
 
         /**
@@ -158,12 +159,26 @@
         }
 
         /**
+         * Returns the version of the module if recorded at compile-time.
+         *
+         * @return The version of the module if recorded at compile-time
+         */
+        public Optional<Version> compiledVersion() {
+            return Optional.ofNullable(compiledVersion);
+        }
+
+        /**
          * Compares this module dependence to another.
          *
          * <p> Two {@code Requires} objects are compared by comparing their
          * module name lexicographically.  Where the module names are equal then
          * the sets of modifiers are compared based on a value computed from the
-         * ordinal of each modifier. </p>
+         * ordinal of each modifier. Where the module names are equal and the
+         * set of modifiers are equal then the version of the modules recorded
+         * at compile-time are compared. When comparing the versions recorded
+         * at compile-time then a dependence that has a recorded version is
+         * considered to succeed a dependence that does not have a recorded
+         * version. </p>
          *
          * @return A negative integer, zero, or a positive integer if this module
          *         dependence is less than, equal to, or greater than the given
@@ -174,8 +189,24 @@
             int c = this.name().compareTo(that.name());
             if (c != 0)
                 return c;
-            // same name, compare by modifiers
-            return Long.compare(this.modsValue(), that.modsValue());
+
+            // modifiers
+            c = Long.compare(this.modsValue(), that.modsValue());
+            if (c != 0)
+                return c;
+
+            // compiledVersion
+            if (this.compiledVersion != null) {
+                if (that.compiledVersion != null)
+                    c = this.compiledVersion.compareTo(that.compiledVersion);
+                else
+                    c = 1;
+            } else {
+                if (that.compiledVersion != null)
+                    c = -1;
+            }
+
+            return c;
         }
 
         /**
@@ -195,7 +226,9 @@
          *
          * <p> If the given object is not a {@code Requires} then this method
          * returns {@code false}. Two module dependence objects are equal if
-         * the module names are equal and set of modifiers are equal. </p>
+         * the module names are equal, set of modifiers are equal, and the
+         * compiled version of both modules is equal or not recorded for
+         * both modules. </p>
          *
          * <p> This method satisfies the general contract of the {@link
          * java.lang.Object#equals(Object) Object.equals} method. </p>
@@ -211,21 +244,25 @@
             if (!(ob instanceof Requires))
                 return false;
             Requires that = (Requires)ob;
-            return (name.equals(that.name) && mods.equals(that.mods));
+            return name.equals(that.name) && mods.equals(that.mods)
+                    && Objects.equals(compiledVersion, that.compiledVersion);
         }
 
         /**
          * Computes a hash code for this module dependence.
          *
-         * <p> The hash code is based upon the module name and modifiers. It
-         * satisfies the general contract of the {@link Object#hashCode
-         * Object.hashCode} method. </p>
+         * <p> The hash code is based upon the module name, modifiers, and the
+         * module version if recorded at compile time. It satisfies the general
+         * contract of the {@link Object#hashCode Object.hashCode} method. </p>
          *
          * @return The hash-code value for this module dependence
          */
         @Override
         public int hashCode() {
-            return name.hashCode() * 43 + mods.hashCode();
+            int hash = name.hashCode() * 43 + mods.hashCode();
+            if (compiledVersion != null)
+                hash = hash * 43 + compiledVersion.hashCode();
+            return hash;
         }
 
         /**
@@ -235,7 +272,13 @@
          */
         @Override
         public String toString() {
-            return ModuleDescriptor.toString(mods, name);
+            String what;
+            if (compiledVersion != null) {
+                what = name() + " (@" + compiledVersion + ")";
+            } else {
+                what = name();
+            }
+            return ModuleDescriptor.toString(mods, what);
         }
     }
 
@@ -967,9 +1010,8 @@
     }
 
 
-
-    // From module declarations
     private final String name;
+    private final Version version;
     private final boolean open;
 
     // Indicates if synthesised for a JAR file found on the module path
@@ -984,17 +1026,16 @@
     private final Set<String> uses;
     private final Set<Provides> provides;
 
-    // "Extended" information, added post-compilation by tools
-    private final Version version;
+    // Added post-compilation by tools
+    private final Set<String> packages;
     private final String mainClass;
     private final String osName;
     private final String osArch;
     private final String osVersion;
-    private final Set<String> packages;
-    private final ModuleHashes hashes;
 
 
     private ModuleDescriptor(String name,
+                             Version version,
                              boolean open,
                              boolean automatic,
                              boolean synthetic,
@@ -1003,16 +1044,14 @@
                              Set<Opens> opens,
                              Set<String> uses,
                              Set<Provides> provides,
-                             Version version,
+                             Set<String> packages,
                              String mainClass,
                              String osName,
                              String osArch,
-                             String osVersion,
-                             Set<String> packages,
-                             ModuleHashes hashes)
+                             String osVersion)
     {
-
         this.name = name;
+        this.version = version;
         this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
@@ -1020,18 +1059,16 @@
         assert (requires.stream().map(Requires::name).distinct().count()
                 == requires.size());
         this.requires = emptyOrUnmodifiableSet(requires);
-
         this.exports = emptyOrUnmodifiableSet(exports);
         this.opens = emptyOrUnmodifiableSet(opens);
         this.uses = emptyOrUnmodifiableSet(uses);
         this.provides = emptyOrUnmodifiableSet(provides);
-        this.version = version;
+
+        this.packages = emptyOrUnmodifiableSet(packages);
         this.mainClass = mainClass;
         this.osName = osName;
         this.osArch = osArch;
         this.osVersion = osVersion;
-        this.hashes = hashes;
-        this.packages = emptyOrUnmodifiableSet(packages);
     }
 
     /**
@@ -1039,6 +1076,7 @@
      */
     ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
         this.name = md.name;
+        this.version = md.version;
         this.open = md.open;
         this.automatic = md.automatic;
         this.synthetic = md.synthetic;
@@ -1049,16 +1087,14 @@
         this.uses = md.uses;
         this.provides = md.provides;
 
-        this.version = md.version;
+        Set<String> packages = new HashSet<>(md.packages);
+        packages.addAll(pkgs);
+        this.packages = emptyOrUnmodifiableSet(packages);
+
         this.mainClass = md.mainClass;
         this.osName = md.osName;
         this.osArch = md.osArch;
         this.osVersion = md.osVersion;
-        this.hashes = null; // need to ignore
-
-        Set<String> packages = new HashSet<>(md.packages);
-        packages.addAll(pkgs);
-        this.packages = emptyOrUnmodifiableSet(packages);
     }
 
     /**
@@ -1066,6 +1102,7 @@
      * The arguments are pre-validated and sets are unmodifiable sets.
      */
     ModuleDescriptor(String name,
+                     Version version,
                      boolean open,
                      boolean automatic,
                      boolean synthetic,
@@ -1074,16 +1111,15 @@
                      Set<Opens> opens,
                      Set<String> uses,
                      Set<Provides> provides,
-                     Version version,
+                     Set<String> packages,
                      String mainClass,
                      String osName,
                      String osArch,
                      String osVersion,
-                     Set<String> packages,
-                     ModuleHashes hashes,
                      int hashCode,
                      boolean unused) {
         this.name = name;
+        this.version = version;
         this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
@@ -1093,12 +1129,10 @@
         this.uses = uses;
         this.provides = provides;
         this.packages = packages;
-        this.version = version;
         this.mainClass = mainClass;
         this.osName = osName;
         this.osArch = osArch;
         this.osVersion = osVersion;
-        this.hashes = hashes;
         this.hash = hashCode;
     }
 
@@ -1284,13 +1318,6 @@
         return packages;
     }
 
-    /**
-     * Returns the object with the hashes of other modules
-     */
-    Optional<ModuleHashes> hashes() {
-        return Optional.ofNullable(hashes);
-    }
-
 
     /**
      * A builder used for building {@link ModuleDescriptor} objects.
@@ -1317,15 +1344,13 @@
     public static final class Builder {
         final String name;
         final boolean strict; // true if module names are checked
-        boolean open;
+        final boolean open;
+        final boolean synthetic;
         boolean automatic;
-        boolean synthetic;
         final Map<String, Requires> requires = new HashMap<>();
-
         final Map<String, Exports> exports = new HashMap<>();
         final Map<String, Opens> opens = new HashMap<>();
         final Set<String> concealedPackages = new HashSet<>();
-
         final Set<String> uses = new HashSet<>();
         final Map<String, Provides> provides = new HashMap<>();
         Version version;
@@ -1333,7 +1358,6 @@
         String osArch;
         String osVersion;
         String mainClass;
-        ModuleHashes hashes;
 
         /**
          * Initializes a new builder with the given module name.
@@ -1341,14 +1365,11 @@
          * @param strict
          *        Indicates whether module names are checked or not
          */
-        Builder(String name, boolean strict) {
-            this.strict = strict;
+        Builder(String name, boolean strict, boolean open, boolean synthetic) {
             this.name = (strict) ? requireModuleName(name) : name;
-        }
-
-        /* package */ Builder open(boolean open) {
+            this.strict = strict;
             this.open = open;
-            return this;
+            this.synthetic = synthetic;
         }
 
         /* package */ Builder automatic(boolean automatic) {
@@ -1356,10 +1377,20 @@
             return this;
         }
 
-        /* package */ boolean isOpen() { return open; }
+        /**
+         * Returns the set of packages that are exported (unconditionally or
+         * unconditionally).
+         */
+        /* package */ Set<String> exportedPackages() {
+            return exports.keySet();
+        }
 
-        /* package */ boolean isAutomatic() {
-            return automatic;
+        /**
+         * Returns the set of packages that are opened (unconditionally or
+         * unconditionally).
+         */
+        /* package */Set<String> openPackages() {
+            return opens.keySet();
         }
 
         /**
@@ -1389,6 +1420,36 @@
 
         /**
          * Adds a dependence on a module with the given (and possibly empty)
+         * set of modifiers. The dependence includes the version of the
+         * module that that was recorded at compile-time.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  mn
+         *         The module name
+         * @param  compiledVersion
+         *         The version of the module recorded at compile-time
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the module name is {@code null}, is not a legal Java
+         *         identifier, or is equal to the module name that this builder
+         *         was initialized to build
+         * @throws IllegalStateException
+         *         If the dependence on the module has already been declared
+         */
+        public Builder requires(Set<Requires.Modifier> ms,
+                                String mn,
+                                Version compiledVersion) {
+            Objects.requireNonNull(compiledVersion);
+            if (strict)
+                mn = requireModuleName(mn);
+            return requires(new Requires(ms, mn, compiledVersion));
+        }
+
+        /**
+         * Adds a dependence on a module with the given (and possibly empty)
          * set of modifiers.
          *
          * @param  ms
@@ -1408,7 +1469,7 @@
         public Builder requires(Set<Requires.Modifier> ms, String mn) {
             if (strict)
                 mn = requireModuleName(mn);
-            return requires(new Requires(ms, mn));
+            return requires(new Requires(ms, mn, null));
         }
 
         /**
@@ -1705,17 +1766,6 @@
             return opens(Collections.emptySet(), pn);
         }
 
-
-        // Used by ModuleInfo, after a packageFinder is invoked
-        /* package */ Set<String> exportedAndOpenPackages() {
-            if (opens.isEmpty())
-                return exports.keySet();
-            Set<String> result = new HashSet<>();
-            result.addAll(exports.keySet());
-            result.addAll(opens.keySet());
-            return result;
-        }
-
         /**
          * Adds a service dependence.
          *
@@ -1789,7 +1839,6 @@
             if (providerNames.isEmpty())
                 throw new IllegalArgumentException("Empty providers set");
             providerNames.forEach(Checks::requireServiceProviderName);
-
             provides.put(service, p);
             return this;
         }
@@ -1914,7 +1963,7 @@
          *         If {@code mainClass} is null or is not a legal Java identifier
          */
         public Builder mainClass(String mc) {
-            mainClass = requireJavaIdentifier("main class name", mc);
+            mainClass = requireBinaryName("main class name", mc);
             return this;
         }
 
@@ -1972,16 +2021,6 @@
             return this;
         }
 
-        /* package */ Builder hashes(ModuleHashes hashes) {
-            this.hashes = hashes;
-            return this;
-        }
-
-        /* package */ Builder synthetic(boolean v) {
-            this.synthetic = v;
-            return this;
-        }
-
         /**
          * Builds and returns a {@code ModuleDescriptor} from its components.
          *
@@ -1990,7 +2029,9 @@
         public ModuleDescriptor build() {
             Set<Requires> requires = new HashSet<>(this.requires.values());
 
-            Set<String> packages = new HashSet<>(exportedAndOpenPackages());
+            Set<String> packages = new HashSet<>();
+            packages.addAll(exports.keySet());
+            packages.addAll(opens.keySet());
             packages.addAll(concealedPackages);
 
             Set<Exports> exports = new HashSet<>(this.exports.values());
@@ -1999,6 +2040,7 @@
             Set<Provides> provides = new HashSet<>(this.provides.values());
 
             return new ModuleDescriptor(name,
+                                        version,
                                         open,
                                         automatic,
                                         synthetic,
@@ -2007,13 +2049,11 @@
                                         opens,
                                         uses,
                                         provides,
-                                        version,
+                                        packages,
                                         mainClass,
                                         osName,
                                         osArch,
-                                        osVersion,
-                                        packages,
-                                        hashes);
+                                        osVersion);
         }
 
     }
@@ -2088,8 +2128,7 @@
                 && Objects.equals(osName, that.osName)
                 && Objects.equals(osArch, that.osArch)
                 && Objects.equals(osVersion, that.osVersion)
-                && Objects.equals(packages, that.packages)
-                && Objects.equals(hashes, that.hashes));
+                && Objects.equals(packages, that.packages));
     }
 
     private transient int hash;  // cached hash code
@@ -2122,7 +2161,6 @@
             hc = hc * 43 + Objects.hashCode(osArch);
             hc = hc * 43 + Objects.hashCode(osVersion);
             hc = hc * 43 + Objects.hashCode(packages);
-            hc = hc * 43 + Objects.hashCode(hashes);
             if (hc == 0)
                 hc = -1;
             hash = hc;
@@ -2145,7 +2183,7 @@
         if (!requires.isEmpty())
             sb.append(", ").append(requires);
         if (!uses.isEmpty())
-            sb.append(", ").append(uses);
+            sb.append(", uses: ").append(uses);
         if (!exports.isEmpty())
             sb.append(", exports: ").append(exports);
         if (!opens.isEmpty())
@@ -2171,7 +2209,7 @@
      *         identifier
      */
     public static Builder module(String name) {
-        return new Builder(name, true);
+        return new Builder(name, true, false, false);
     }
 
     /**
@@ -2199,7 +2237,7 @@
      *         identifier
      */
     public static Builder openModule(String name) {
-        return new Builder(name, true).open(true);
+        return new Builder(name, true, true, false);
     }
 
     /**
@@ -2221,7 +2259,7 @@
      * @see ModuleFinder#of(Path[])
      */
     public static Builder automaticModule(String name) {
-        return new Builder(name, true).automatic(true);
+        return new Builder(name, true, false, false).automatic(true);
     }
 
 
@@ -2263,7 +2301,7 @@
                                         Supplier<Set<String>> packageFinder)
         throws IOException
     {
-        return ModuleInfo.read(in, requireNonNull(packageFinder));
+        return ModuleInfo.read(in, requireNonNull(packageFinder)).descriptor();
     }
 
     /**
@@ -2281,7 +2319,7 @@
      *         If an I/O error occurs reading from the input stream
      */
     public static ModuleDescriptor read(InputStream in) throws IOException {
-        return ModuleInfo.read(in, null);
+        return ModuleInfo.read(in, null).descriptor();
     }
 
     /**
@@ -2320,7 +2358,7 @@
     public static ModuleDescriptor read(ByteBuffer bb,
                                         Supplier<Set<String>> packageFinder)
     {
-        return ModuleInfo.read(bb, requireNonNull(packageFinder));
+        return ModuleInfo.read(bb, requireNonNull(packageFinder)).descriptor();
     }
 
     /**
@@ -2336,7 +2374,7 @@
      *         If an invalid module descriptor is detected
      */
     public static ModuleDescriptor read(ByteBuffer bb) {
-        return ModuleInfo.read(bb, null);
+        return ModuleInfo.read(bb, null).descriptor();
     }
 
     private static <K,V> Map<K,V> emptyOrUnmodifiableMap(Map<K,V> map) {
@@ -2377,18 +2415,26 @@
         jdk.internal.misc.SharedSecrets
             .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
                 @Override
-                public Builder newModuleBuilder(String mn, boolean strict) {
-                    return new Builder(mn, strict);
+                public Builder newModuleBuilder(String mn,
+                                                boolean strict,
+                                                boolean open,
+                                                boolean synthetic) {
+                    return new Builder(mn, strict, open, synthetic);
                 }
 
                 @Override
-                public Builder newOpenModuleBuilder(String mn, boolean strict) {
-                    return new Builder(mn, strict).open(true);
+                public Set<String> exportedPackages(ModuleDescriptor.Builder builder) {
+                    return builder.exportedPackages();
                 }
 
                 @Override
-                public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
-                    return new Requires(ms, mn, true);
+                public Set<String> openPackages(ModuleDescriptor.Builder builder) {
+                    return builder.openPackages();
+                }
+
+                @Override
+                public Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v) {
+                    return new Requires(ms, mn, v, true);
                 }
 
                 @Override
@@ -2433,6 +2479,7 @@
 
                 @Override
                 public ModuleDescriptor newModuleDescriptor(String name,
+                                                            Version version,
                                                             boolean open,
                                                             boolean automatic,
                                                             boolean synthetic,
@@ -2441,15 +2488,14 @@
                                                             Set<Opens> opens,
                                                             Set<String> uses,
                                                             Set<Provides> provides,
-                                                            Version version,
+                                                            Set<String> packages,
                                                             String mainClass,
                                                             String osName,
                                                             String osArch,
                                                             String osVersion,
-                                                            Set<String> packages,
-                                                            ModuleHashes hashes,
                                                             int hashCode) {
                     return new ModuleDescriptor(name,
+                                                version,
                                                 open,
                                                 automatic,
                                                 synthetic,
@@ -2458,23 +2504,16 @@
                                                 opens,
                                                 uses,
                                                 provides,
-                                                version,
+                                                packages,
                                                 mainClass,
                                                 osName,
                                                 osArch,
                                                 osVersion,
-                                                packages,
-                                                hashes,
                                                 hashCode,
                                                 false);
                 }
 
                 @Override
-                public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
-                    return descriptor.hashes();
-                }
-
-                @Override
                 public Configuration resolveRequiresAndUses(ModuleFinder finder,
                                                             Collection<String> roots,
                                                             boolean check,
@@ -2482,20 +2521,6 @@
                 {
                     return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput);
                 }
-
-                @Override
-                public ModuleReference newPatchedModule(ModuleDescriptor descriptor,
-                                                        URI location,
-                                                        Supplier<ModuleReader> s) {
-                    return new ModuleReference(descriptor, location, s, true, null);
-                }
-
-                @Override
-                public ModuleFinder newModulePath(Runtime.Version version,
-                                                  boolean isLinkPhase,
-                                                  Path... entries) {
-                    return new ModulePath(version, isLinkPhase, entries);
-                }
             });
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Mon Dec 19 16:05:38 2016 +0000
@@ -42,6 +42,8 @@
 import java.util.Optional;
 import java.util.Set;
 
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.SystemModuleFinder;
 import sun.security.action.GetPropertyAction;
 
 /**
@@ -137,7 +139,7 @@
 
     /**
      * Returns a module finder that locates the <em>system modules</em>. The
-     * system modules are typically linked into the Java run-time image.
+     * system modules are the modules in the Java run-time image.
      * The module finder will always find {@code java.base}.
      *
      * <p> If there is a security manager set then its {@link
@@ -166,7 +168,7 @@
 
         Path modules = Paths.get(home, "lib", "modules");
         if (Files.isRegularFile(modules)) {
-            return new SystemModuleFinder();
+            return SystemModuleFinder.getInstance();
         } else {
             Path mlib = Paths.get(home, "modules");
             if (Files.isDirectory(mlib)) {
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java	Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,899 +0,0 @@
-/*
- * Copyright (c) 2014, 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 java.lang.module;
-
-import java.io.DataInput;
-import java.io.DataInputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor.Builder;
-import java.lang.module.ModuleDescriptor.Requires;
-import java.lang.module.ModuleDescriptor.Exports;
-import java.lang.module.ModuleDescriptor.Opens;
-import java.nio.ByteBuffer;
-import java.nio.BufferUnderflowException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes;
-
-import static jdk.internal.module.ClassFileConstants.*;
-
-
-/**
- * Read module information from a {@code module-info} class file.
- *
- * @implNote The rationale for the hand-coded reader is startup performance
- * and fine control over the throwing of InvalidModuleDescriptorException.
- */
-
-final class ModuleInfo {
-
-    // supplies the set of packages when ModulePackages attribute not present
-    private final Supplier<Set<String>> packageFinder;
-
-    // indicates if the ModuleHashes attribute should be parsed
-    private final boolean parseHashes;
-
-    private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
-        packageFinder = pf;
-        parseHashes = ph;
-    }
-
-    private ModuleInfo(Supplier<Set<String>> pf) {
-        this(pf, true);
-    }
-
-    /**
-     * Reads a {@code module-info.class} from the given input stream.
-     *
-     * @throws InvalidModuleDescriptorException
-     * @throws IOException
-     */
-    public static ModuleDescriptor read(InputStream in,
-                                        Supplier<Set<String>> pf)
-        throws IOException
-    {
-        try {
-            return new ModuleInfo(pf).doRead(new DataInputStream(in));
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw invalidModuleDescriptor(e.getMessage());
-        } catch (EOFException x) {
-            throw truncatedModuleDescriptor();
-        }
-    }
-
-    /**
-     * Reads a {@code module-info.class} from the given byte buffer.
-     *
-     * @throws InvalidModuleDescriptorException
-     * @throws UncheckedIOException
-     */
-    public static ModuleDescriptor read(ByteBuffer bb,
-                                        Supplier<Set<String>> pf)
-    {
-        try {
-            return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw invalidModuleDescriptor(e.getMessage());
-        } catch (EOFException x) {
-            throw truncatedModuleDescriptor();
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-    }
-
-    /**
-     * Reads a {@code module-info.class} from the given byte buffer
-     * but ignore the {@code ModuleHashes} attribute.
-     *
-     * @throws InvalidModuleDescriptorException
-     * @throws UncheckedIOException
-     */
-    static ModuleDescriptor readIgnoringHashes(ByteBuffer bb,
-                                               Supplier<Set<String>> pf)
-    {
-        try {
-            return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException | IllegalStateException e) {
-            throw invalidModuleDescriptor(e.getMessage());
-        } catch (EOFException x) {
-            throw truncatedModuleDescriptor();
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-    }
-
-    /**
-     * Reads the input as a module-info class file.
-     *
-     * @throws IOException
-     * @throws InvalidModuleDescriptorException
-     * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
-     *         because an identifier is not a legal Java identifier, duplicate
-     *         exports, and many other reasons
-     */
-    private ModuleDescriptor doRead(DataInput in) throws IOException {
-
-        int magic = in.readInt();
-        if (magic != 0xCAFEBABE)
-            throw invalidModuleDescriptor("Bad magic number");
-
-        int minor_version = in.readUnsignedShort();
-        int major_version = in.readUnsignedShort();
-        if (major_version < 53) {
-            throw invalidModuleDescriptor("Must be >= 53.0");
-        }
-
-        ConstantPool cpool = new ConstantPool(in);
-
-        int access_flags = in.readUnsignedShort();
-        if (access_flags != ACC_MODULE)
-            throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
-
-        int this_class = in.readUnsignedShort();
-        if (this_class != 0)
-            throw invalidModuleDescriptor("this_class must be 0");
-
-        int super_class = in.readUnsignedShort();
-        if (super_class > 0)
-            throw invalidModuleDescriptor("bad #super_class");
-
-        int interfaces_count = in.readUnsignedShort();
-        if (interfaces_count > 0)
-            throw invalidModuleDescriptor("Bad #interfaces");
-
-        int fields_count = in.readUnsignedShort();
-        if (fields_count > 0)
-            throw invalidModuleDescriptor("Bad #fields");
-
-        int methods_count = in.readUnsignedShort();
-        if (methods_count > 0)
-            throw invalidModuleDescriptor("Bad #methods");
-
-        int attributes_count = in.readUnsignedShort();
-
-        // the names of the attributes found in the class file
-        Set<String> attributes = new HashSet<>();
-
-        Builder builder = null;
-        Set<String> packages = null;
-        String version = null;
-        String mainClass = null;
-        String[] osValues = null;
-        ModuleHashes hashes = null;
-
-        for (int i = 0; i < attributes_count ; i++) {
-            int name_index = in.readUnsignedShort();
-            String attribute_name = cpool.getUtf8(name_index);
-            int length = in.readInt();
-
-            boolean added = attributes.add(attribute_name);
-            if (!added && isAttributeAtMostOnce(attribute_name)) {
-                throw invalidModuleDescriptor("More than one "
-                                              + attribute_name + " attribute");
-            }
-
-            switch (attribute_name) {
-
-                case MODULE :
-                    builder = readModuleAttribute(in, cpool);
-                    break;
-
-                case MODULE_PACKAGES :
-                    packages = readModulePackagesAttribute(in, cpool);
-                    break;
-
-                case MODULE_VERSION :
-                    version = readModuleVersionAttribute(in, cpool);
-                    break;
-
-                case MODULE_MAIN_CLASS :
-                    mainClass = readModuleMainClassAttribute(in, cpool);
-                    break;
-
-                case MODULE_TARGET :
-                    osValues = readModuleTargetAttribute(in, cpool);
-                    break;
-
-                case MODULE_HASHES :
-                    if (parseHashes) {
-                        hashes = readModuleHashesAttribute(in, cpool);
-                    } else {
-                        in.skipBytes(length);
-                    }
-                    break;
-
-                default:
-                    if (isAttributeDisallowed(attribute_name)) {
-                        throw invalidModuleDescriptor(attribute_name
-                                                      + " attribute not allowed");
-                    } else {
-                        in.skipBytes(length);
-                    }
-
-            }
-        }
-
-        // the Module attribute is required
-        if (builder == null) {
-            throw invalidModuleDescriptor(MODULE + " attribute not found");
-        }
-
-        // If the ModulePackages attribute is not present then the packageFinder
-        // is used to find the set of packages
-        boolean usedPackageFinder = false;
-        if (packages == null && packageFinder != null) {
-            try {
-                packages = new HashSet<>(packageFinder.get());
-            } catch (UncheckedIOException x) {
-                throw x.getCause();
-            }
-            usedPackageFinder = true;
-        }
-        if (packages != null) {
-            for (String pn : builder.exportedAndOpenPackages()) {
-                if (!packages.contains(pn)) {
-                    String tail;
-                    if (usedPackageFinder) {
-                        tail = " not found by package finder";
-                    } else {
-                        tail = " missing from ModulePackages attribute";
-                    }
-                    throw invalidModuleDescriptor("Package " + pn + tail);
-                }
-                packages.remove(pn);
-            }
-            builder.contains(packages);
-        }
-
-        if (version != null)
-            builder.version(version);
-        if (mainClass != null)
-            builder.mainClass(mainClass);
-        if (osValues != null) {
-            if (osValues[0] != null) builder.osName(osValues[0]);
-            if (osValues[1] != null) builder.osArch(osValues[1]);
-            if (osValues[2] != null) builder.osVersion(osValues[2]);
-        }
-        if (hashes != null)
-            builder.hashes(hashes);
-
-        return builder.build();
-    }
-
-    /**
-     * Reads the Module attribute, returning the ModuleDescriptor.Builder to
-     * build the corresponding ModuleDescriptor.
-     */
-    private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        // module_name
-        int module_name_index = in.readUnsignedShort();
-        String mn = cpool.getUtf8AsBinaryName(module_name_index);
-
-        Builder builder = new ModuleDescriptor.Builder(mn, /*strict*/ false);
-
-        int module_flags = in.readUnsignedShort();
-        boolean open = ((module_flags & ACC_OPEN) != 0);
-        if (open)
-            builder.open(true);
-        if ((module_flags & ACC_SYNTHETIC) != 0)
-            builder.synthetic(true);
-
-        int requires_count = in.readUnsignedShort();
-        boolean requiresJavaBase = false;
-        for (int i=0; i<requires_count; i++) {
-            int index = in.readUnsignedShort();
-            int flags = in.readUnsignedShort();
-            String dn = cpool.getUtf8AsBinaryName(index);
-            Set<Requires.Modifier> mods;
-            if (flags == 0) {
-                mods = Collections.emptySet();
-            } else {
-                mods = new HashSet<>();
-                if ((flags & ACC_TRANSITIVE) != 0)
-                    mods.add(Requires.Modifier.TRANSITIVE);
-                if ((flags & ACC_STATIC_PHASE) != 0)
-                    mods.add(Requires.Modifier.STATIC);
-                if ((flags & ACC_SYNTHETIC) != 0)
-                    mods.add(Requires.Modifier.SYNTHETIC);
-                if ((flags & ACC_MANDATED) != 0)
-                    mods.add(Requires.Modifier.MANDATED);
-            }
-            builder.requires(mods, dn);
-            if (dn.equals("java.base"))
-                requiresJavaBase = true;
-        }
-        if (mn.equals("java.base")) {
-            if (requires_count > 0) {
-                throw invalidModuleDescriptor("The requires table for java.base"
-                                              + " must be 0 length");
-            }
-        } else if (!requiresJavaBase) {
-            throw invalidModuleDescriptor("The requires table must have"
-                                          + " an entry for java.base");
-        }
-
-        int exports_count = in.readUnsignedShort();
-        if (exports_count > 0) {
-            for (int i=0; i<exports_count; i++) {
-                int index = in.readUnsignedShort();
-                String pkg = cpool.getUtf8AsBinaryName(index);
-
-                Set<Exports.Modifier> mods;
-                int flags = in.readUnsignedShort();
-                if (flags == 0) {
-                    mods = Collections.emptySet();
-                } else {
-                    mods = new HashSet<>();
-                    if ((flags & ACC_SYNTHETIC) != 0)
-                        mods.add(Exports.Modifier.SYNTHETIC);
-                    if ((flags & ACC_MANDATED) != 0)
-                        mods.add(Exports.Modifier.MANDATED);
-                }
-
-                int exports_to_count = in.readUnsignedShort();
-                if (exports_to_count > 0) {
-                    Set<String> targets = new HashSet<>(exports_to_count);
-                    for (int j=0; j<exports_to_count; j++) {
-                        int exports_to_index = in.readUnsignedShort();
-                        targets.add(cpool.getUtf8AsBinaryName(exports_to_index));
-                    }
-                    builder.exports(mods, pkg, targets);
-                } else {
-                    builder.exports(mods, pkg);
-                }
-            }
-        }
-
-        int opens_count = in.readUnsignedShort();
-        if (opens_count > 0) {
-            if (open) {
-                throw invalidModuleDescriptor("The opens table for an open"
-                                              + " module must be 0 length");
-            }
-            for (int i=0; i<opens_count; i++) {
-                int index = in.readUnsignedShort();
-                String pkg = cpool.getUtf8AsBinaryName(index);
-
-                Set<Opens.Modifier> mods;
-                int flags = in.readUnsignedShort();
-                if (flags == 0) {
-                    mods = Collections.emptySet();
-                } else {
-                    mods = new HashSet<>();
-                    if ((flags & ACC_SYNTHETIC) != 0)
-                        mods.add(Opens.Modifier.SYNTHETIC);
-                    if ((flags & ACC_MANDATED) != 0)
-                        mods.add(Opens.Modifier.MANDATED);
-                }
-
-                int open_to_count = in.readUnsignedShort();
-                if (open_to_count > 0) {
-                    Set<String> targets = new HashSet<>(open_to_count);
-                    for (int j=0; j<open_to_count; j++) {
-                        int opens_to_index = in.readUnsignedShort();
-                        targets.add(cpool.getUtf8AsBinaryName(opens_to_index));
-                    }
-                    builder.opens(mods, pkg, targets);
-                } else {
-                    builder.opens(mods, pkg);
-                }
-            }
-        }
-
-        int uses_count = in.readUnsignedShort();
-        if (uses_count > 0) {
-            for (int i=0; i<uses_count; i++) {
-                int index = in.readUnsignedShort();
-                String sn = cpool.getClassNameAsBinaryName(index);
-                builder.uses(sn);
-            }
-        }
-
-        int provides_count = in.readUnsignedShort();
-        if (provides_count > 0) {
-            for (int i=0; i<provides_count; i++) {
-                int index = in.readUnsignedShort();
-                String sn = cpool.getClassNameAsBinaryName(index);
-                int with_count = in.readUnsignedShort();
-                List<String> providers = new ArrayList<>(with_count);
-                for (int j=0; j<with_count; j++) {
-                    index = in.readUnsignedShort();
-                    String pn = cpool.getClassNameAsBinaryName(index);
-                    providers.add(pn);
-                }
-                builder.provides(sn, providers);
-            }
-        }
-
-        return builder;
-    }
-
-    /**
-     * Reads the ModulePackages attribute
-     */
-    private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int package_count = in.readUnsignedShort();
-        Set<String> packages = new HashSet<>(package_count);
-        for (int i=0; i<package_count; i++) {
-            int index = in.readUnsignedShort();
-            String pn = cpool.getUtf8AsBinaryName(index);
-            packages.add(pn);
-        }
-        return packages;
-    }
-
-    /**
-     * Reads the ModuleVersion attribute
-     */
-    private String readModuleVersionAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int index = in.readUnsignedShort();
-        return cpool.getUtf8(index);
-    }
-
-    /**
-     * Reads the ModuleMainClass attribute
-     */
-    private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int index = in.readUnsignedShort();
-        return cpool.getClassNameAsBinaryName(index);
-    }
-
-    /**
-     * Reads the ModuleTarget attribute
-     */
-    private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        String[] values = new String[3];
-
-        int name_index = in.readUnsignedShort();
-        if (name_index != 0)
-            values[0] = cpool.getUtf8(name_index);
-
-        int arch_index = in.readUnsignedShort();
-        if (arch_index != 0)
-            values[1] = cpool.getUtf8(arch_index);
-
-        int version_index = in.readUnsignedShort();
-        if (version_index != 0)
-            values[2] = cpool.getUtf8(version_index);
-
-        return values;
-    }
-
-
-    /**
-     * Reads the ModuleHashes attribute
-     */
-    private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
-        throws IOException
-    {
-        int algorithm_index = in.readUnsignedShort();
-        String algorithm = cpool.getUtf8(algorithm_index);
-
-        int hash_count = in.readUnsignedShort();
-        Map<String, byte[]> map = new HashMap<>(hash_count);
-        for (int i=0; i<hash_count; i++) {
-            int module_name_index = in.readUnsignedShort();
-            String mn = cpool.getUtf8AsBinaryName(module_name_index);
-            int hash_length = in.readUnsignedShort();
-            if (hash_length == 0) {
-                throw invalidModuleDescriptor("hash_length == 0");
-            }
-            byte[] hash = new byte[hash_length];
-            in.readFully(hash);
-            map.put(mn, hash);
-        }
-
-        return new ModuleHashes(algorithm, map);
-    }
-
-
-    /**
-     * Returns true if the given attribute can be present at most once
-     * in the class file. Returns false otherwise.
-     */
-    private static boolean isAttributeAtMostOnce(String name) {
-
-        if (name.equals(MODULE) ||
-                name.equals(SOURCE_FILE) ||
-                name.equals(SDE) ||
-                name.equals(MODULE_PACKAGES) ||
-                name.equals(MODULE_VERSION) ||
-                name.equals(MODULE_MAIN_CLASS) ||
-                name.equals(MODULE_TARGET) ||
-                name.equals(MODULE_HASHES))
-            return true;
-
-        return false;
-    }
-
-    /**
-     * Return true if the given attribute name is the name of a pre-defined
-     * attribute that is not allowed in the class file.
-     *
-     * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
-     * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
-     */
-    private static boolean isAttributeDisallowed(String name) {
-        Set<String> notAllowed = predefinedNotAllowed;
-        if (notAllowed == null) {
-            notAllowed = Set.of(
-                    "ConstantValue",
-                    "Code",
-                    "StackMapTable",
-                    "Exceptions",
-                    "EnclosingMethod",
-                    "Signature",
-                    "LineNumberTable",
-                    "LocalVariableTable",
-                    "LocalVariableTypeTable",
-                    "RuntimeVisibleParameterAnnotations",
-                    "RuntimeInvisibleParameterAnnotations",
-                    "RuntimeVisibleTypeAnnotations",
-                    "RuntimeInvisibleTypeAnnotations",
-                    "Synthetic",
-                    "AnnotationDefault",
-                    "BootstrapMethods",
-                    "MethodParameters");
-            predefinedNotAllowed = notAllowed;
-        }
-        return notAllowed.contains(name);
-    }
-
-    // lazily created set the pre-defined attributes that are not allowed
-    private static volatile Set<String> predefinedNotAllowed;
-
-
-    /**
-     * The constant pool in a class file.
-     */
-    private static class ConstantPool {
-        static final int CONSTANT_Utf8 = 1;
-        static final int CONSTANT_Integer = 3;
-        static final int CONSTANT_Float = 4;
-        static final int CONSTANT_Long = 5;
-        static final int CONSTANT_Double = 6;
-        static final int CONSTANT_Class = 7;
-        static final int CONSTANT_String = 8;
-        static final int CONSTANT_Fieldref = 9;
-        static final int CONSTANT_Methodref = 10;
-        static final int CONSTANT_InterfaceMethodref = 11;
-        static final int CONSTANT_NameAndType = 12;
-        static final int CONSTANT_MethodHandle = 15;
-        static final int CONSTANT_MethodType = 16;
-        static final int CONSTANT_InvokeDynamic = 18;
-
-        private static class Entry {
-            protected Entry(int tag) {
-                this.tag = tag;
-            }
-            final int tag;
-        }
-
-        private static class IndexEntry extends Entry {
-            IndexEntry(int tag, int index) {
-                super(tag);
-                this.index = index;
-            }
-            final int index;
-        }
-
-        private static class Index2Entry extends Entry {
-            Index2Entry(int tag, int index1, int index2) {
-                super(tag);
-                this.index1 = index1;
-                this.index2 = index2;
-            }
-            final int index1,  index2;
-        }
-
-        private static class ValueEntry extends Entry {
-            ValueEntry(int tag, Object value) {
-                super(tag);
-                this.value = value;
-            }
-            final Object value;
-        }
-
-        final Entry[] pool;
-
-        ConstantPool(DataInput in) throws IOException {
-            int count = in.readUnsignedShort();
-            pool = new Entry[count];
-
-            for (int i = 1; i < count; i++) {
-                int tag = in.readUnsignedByte();
-                switch (tag) {
-
-                    case CONSTANT_Utf8:
-                        String svalue = in.readUTF();
-                        pool[i] = new ValueEntry(tag, svalue);
-                        break;
-
-                    case CONSTANT_Class:
-                    case CONSTANT_String:
-                        int index = in.readUnsignedShort();
-                        pool[i] = new IndexEntry(tag, index);
-                        break;
-
-                    case CONSTANT_Double:
-                        double dvalue = in.readDouble();
-                        pool[i] = new ValueEntry(tag, dvalue);
-                        i++;
-                        break;
-
-                    case CONSTANT_Fieldref:
-                    case CONSTANT_InterfaceMethodref:
-                    case CONSTANT_Methodref:
-                    case CONSTANT_InvokeDynamic:
-                    case CONSTANT_NameAndType:
-                        int index1 = in.readUnsignedShort();
-                        int index2 = in.readUnsignedShort();
-                        pool[i] = new Index2Entry(tag, index1, index2);
-                        break;
-
-                    case CONSTANT_MethodHandle:
-                        int refKind = in.readUnsignedByte();
-                        index = in.readUnsignedShort();
-                        pool[i] = new Index2Entry(tag, refKind, index);
-                        break;
-
-                    case CONSTANT_MethodType:
-                        index = in.readUnsignedShort();
-                        pool[i] = new IndexEntry(tag, index);
-                        break;
-
-                    case CONSTANT_Float:
-                        float fvalue = in.readFloat();
-                        pool[i] = new ValueEntry(tag, fvalue);
-                        break;
-
-                    case CONSTANT_Integer:
-                        int ivalue = in.readInt();
-                        pool[i] = new ValueEntry(tag, ivalue);
-                        break;
-
-                    case CONSTANT_Long:
-                        long lvalue = in.readLong();
-                        pool[i] = new ValueEntry(tag, lvalue);
-                        i++;
-                        break;
-
-                    default:
-                        throw invalidModuleDescriptor("Bad constant pool entry: "
-                                                      + i);
-                }
-            }
-        }
-
-        String getClassName(int index) {
-            checkIndex(index);
-            Entry e = pool[index];
-            if (e.tag != CONSTANT_Class) {
-                throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
-                                              + index);
-            }
-            return getUtf8(((IndexEntry) e).index);
-        }
-
-        String getClassNameAsBinaryName(int index) {
-            String value = getClassName(index);
-            return value.replace('/', '.');  // internal form -> binary name
-        }
-
-        String getUtf8(int index) {
-            checkIndex(index);
-            Entry e = pool[index];
-            if (e.tag != CONSTANT_Utf8) {
-                throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
-                                              + index);
-            }
-            return (String) (((ValueEntry) e).value);
-        }
-
-        String getUtf8AsBinaryName(int index) {
-            String value = getUtf8(index);
-            return value.replace('/', '.');  // internal -> binary name
-        }
-
-        void checkIndex(int index) {
-            if (index < 1 || index >= pool.length)
-                throw invalidModuleDescriptor("Index into constant pool out of range");
-        }
-    }
-
-    /**
-     * A DataInput implementation that reads from a ByteBuffer.
-     */
-    private static class DataInputWrapper implements DataInput {
-        private final ByteBuffer bb;
-
-        DataInputWrapper(ByteBuffer bb) {
-            this.bb = bb;
-        }
-
-        @Override
-        public void readFully(byte b[]) throws IOException {
-            readFully(b, 0, b.length);
-        }
-
-        @Override
-        public void readFully(byte b[], int off, int len) throws IOException {
-            try {
-                bb.get(b, off, len);
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int skipBytes(int n) {
-            int skip = Math.min(n, bb.remaining());
-            bb.position(bb.position() + skip);
-            return skip;
-        }
-
-        @Override
-        public boolean readBoolean() throws IOException {
-            try {
-                int ch = bb.get();
-                return (ch != 0);
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public byte readByte() throws IOException {
-            try {
-                return bb.get();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int readUnsignedByte() throws IOException {
-            try {
-                return ((int) bb.get()) & 0xff;
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public short readShort() throws IOException {
-            try {
-                return bb.getShort();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int readUnsignedShort() throws IOException {
-            try {
-                return ((int) bb.getShort()) & 0xffff;
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public char readChar() throws IOException {
-            try {
-                return bb.getChar();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public int readInt() throws IOException {
-            try {
-                return bb.getInt();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public long readLong() throws IOException {
-            try {
-                return bb.getLong();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public float readFloat() throws IOException {
-            try {
-                return bb.getFloat();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public double readDouble() throws IOException {
-            try {
-                return bb.getDouble();
-            } catch (BufferUnderflowException e) {
-                throw new EOFException(e.getMessage());
-            }
-        }
-
-        @Override
-        public String readLine() {
-            throw new RuntimeException("not implemented");
-        }
-
-        @Override
-        public String readUTF() throws IOException {
-            // ### Need to measure the performance and feasibility of using
-            // the UTF-8 decoder instead.
-            return DataInputStream.readUTF(this);
-        }
-    }
-
-    /**
-     * Returns an InvalidModuleDescriptorException with the given detail
-     * message
-     */
-    private static InvalidModuleDescriptorException
-    invalidModuleDescriptor(String msg) {
-        return new InvalidModuleDescriptorException(msg);
-    }
-
-    /**
-     * Returns an InvalidModuleDescriptorException with a detail message to
-     * indicate that the class file is truncated.
-     */
-    private static InvalidModuleDescriptorException truncatedModuleDescriptor() {
-        return invalidModuleDescriptor("Truncated module-info.class");
-    }
-
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,681 +0,0 @@
-/*
- * Copyright (c) 2014, 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 java.lang.module;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor.Requires;
-import java.net.URI;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.zip.ZipFile;
-
-import jdk.internal.jmod.JmodFile;
-import jdk.internal.jmod.JmodFile.Section;
-import jdk.internal.module.Checks;
-import jdk.internal.perf.PerfCounter;
-import jdk.internal.util.jar.VersionedStream;
-
-
-/**
- * A {@code ModuleFinder} that locates modules on the file system by searching
- * a sequence of directories or packaged modules.
- *
- * The {@code ModuleFinder} can be created to work in either the run-time
- * or link-time phases. In both cases it locates modular JAR and exploded
- * modules. When created for link-time then it additionally locates
- * modules in JMOD files.
- */
-
-class ModulePath implements ModuleFinder {
-    private static final String MODULE_INFO = "module-info.class";
-
-    // the version to use for multi-release modular JARs
-    private final Runtime.Version releaseVersion;
-
-    // true for the link phase (supports modules packaged in JMOD format)
-    private final boolean isLinkPhase;
-
-    // the entries on this module path
-    private final Path[] entries;
-    private int next;
-
-    // map of module name to module reference map for modules already located
-    private final Map<String, ModuleReference> cachedModules = new HashMap<>();
-
-    ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
-        this.releaseVersion = version;
-        this.isLinkPhase = isLinkPhase;
-        this.entries = entries.clone();
-        for (Path entry : this.entries) {
-            Objects.requireNonNull(entry);
-        }
-    }
-
-    ModulePath(Path... entries) {
-        this(JarFile.runtimeVersion(), false, entries);
-    }
-
-    @Override
-    public Optional<ModuleReference> find(String name) {
-        Objects.requireNonNull(name);
-
-        // try cached modules
-        ModuleReference m = cachedModules.get(name);
-        if (m != null)
-            return Optional.of(m);
-
-        // the module may not have been encountered yet
-        while (hasNextEntry()) {
-            scanNextEntry();
-            m = cachedModules.get(name);
-            if (m != null)
-                return Optional.of(m);
-        }
-        return Optional.empty();
-    }
-
-    @Override
-    public Set<ModuleReference> findAll() {
-        // need to ensure that all entries have been scanned
-        while (hasNextEntry()) {
-            scanNextEntry();
-        }
-        return cachedModules.values().stream().collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns {@code true} if there are additional entries to scan
-     */
-    private boolean hasNextEntry() {
-        return next < entries.length;
-    }
-
-    /**
-     * Scans the next entry on the module path. A no-op if all entries have
-     * already been scanned.
-     *
-     * @throws FindException if an error occurs scanning the next entry
-     */
-    private void scanNextEntry() {
-        if (hasNextEntry()) {
-
-            long t0 = System.nanoTime();
-
-            Path entry = entries[next];
-            Map<String, ModuleReference> modules = scan(entry);
-            next++;
-
-            // update cache, ignoring duplicates
-            int initialSize = cachedModules.size();
-            for (Map.Entry<String, ModuleReference> e : modules.entrySet()) {
-                cachedModules.putIfAbsent(e.getKey(), e.getValue());
-            }
-
-            // update counters
-            int added = cachedModules.size() - initialSize;
-            moduleCount.add(added);
-
-            scanTime.addElapsedTimeFrom(t0);
-        }
-    }
-
-
-    /**
-     * Scan the given module path entry. If the entry is a directory then it is
-     * a directory of modules or an exploded module. If the entry is a regular
-     * file then it is assumed to be a packaged module.
-     *
-     * @throws FindException if an error occurs scanning the entry
-     */
-    private Map<String, ModuleReference> scan(Path entry) {
-
-        BasicFileAttributes attrs;
-        try {
-            attrs = Files.readAttributes(entry, BasicFileAttributes.class);
-        } catch (NoSuchFileException e) {
-            return Collections.emptyMap();
-        } catch (IOException ioe) {
-            throw new FindException(ioe);
-        }
-
-        try {
-
-            if (attrs.isDirectory()) {
-                Path mi = entry.resolve(MODULE_INFO);
-                if (!Files.exists(mi)) {
-                    // does not exist or unable to determine so assume a
-                    // directory of modules
-                    return scanDirectory(entry);
-                }
-            }
-
-            // packaged or exploded module
-            ModuleReference mref = readModule(entry, attrs);
-            if (mref != null) {
-                String name = mref.descriptor().name();
-                return Collections.singletonMap(name, mref);
-            } else {
-                // skipped
-                return Collections.emptyMap();
-            }
-
-        } catch (IOException ioe) {
-            throw new FindException(ioe);
-        }
-    }
-
-
-    /**
-     * Scans the given directory for packaged or exploded modules.
-     *
-     * @return a map of module name to ModuleReference for the modules found
-     *         in the directory
-     *
-     * @throws IOException if an I/O error occurs
-     * @throws FindException if an error occurs scanning the entry or the
-     *         directory contains two or more modules with the same name
-     */
-    private Map<String, ModuleReference> scanDirectory(Path dir)
-        throws IOException
-    {
-        // The map of name -> mref of modules found in this directory.
-        Map<String, ModuleReference> nameToReference = new HashMap<>();
-
-        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
-            for (Path entry : stream) {
-                BasicFileAttributes attrs;
-                try {
-                    attrs = Files.readAttributes(entry, BasicFileAttributes.class);
-                } catch (NoSuchFileException ignore) {
-                    // file has been removed or moved, ignore for now
-                    continue;
-                }
-
-                ModuleReference mref = readModule(entry, attrs);
-
-                // module found
-                if (mref != null) {
-                    // can have at most one version of a module in the directory
-                    String name = mref.descriptor().name();
-                    ModuleReference previous = nameToReference.put(name, mref);
-                    if (previous != null) {
-                        String fn1 = fileName(mref);
-                        String fn2 = fileName(previous);
-                        throw new FindException("Two versions of module "
-                                                 + name + " found in " + dir
-                                                 + " (" + fn1 + " and " + fn2 + ")");
-                    }
-                }
-            }
-        }
-
-        return nameToReference;
-    }
-
-
-    /**
-     * Locates a packaged or exploded module, returning a {@code ModuleReference}
-     * to the module. Returns {@code null} if the entry is skipped because it is
-     * to a directory that does not contain a module-info.class or it's a hidden
-     * file.
-     *
-     * @throws IOException if an I/O error occurs
-     * @throws FindException if the file is not recognized as a module or an
-     *         error occurs parsing its module descriptor
-     */
-    private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
-        throws IOException
-    {
-        try {
-
-            if (attrs.isDirectory()) {
-                return readExplodedModule(entry); // may return null
-            }
-
-            String fn = entry.getFileName().toString();
-            if (attrs.isRegularFile()) {
-                if (fn.endsWith(".jar")) {
-                    return readJar(entry);
-                } else if (fn.endsWith(".jmod")) {
-                    if (isLinkPhase)
-                        return readJMod(entry);
-                    throw new FindException("JMOD files not supported: " + entry);
-                }
-            }
-
-            // skip hidden files
-            if (fn.startsWith(".") || Files.isHidden(entry)) {
-                return null;
-            } else {
-                throw new FindException("Unrecognized module: " + entry);
-            }
-
-        } catch (InvalidModuleDescriptorException e) {
-            throw new FindException("Error reading module: " + entry, e);
-        }
-    }
-
-
-    /**
-     * Returns a string with the file name of the module if possible.
-     * If the module location is not a file URI then return the URI
-     * as a string.
-     */
-    private String fileName(ModuleReference mref) {
-        URI uri = mref.location().orElse(null);
-        if (uri != null) {
-            if (uri.getScheme().equalsIgnoreCase("file")) {
-                Path file = Paths.get(uri);
-                return file.getFileName().toString();
-            } else {
-                return uri.toString();
-            }
-        } else {
-            return "<unknown>";
-        }
-    }
-
-    // -- jmod files --
-
-    private Set<String> jmodPackages(JmodFile jf) {
-        return jf.stream()
-            .filter(e -> e.section() == Section.CLASSES)
-            .map(JmodFile.Entry::name)
-            .map(this::toPackageName)
-            .flatMap(Optional::stream)
-            .collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns a {@code ModuleReference} to a module in jmod file on the
-     * file system.
-     *
-     * @throws IOException
-     * @throws InvalidModuleDescriptorException
-     */
-    private ModuleReference readJMod(Path file) throws IOException {
-        try (JmodFile jf = new JmodFile(file)) {
-            ModuleDescriptor md;
-            try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
-                md = ModuleDescriptor.read(in, () -> jmodPackages(jf));
-            }
-            return ModuleReferences.newJModModule(md, file);
-        }
-    }
-
-
-    // -- JAR files --
-
-    private static final String SERVICES_PREFIX = "META-INF/services/";
-
-    /**
-     * Returns the service type corresponding to the name of a services
-     * configuration file if it is a valid Java identifier.
-     *
-     * 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 (Checks.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;
-    }
-
-    /**
-     * Treat the given JAR file as a module as follows:
-     *
-     * 1. The module name (and optionally the version) is derived from the file
-     *    name of the JAR file
-     * 2. All packages are exported and open
-     * 3. It has no non-exported/non-open packages
-     * 4. The contents of any META-INF/services configuration files are mapped
-     *    to "provides" declarations
-     * 5. The Main-Class attribute in the main attributes of the JAR manifest
-     *    is mapped to the module descriptor mainClass
-     */
-    private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
-        throws IOException
-    {
-        // Derive module name and version from JAR file name
-
-        String fn = jf.getName();
-        int i = fn.lastIndexOf(File.separator);
-        if (i != -1)
-            fn = fn.substring(i+1);
-
-        // drop .jar
-        String mn = fn.substring(0, fn.length()-4);
-        String vs = null;
-
-        // find first occurrence of -${NUMBER}. or -${NUMBER}$
-        Matcher matcher = Patterns.DASH_VERSION.matcher(mn);
-        if (matcher.find()) {
-            int start = matcher.start();
-
-            // attempt to parse the tail as a version string
-            try {
-                String tail = mn.substring(start+1);
-                ModuleDescriptor.Version.parse(tail);
-                vs = tail;
-            } catch (IllegalArgumentException ignore) { }
-
-            mn = mn.substring(0, start);
-        }
-
-        // finally clean up the module name
-        mn = cleanModuleName(mn);
-
-        // Builder throws IAE if module name is empty or invalid
-        ModuleDescriptor.Builder builder
-            = ModuleDescriptor.automaticModule(mn)
-                .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
-        if (vs != null)
-            builder.version(vs);
-
-        // scan the names of the entries in the JAR file
-        Map<Boolean, Set<String>> map = VersionedStream.stream(jf)
-                .filter(e -> !e.isDirectory())
-                .map(JarEntry::getName)
-                .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
-                                                   Collectors.toSet()));
-
-        Set<String> resources = map.get(Boolean.FALSE);
-        Set<String> configFiles = map.get(Boolean.TRUE);
-        // all packages are exported and open
-        resources.stream()
-                .map(this::toPackageName)
-                .flatMap(Optional::stream)
-                .distinct()
-                .forEach(pn -> builder.exports(pn).opens(pn));
-
-        // map names of service configuration files to service names
-        Set<String> serviceNames = configFiles.stream()
-                .map(this::toServiceName)
-                .flatMap(Optional::stream)
-                .collect(Collectors.toSet());
-
-        // parse each service configuration file
-        for (String sn : serviceNames) {
-            JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
-            List<String> providerClasses = new ArrayList<>();
-            try (InputStream in = jf.getInputStream(entry)) {
-                BufferedReader reader
-                    = new BufferedReader(new InputStreamReader(in, "UTF-8"));
-                String cn;
-                while ((cn = nextLine(reader)) != null) {
-                    if (cn.length() > 0) {
-                        providerClasses.add(cn);
-                    }
-                }
-            }
-            if (!providerClasses.isEmpty())
-                builder.provides(sn, providerClasses);
-        }
-
-        // Main-Class attribute if it exists
-        Manifest man = jf.getManifest();
-        if (man != null) {
-            Attributes attrs = man.getMainAttributes();
-            String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
-            if (mainClass != null)
-                builder.mainClass(mainClass.replace("/", "."));
-        }
-
-        return builder.build();
-    }
-
-    /**
-     * Patterns used to derive the module name from a JAR file name.
-     */
-    private static class Patterns {
-        static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
-        static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$");
-        static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]");
-        static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
-        static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
-        static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
-    }
-
-    /**
-     * Clean up candidate module name derived from a JAR file name.
-     */
-    private static String cleanModuleName(String mn) {
-        // drop trailing version from name
-        mn = Patterns.TRAILING_VERSION.matcher(mn).replaceAll("");
-
-        // replace non-alphanumeric
-        mn = Patterns.NON_ALPHANUM.matcher(mn).replaceAll(".");
-
-        // collapse repeating dots
-        mn = Patterns.REPEATING_DOTS.matcher(mn).replaceAll(".");
-
-        // drop leading dots
-        if (mn.length() > 0 && mn.charAt(0) == '.')
-            mn = Patterns.LEADING_DOTS.matcher(mn).replaceAll("");
-
-        // drop trailing dots
-        int len = mn.length();
-        if (len > 0 && mn.charAt(len-1) == '.')
-            mn = Patterns.TRAILING_DOTS.matcher(mn).replaceAll("");
-
-        return mn;
-    }
-
-    private Set<String> jarPackages(JarFile jf) {
-        return VersionedStream.stream(jf)
-                .filter(e -> !e.isDirectory())
-                .map(JarEntry::getName)
-                .map(this::toPackageName)
-                .flatMap(Optional::stream)
-                .collect(Collectors.toSet());
-    }
-
-    /**
-     * Returns a {@code ModuleReference} to a module in modular JAR file on
-     * the file system.
-     *
-     * @throws IOException
-     * @throws FindException
-     * @throws InvalidModuleDescriptorException
-     */
-    private ModuleReference readJar(Path file) throws IOException {
-        try (JarFile jf = new JarFile(file.toFile(),
-                                      true,               // verify
-                                      ZipFile.OPEN_READ,
-                                      releaseVersion))
-        {
-            ModuleDescriptor md;
-            JarEntry entry = jf.getJarEntry(MODULE_INFO);
-            if (entry == null) {
-
-                // no module-info.class so treat it as automatic module
-                try {
-                    md = deriveModuleDescriptor(jf);
-                } catch (IllegalArgumentException iae) {
-                    throw new FindException(
-                        "Unable to derive module descriptor for: "
-                        + jf.getName(), iae);
-                }
-
-            } else {
-                md = ModuleDescriptor.read(jf.getInputStream(entry),
-                                           () -> jarPackages(jf));
-            }
-
-            return ModuleReferences.newJarModule(md, file);
-        }
-    }
-
-
-    // -- exploded directories --
-
-    private Set<String> explodedPackages(Path dir) {
-        try {
-            return Files.find(dir, Integer.MAX_VALUE,
-                              ((path, attrs) -> attrs.isRegularFile()))
-                    .map(path -> dir.relativize(path))
-                    .map(this::toPackageName)
-                    .flatMap(Optional::stream)
-                    .collect(Collectors.toSet());
-        } catch (IOException x) {
-            throw new UncheckedIOException(x);
-        }
-    }
-
-    /**
-     * Returns a {@code ModuleReference} to an exploded module on the file
-     * system or {@code null} if {@code module-info.class} not found.
-     *
-     * @throws IOException
-     * @throws InvalidModuleDescriptorException
-     */
-    private ModuleReference readExplodedModule(Path dir) throws IOException {
-        Path mi = dir.resolve(MODULE_INFO);
-        ModuleDescriptor md;
-        try (InputStream in = Files.newInputStream(mi)) {
-            md = ModuleDescriptor.read(new BufferedInputStream(in),
-                                       () -> explodedPackages(dir));
-        } catch (NoSuchFileException e) {
-            // for now
-            return null;
-        }
-        return ModuleReferences.newExplodedModule(md, dir);
-    }
-
-    /**
-     * Maps the name of an entry in a JAR or ZIP file to a package name.
-     *
-     * @throws IllegalArgumentException if the name is a class file in
-     *         the top-level directory of the JAR/ZIP file (and it's
-     *         not module-info.class)
-     */
-    private Optional<String> toPackageName(String name) {
-        assert !name.endsWith("/");
-
-        int index = name.lastIndexOf("/");
-        if (index == -1) {
-            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
-                throw new IllegalArgumentException(name
-                        + " found in top-level directory:"
-                        + " (unnamed package not allowed in module)");
-            }
-            return Optional.empty();
-        }
-
-        String pn = name.substring(0, index).replace('/', '.');
-        if (Checks.isJavaIdentifier(pn)) {
-            return Optional.of(pn);
-        } else {
-            // not a valid package name
-            return Optional.empty();
-        }
-    }
-
-    /**
-     * Maps the relative path of an entry in an exploded module to a package
-     * name.
-     *
-     * @throws IllegalArgumentException if the name is a class file in
-     *         the top-level directory (and it's not module-info.class)
-     */
-    private Optional<String> toPackageName(Path file) {
-        assert file.getRoot() == null;
-
-        Path parent = file.getParent();
-        if (parent == null) {
-            String name = file.toString();
-            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
-                throw new IllegalArgumentException(name
-                        + " found in in top-level directory"
-                        + " (unnamed package not allowed in module)");
-            }
-            return Optional.empty();
-        }
-
-        String pn = parent.toString().replace(File.separatorChar, '.');
-        if (Checks.isJavaIdentifier(pn)) {
-            return Optional.of(pn);
-        } else {
-            // not a valid package name
-            return Optional.empty();
-        }
-    }
-
-    private static final PerfCounter scanTime
-        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
-    private static final PerfCounter moduleCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Mon Dec 19 16:05:38 2016 +0000
@@ -26,96 +26,42 @@
 package java.lang.module;
 
 import java.io.IOException;
-import java.io.UncheckedIOException;
 import java.net.URI;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes.HashSupplier;
 
 
 /**
  * A reference to a module's content.
  *
- * <p> A module reference contains the module's descriptor and its location, if
- * known.  It also has the ability to create a {@link ModuleReader} in order to
- * access the module's content, which may be inside the Java run-time system
- * itself or in an artifact such as a modular JAR file.
+ * <p> A module reference is a concrete implementation of this class that
+ * implements the abstract methods defined by this class. It contains the
+ * module's descriptor and its location, if known.  It also has the ability to
+ * create a {@link ModuleReader} in order to access the module's content, which
+ * may be inside the Java run-time system itself or in an artifact such as a
+ * modular JAR file.
  *
  * @see ModuleFinder
  * @see ModuleReader
  * @since 9
  */
 
-public final class ModuleReference {
+public abstract class ModuleReference {
 
     private final ModuleDescriptor descriptor;
     private final URI location;
-    private final Supplier<ModuleReader> readerSupplier;
-
-    // true if this is a reference to a patched module
-    private boolean patched;
-
-    // the function that computes the hash of this module reference
-    private final HashSupplier hasher;
-
-    // cached hash to avoid needing to compute it many times
-    private byte[] cachedHash;
-
 
     /**
      * Constructs a new instance of this class.
-     */
-    ModuleReference(ModuleDescriptor descriptor,
-                    URI location,
-                    Supplier<ModuleReader> readerSupplier,
-                    boolean patched,
-                    HashSupplier hasher)
-
-    {
-        this.descriptor = Objects.requireNonNull(descriptor);
-        this.location = location;
-        this.readerSupplier = Objects.requireNonNull(readerSupplier);
-        this.patched = patched;
-        this.hasher = hasher;
-    }
-
-    /**
-     * Constructs a new instance of this class.
-     */
-    ModuleReference(ModuleDescriptor descriptor,
-                    URI location,
-                    Supplier<ModuleReader> readerSupplier,
-                    HashSupplier hasher)
-
-    {
-        this(descriptor, location, readerSupplier, false, hasher);
-    }
-
-
-    /**
-     * Constructs a new instance of this class.
-     *
-     * <p> The {@code readSupplier} parameter is the supplier of the {@link
-     * ModuleReader} that may be used to read the module content. Its {@link
-     * Supplier#get() get()} method throws {@link UncheckedIOException} if an
-     * I/O error occurs opening the module content. The {@code get()} method
-     * throws {@link SecurityException} if opening the module is denied by the
-     * security manager.
      *
      * @param descriptor
      *        The module descriptor
      * @param location
      *        The module location or {@code null} if not known
-     * @param readerSupplier
-     *        The {@code Supplier} of the {@code ModuleReader}
      */
-    public ModuleReference(ModuleDescriptor descriptor,
-                           URI location,
-                           Supplier<ModuleReader> readerSupplier)
-    {
-        this(descriptor, location, readerSupplier, false, null);
+    protected ModuleReference(ModuleDescriptor descriptor, URI location) {
+        this.descriptor = Objects.requireNonNull(descriptor);
+        this.location = location;
     }
 
     /**
@@ -123,11 +69,10 @@
      *
      * @return The module descriptor
      */
-    public ModuleDescriptor descriptor() {
+    public final ModuleDescriptor descriptor() {
         return descriptor;
     }
 
-
     /**
      * Returns the location of this module's content, if known.
      *
@@ -139,18 +84,13 @@
      *
      * @return The location or an empty {@code Optional} if not known
      */
-    public Optional<URI> location() {
+    public final Optional<URI> location() {
         return Optional.ofNullable(location);
     }
 
-
     /**
      * Opens the module content for reading.
      *
-     * <p> This method opens the module content by invoking the {@link
-     * Supplier#get() get()} method of the {@code readSupplier} specified at
-     * construction time. </p>
-     *
      * @return A {@code ModuleReader} to read the module
      *
      * @throws IOException
@@ -158,113 +98,5 @@
      * @throws SecurityException
      *         If denied by the security manager
      */
-    public ModuleReader open() throws IOException {
-        try {
-            return readerSupplier.get();
-        } catch (UncheckedIOException e) {
-            throw e.getCause();
-        }
-
-    }
-
-
-    /**
-     * Returns {@code true} if this module has been patched via --patch-module.
-     */
-    boolean isPatched() {
-        return patched;
-    }
-
-    /**
-     * Returns the hash supplier for this module.
-     */
-    HashSupplier hasher() {
-        return hasher;
-    }
-
-    /**
-     * Computes the hash of this module. Returns {@code null} if the hash
-     * cannot be computed.
-     *
-     * @throws java.io.UncheckedIOException if an I/O error occurs
-     */
-    byte[] computeHash(String algorithm) {
-        byte[] result = cachedHash;
-        if (result != null)
-            return result;
-        if (hasher == null)
-            return null;
-        cachedHash = result = hasher.generate(algorithm);
-        return result;
-    }
-
-    /**
-     * Computes a hash code for this module reference.
-     *
-     * <p> The hash code is based upon the components of the reference, and
-     * satisfies the general contract of the {@link Object#hashCode
-     * Object.hashCode} method. </p>
-     *
-     * @return The hash-code value for this module reference
-     */
-    @Override
-    public int hashCode() {
-        int hc = hash;
-        if (hc == 0) {
-            hc = descriptor.hashCode();
-            hc = 43 * hc + readerSupplier.hashCode();
-            hc = 43 * hc + Objects.hashCode(location);
-            hc = 43 * hc + Objects.hashCode(hasher);
-            hc = 43 * hc + Boolean.hashCode(patched);
-            if (hc == 0)
-                hc = -1;
-            hash = hc;
-        }
-        return hc;
-    }
-
-    private int hash;
-
-    /**
-     * Tests this module reference for equality with the given object.
-     *
-     * <p> If the given object is not a {@code ModuleReference} then this
-     * method returns {@code false}. Two module references are equal if their
-     * module descriptors are equal, their locations are equal or both unknown,
-     * and were created with equal supplier objects to access the module
-     * content. </p>
-     *
-     * <p> This method satisfies the general contract of the {@link
-     * java.lang.Object#equals(Object) Object.equals} method. </p>
-     *
-     * @param   ob
-     *          the object to which this object is to be compared
-     *
-     * @return  {@code true} if, and only if, the given object is a module
-     *          reference that is equal to this module reference
-     */
-    @Override
-    public boolean equals(Object ob) {
-        if (!(ob instanceof ModuleReference))
-            return false;
-        ModuleReference that = (ModuleReference)ob;
-
-        return Objects.equals(this.descriptor, that.descriptor)
-                && Objects.equals(this.location, that.location)
-                && Objects.equals(this.readerSupplier, that.readerSupplier)
-                && Objects.equals(this.hasher, that.hasher)
-                && this.patched == that.patched;
-    }
-
-    /**
-     * Returns a string describing this module reference.
-     *
-     * @return A string describing this module reference
-     */
-    @Override
-    public String toString() {
-        return ("[module " + descriptor().name()
-                + ", location=" + location + "]");
-    }
-
+    public abstract ModuleReader open() throws IOException;
 }
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,443 +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 java.lang.module;
-
-import java.io.File;
-import java.io.IOError;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.net.URI;
-import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.function.Supplier;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.zip.ZipFile;
-
-import jdk.internal.jmod.JmodFile;
-import jdk.internal.misc.JavaLangAccess;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.ModuleBootstrap;
-import jdk.internal.module.ModuleHashes;
-import jdk.internal.module.ModuleHashes.HashSupplier;
-import jdk.internal.module.ModulePatcher;
-import jdk.internal.util.jar.VersionedStream;
-import sun.net.www.ParseUtil;
-
-
-/**
- * A factory for creating ModuleReference implementations where the modules are
- * packaged as modular JAR file, JMOD files or where the modules are exploded
- * on the file system.
- */
-
-class ModuleReferences {
-
-    private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
-
-    private ModuleReferences() { }
-
-    /**
-     * Creates a ModuleReference to a module or to patched module when
-     * creating modules for the boot Layer and --patch-module is specified.
-     */
-    private static ModuleReference newModule(ModuleDescriptor md,
-                                             URI uri,
-                                             Supplier<ModuleReader> supplier,
-                                             HashSupplier hasher) {
-
-        ModuleReference mref = new ModuleReference(md, uri, supplier, hasher);
-        if (JLA.getBootLayer() == null)
-            mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
-
-        return mref;
-    }
-
-    /**
-     * Creates a ModuleReference to a module packaged as a modular JAR.
-     */
-    static ModuleReference newJarModule(ModuleDescriptor md, Path file) {
-        URI uri = file.toUri();
-        Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
-        return newModule(md, uri, supplier, hasher);
-    }
-
-    /**
-     * Creates a ModuleReference to a module packaged as a JMOD.
-     */
-    static ModuleReference newJModModule(ModuleDescriptor md, Path file) {
-        URI uri = file.toUri();
-        Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
-        return newModule(md, file.toUri(), supplier, hasher);
-    }
-
-    /**
-     * Creates a ModuleReference to an exploded module.
-     */
-    static ModuleReference newExplodedModule(ModuleDescriptor md, Path dir) {
-        Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
-        return newModule(md, dir.toUri(), supplier, null);
-    }
-
-
-    /**
-     * A base module reader that encapsulates machinery required to close the
-     * module reader safely.
-     */
-    static abstract class SafeCloseModuleReader implements ModuleReader {
-
-        // RW lock to support safe close
-        private final ReadWriteLock lock = new ReentrantReadWriteLock();
-        private final Lock readLock = lock.readLock();
-        private final Lock writeLock = lock.writeLock();
-        private boolean closed;
-
-        SafeCloseModuleReader() { }
-
-        /**
-         * Returns a URL to  resource. This method is invoked by the find
-         * method to do the actual work of finding the resource.
-         */
-        abstract Optional<URI> implFind(String name) throws IOException;
-
-        /**
-         * Returns an input stream for reading a resource. This method is
-         * invoked by the open method to do the actual work of opening
-         * an input stream to the resource.
-         */
-        abstract Optional<InputStream> implOpen(String name) throws IOException;
-
-        /**
-         * Returns a stream of the names of resources in the module. This
-         * method is invoked by the list method to do the actual work of
-         * creating the stream.
-         */
-        abstract Stream<String> implList() throws IOException;
-
-        /**
-         * Closes the module reader. This method is invoked by close to do the
-         * actual work of closing the module reader.
-         */
-        abstract void implClose() throws IOException;
-
-        @Override
-        public final Optional<URI> find(String name) throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implFind(name);
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-
-        @Override
-        public final Optional<InputStream> open(String name) throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implOpen(name);
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        @Override
-        public final Stream<String> list() throws IOException {
-            readLock.lock();
-            try {
-                if (!closed) {
-                    return implList();
-                } else {
-                    throw new IOException("ModuleReader is closed");
-                }
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        @Override
-        public final void close() throws IOException {
-            writeLock.lock();
-            try {
-                if (!closed) {
-                    closed = true;
-                    implClose();
-                }
-            } finally {
-                writeLock.unlock();
-            }
-        }
-    }
-
-
-    /**
-     * A ModuleReader for a modular JAR file.
-     */
-    static class JarModuleReader extends SafeCloseModuleReader {
-        private final JarFile jf;
-        private final URI uri;
-
-        static JarFile newJarFile(Path path) {
-            try {
-                return new JarFile(path.toFile(),
-                                   true,               // verify
-                                   ZipFile.OPEN_READ,
-                                   JarFile.runtimeVersion());
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-        }
-
-        JarModuleReader(Path path, URI uri) {
-            this.jf = newJarFile(path);
-            this.uri = uri;
-        }
-
-        private JarEntry getEntry(String name) {
-            return jf.getJarEntry(Objects.requireNonNull(name));
-        }
-
-        @Override
-        Optional<URI> implFind(String name) throws IOException {
-            JarEntry je = getEntry(name);
-            if (je != null) {
-                if (jf.isMultiRelease())
-                    name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
-                String encodedPath = ParseUtil.encodePath(name, false);
-                String uris = "jar:" + uri + "!/" + encodedPath;
-                return Optional.of(URI.create(uris));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Optional<InputStream> implOpen(String name) throws IOException {
-            JarEntry je = getEntry(name);
-            if (je != null) {
-                return Optional.of(jf.getInputStream(je));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Stream<String> implList() throws IOException {
-            // take snapshot to avoid async close
-            List<String> names = VersionedStream.stream(jf)
-                    .filter(e -> !e.isDirectory())
-                    .map(JarEntry::getName)
-                    .collect(Collectors.toList());
-            return names.stream();
-        }
-
-        @Override
-        void implClose() throws IOException {
-            jf.close();
-        }
-    }
-
-
-    /**
-     * A ModuleReader for a JMOD file.
-     */
-    static class JModModuleReader extends SafeCloseModuleReader {
-        private final JmodFile jf;
-        private final URI uri;
-
-        static JmodFile newJmodFile(Path path) {
-            try {
-                return new JmodFile(path);
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-        }
-
-        JModModuleReader(Path path, URI uri) {
-            this.jf = newJmodFile(path);
-            this.uri = uri;
-        }
-
-        private JmodFile.Entry getEntry(String name) {
-            Objects.requireNonNull(name);
-            return jf.getEntry(JmodFile.Section.CLASSES, name);
-        }
-
-        @Override
-        Optional<URI> implFind(String name) {
-            JmodFile.Entry je = getEntry(name);
-            if (je != null) {
-                String encodedPath = ParseUtil.encodePath(name, false);
-                String uris = "jmod:" + uri + "!/" + encodedPath;
-                return Optional.of(URI.create(uris));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Optional<InputStream> implOpen(String name) throws IOException {
-            JmodFile.Entry je = getEntry(name);
-            if (je != null) {
-                return Optional.of(jf.getInputStream(je));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        Stream<String> implList() throws IOException {
-            // take snapshot to avoid async close
-            List<String> names = jf.stream()
-                    .filter(e -> e.section() == JmodFile.Section.CLASSES)
-                    .map(JmodFile.Entry::name)
-                    .collect(Collectors.toList());
-            return names.stream();
-        }
-
-        @Override
-        void implClose() throws IOException {
-            jf.close();
-        }
-    }
-
-
-    /**
-     * A ModuleReader for an exploded module.
-     */
-    static class ExplodedModuleReader implements ModuleReader {
-        private final Path dir;
-        private volatile boolean closed;
-
-        ExplodedModuleReader(Path dir) {
-            this.dir = dir;
-
-            // when running with a security manager then check that the caller
-            // has access to the directory.
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                boolean unused = Files.isDirectory(dir);
-            }
-        }
-
-        /**
-         * Returns a Path to access to the given resource.
-         */
-        private Path toPath(String name) {
-            Path path = Paths.get(name.replace('/', File.separatorChar));
-            if (path.getRoot() == null) {
-                return dir.resolve(path);
-            } else {
-                // drop the root component so that the resource is
-                // located relative to the module directory
-                int n = path.getNameCount();
-                return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
-            }
-        }
-
-        /**
-         * Throws IOException if the module reader is closed;
-         */
-        private void ensureOpen() throws IOException {
-            if (closed) throw new IOException("ModuleReader is closed");
-        }
-
-        @Override
-        public Optional<URI> find(String name) throws IOException {
-            ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
-                try {
-                    return Optional.of(path.toUri());
-                } catch (IOError e) {
-                    throw (IOException) e.getCause();
-                }
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<InputStream> open(String name) throws IOException {
-            ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
-                return Optional.of(Files.newInputStream(path));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<ByteBuffer> read(String name) throws IOException {
-            ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
-                return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Stream<String> list() throws IOException {
-            ensureOpen();
-            // sym links not followed
-            return Files.find(dir, Integer.MAX_VALUE,
-                              (path, attrs) -> attrs.isRegularFile())
-                    .map(f -> dir.relativize(f)
-                                 .toString()
-                                 .replace(File.separatorChar, '/'));
-        }
-
-        @Override
-        public void close() {
-            closed = true;
-        }
-    }
-
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Mon Dec 19 16:05:38 2016 +0000
@@ -46,6 +46,7 @@
 import java.util.stream.Collectors;
 
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
 
 /**
  * The resolver used by {@link Configuration#resolveRequires} and
@@ -438,24 +439,32 @@
      */
     private void checkHashes() {
         for (ModuleReference mref : nameToReference.values()) {
-            ModuleDescriptor descriptor = mref.descriptor();
 
-            // get map of module hashes
-            Optional<ModuleHashes> ohashes = descriptor.hashes();
-            if (!ohashes.isPresent())
+            // get the recorded hashes, if any
+            if (!(mref instanceof ModuleReferenceImpl))
                 continue;
-            ModuleHashes hashes = ohashes.get();
+            ModuleHashes hashes = ((ModuleReferenceImpl)mref).recordedHashes();
+            if (hashes == null)
+                continue;
 
+            ModuleDescriptor descriptor = mref.descriptor();
             String algorithm = hashes.algorithm();
             for (String dn : hashes.names()) {
-                ModuleReference other = nameToReference.get(dn);
-                if (other == null) {
+                ModuleReference mref2 = nameToReference.get(dn);
+                if (mref2 == null) {
                     ResolvedModule resolvedModule = findInParent(dn);
                     if (resolvedModule != null)
-                        other = resolvedModule.reference();
+                        mref2 = resolvedModule.reference();
+                }
+                if (mref2 == null)
+                    continue;
+
+                if (!(mref2 instanceof ModuleReferenceImpl)) {
+                    fail("Unable to compute the hash of module %s", dn);
                 }
 
                 // skip checking the hash if the module has been patched
+                ModuleReferenceImpl other = (ModuleReferenceImpl)mref2;
                 if (other != null && !other.isPatched()) {
                     byte[] recordedHash = hashes.hashFor(dn);
                     byte[] actualHash = other.computeHash(algorithm);
--- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,443 +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 java.lang.module;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.net.URI;
-import java.net.URLConnection;
-import java.nio.ByteBuffer;
-import java.util.ArrayDeque;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-import jdk.internal.jimage.ImageLocation;
-import jdk.internal.jimage.ImageReader;
-import jdk.internal.jimage.ImageReaderFactory;
-import jdk.internal.misc.JavaNetUriAccess;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.ModuleBootstrap;
-import jdk.internal.module.ModuleHashes;
-import jdk.internal.module.ModuleHashes.HashSupplier;
-import jdk.internal.module.SystemModules;
-import jdk.internal.module.ModulePatcher;
-import jdk.internal.perf.PerfCounter;
-
-/**
- * A {@code ModuleFinder} that finds modules that are linked into the
- * run-time image.
- *
- * The modules linked into the run-time image are assumed to have the
- * Packages attribute.
- */
-
-class SystemModuleFinder implements ModuleFinder {
-
-    private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
-
-    private static final PerfCounter initTime
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
-    private static final PerfCounter moduleCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
-    private static final PerfCounter packageCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
-    private static final PerfCounter exportsCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
-    // ImageReader used to access all modules in the image
-    private static final ImageReader imageReader;
-
-    // the set of modules in the run-time image
-    private static final Set<ModuleReference> modules;
-
-    // maps module name to module reference
-    private static final Map<String, ModuleReference> nameToModule;
-
-    /**
-     * For now, the module references are created eagerly on the assumption
-     * that service binding will require all modules to be located.
-     */
-    static {
-        long t0 = System.nanoTime();
-        imageReader = ImageReaderFactory.getImageReader();
-
-        String[] names = moduleNames();
-        ModuleDescriptor[] descriptors = descriptors(names);
-
-        int n = names.length;
-        moduleCount.add(n);
-
-        ModuleReference[] mods = new ModuleReference[n];
-
-        @SuppressWarnings(value = {"rawtypes", "unchecked"})
-        Entry<String, ModuleReference>[] map
-            = (Entry<String, ModuleReference>[])new Entry[n];
-
-        for (int i = 0; i < n; i++) {
-            ModuleDescriptor md = descriptors[i];
-
-            // create the ModuleReference
-            ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i]));
-
-            mods[i] = mref;
-            map[i] = Map.entry(names[i], mref);
-
-            // counters
-            packageCount.add(md.packages().size());
-            exportsCount.add(md.exports().size());
-        }
-
-        modules = Set.of(mods);
-        nameToModule = Map.ofEntries(map);
-
-        initTime.addElapsedTimeFrom(t0);
-    }
-
-    /*
-     * Returns an array of ModuleDescriptor of the given module names.
-     *
-     * This obtains ModuleDescriptors from SystemModules class that is generated
-     * from the jlink system-modules plugin.  ModuleDescriptors have already
-     * been validated at link time.
-     *
-     * If java.base is patched, or fastpath is disabled for troubleshooting
-     * purpose, it will fall back to find system modules via jrt file system.
-     */
-    private static ModuleDescriptor[] descriptors(String[] names) {
-        // fastpath is enabled by default.
-        // It can be disabled for troubleshooting purpose.
-        boolean disabled =
-            System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
-
-        // fast loading of ModuleDescriptor of system modules
-        if (isFastPathSupported() && !disabled)
-            return SystemModules.modules();
-
-        // if fast loading of ModuleDescriptors is disabled
-        // fallback to read module-info.class
-        ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length];
-        for (int i = 0; i < names.length; i++) {
-            String mn = names[i];
-            ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
-            descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc));
-
-            // add the recorded hashes of tied modules
-            Hashes.add(descriptors[i]);
-        }
-        return descriptors;
-    }
-
-    private static boolean isFastPathSupported() {
-       return SystemModules.MODULE_NAMES.length > 0;
-    }
-
-    private static String[] moduleNames() {
-        if (isFastPathSupported())
-            // module names recorded at link time
-            return SystemModules.MODULE_NAMES;
-
-        // this happens when java.base is patched with java.base
-        // from an exploded image
-        return imageReader.getModuleNames();
-    }
-
-    private static ModuleReference toModuleReference(ModuleDescriptor md,
-                                                     HashSupplier hash)
-    {
-        String mn = md.name();
-        URI uri = JNUA.create("jrt", "/".concat(mn));
-
-        Supplier<ModuleReader> readerSupplier = new Supplier<>() {
-            @Override
-            public ModuleReader get() {
-                return new ImageModuleReader(mn, uri);
-            }
-        };
-
-        ModuleReference mref =
-            new ModuleReference(md, uri, readerSupplier, hash);
-
-        // may need a reference to a patched module if --patch-module specified
-        mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
-
-        return mref;
-    }
-
-    private static HashSupplier hashSupplier(int index, String name) {
-        if (isFastPathSupported()) {
-            return new HashSupplier() {
-                @Override
-                public byte[] generate(String algorithm) {
-                    return SystemModules.MODULES_TO_HASH[index];
-                }
-            };
-        } else {
-            return Hashes.hashFor(name);
-        }
-    }
-
-    /*
-     * This helper class is only used when SystemModules is patched.
-     * It will get the recorded hashes from module-info.class.
-     */
-    private static class Hashes {
-        static Map<String, byte[]> hashes = new HashMap<>();
-
-        static void add(ModuleDescriptor descriptor) {
-            Optional<ModuleHashes> ohashes = descriptor.hashes();
-            if (ohashes.isPresent()) {
-                hashes.putAll(ohashes.get().hashes());
-            }
-        }
-
-        static HashSupplier hashFor(String name) {
-            if (!hashes.containsKey(name))
-                return null;
-
-            return new HashSupplier() {
-                @Override
-                public byte[] generate(String algorithm) {
-                    return hashes.get(name);
-                }
-            };
-        }
-    }
-
-    SystemModuleFinder() { }
-
-    @Override
-    public Optional<ModuleReference> find(String name) {
-        Objects.requireNonNull(name);
-        return Optional.ofNullable(nameToModule.get(name));
-    }
-
-    @Override
-    public Set<ModuleReference> findAll() {
-        return modules;
-    }
-
-
-    /**
-     * A ModuleReader for reading resources from a module linked into the
-     * run-time image.
-     */
-    static class ImageModuleReader implements ModuleReader {
-        private final String module;
-        private volatile boolean closed;
-
-        /**
-         * If there is a security manager set then check permission to
-         * connect to the run-time image.
-         */
-        private static void checkPermissionToConnect(URI uri) {
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                try {
-                    URLConnection uc = uri.toURL().openConnection();
-                    sm.checkPermission(uc.getPermission());
-                } catch (IOException ioe) {
-                    throw new UncheckedIOException(ioe);
-                }
-            }
-        }
-
-        ImageModuleReader(String module, URI uri) {
-            checkPermissionToConnect(uri);
-            this.module = module;
-        }
-
-        /**
-         * Returns the ImageLocation for the given resource, {@code null}
-         * if not found.
-         */
-        private ImageLocation findImageLocation(String name) throws IOException {
-            Objects.requireNonNull(name);
-            if (closed)
-                throw new IOException("ModuleReader is closed");
-            if (imageReader != null) {
-                return imageReader.findLocation(module, name);
-            } else {
-                // not an images build
-                return null;
-            }
-        }
-
-        @Override
-        public Optional<URI> find(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                URI u = URI.create("jrt:/" + module + "/" + name);
-                return Optional.of(u);
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<InputStream> open(String name) throws IOException {
-            return read(name).map(this::toInputStream);
-        }
-
-        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
-            try {
-                int rem = bb.remaining();
-                byte[] bytes = new byte[rem];
-                bb.get(bytes);
-                return new ByteArrayInputStream(bytes);
-            } finally {
-                release(bb);
-            }
-        }
-
-        @Override
-        public Optional<ByteBuffer> read(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                return Optional.of(imageReader.getResourceBuffer(location));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public void release(ByteBuffer bb) {
-            Objects.requireNonNull(bb);
-            ImageReader.releaseByteBuffer(bb);
-        }
-
-        @Override
-        public Stream<String> list() throws IOException {
-            if (closed)
-                throw new IOException("ModuleReader is closed");
-
-            Spliterator<String> s = new ModuleContentSpliterator(module);
-            return StreamSupport.stream(s, false);
-        }
-
-        @Override
-        public void close() {
-            // nothing else to do
-            closed = true;
-        }
-    }
-
-    /**
-     * A Spliterator for traversing the resources of a module linked into the
-     * run-time image.
-     */
-    static class ModuleContentSpliterator implements Spliterator<String> {
-        final String moduleRoot;
-        final Deque<ImageReader.Node> stack;
-        Iterator<ImageReader.Node> iterator;
-
-        ModuleContentSpliterator(String module) throws IOException {
-            moduleRoot = "/modules/" + module;
-            stack = new ArrayDeque<>();
-
-            // push the root node to the stack to get started
-            ImageReader.Node dir = imageReader.findNode(moduleRoot);
-            if (dir == null || !dir.isDirectory())
-                throw new IOException(moduleRoot + " not a directory");
-            stack.push(dir);
-            iterator = Collections.emptyIterator();
-        }
-
-        /**
-         * Returns the name of the next non-directory node or {@code null} if
-         * there are no remaining nodes to visit.
-         */
-        private String next() throws IOException {
-            for (;;) {
-                while (iterator.hasNext()) {
-                    ImageReader.Node node = iterator.next();
-                    String name = node.getName();
-                    if (node.isDirectory()) {
-                        // build node
-                        ImageReader.Node dir = imageReader.findNode(name);
-                        assert dir.isDirectory();
-                        stack.push(dir);
-                    } else {
-                        // strip /modules/$MODULE/ prefix
-                        return name.substring(moduleRoot.length() + 1);
-                    }
-                }
-
-                if (stack.isEmpty()) {
-                    return null;
-                } else {
-                    ImageReader.Node dir = stack.poll();
-                    assert dir.isDirectory();
-                    iterator = dir.getChildren().iterator();
-                }
-            }
-        }
-
-        @Override
-        public boolean tryAdvance(Consumer<? super String> action) {
-            String next;
-            try {
-                next = next();
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-            if (next != null) {
-                action.accept(next);
-                return true;
-            } else {
-                return false;
-            }
-        }
-
-        @Override
-        public Spliterator<String> trySplit() {
-            return null;
-        }
-
-        @Override
-        public int characteristics() {
-            return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
-        }
-
-        @Override
-        public long estimateSize() {
-            return Long.MAX_VALUE;
-        }
-    }
-}
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Mon Dec 19 16:05:38 2016 +0000
@@ -28,9 +28,11 @@
 import java.lang.annotation.Annotation;
 import java.security.AccessController;
 
+import jdk.internal.misc.VM;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.reflect.ReflectionFactory;
+import sun.security.action.GetPropertyAction;
 
 /**
  * The AccessibleObject class is the base class for Field, Method and
@@ -172,8 +174,10 @@
 
         // package is open to caller
         String pn = packageName(declaringClass);
-        if (declaringModule.isOpen(pn, callerModule))
+        if (declaringModule.isOpen(pn, callerModule)) {
+            printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule);
             return;
+        }
 
         // package is exported to caller and class/member is public
         boolean isExported = declaringModule.isExported(pn, callerModule);
@@ -185,8 +189,10 @@
             modifiers = ((Field) this).getModifiers();
         }
         boolean isMemberPublic = Modifier.isPublic(modifiers);
-        if (isExported && isClassPublic && isMemberPublic)
+        if (isExported && isClassPublic && isMemberPublic) {
+            printStackTraceIfExportedReflectively(declaringModule, pn, callerModule);
             return;
+        }
 
         // not accessible
         String msg = "Unable to make ";
@@ -198,7 +204,44 @@
         else
             msg += "opens";
         msg += " " + pn + "\" to " + callerModule;
-        Reflection.throwInaccessibleObjectException(msg);
+        InaccessibleObjectException e = new InaccessibleObjectException(msg);
+        if (Reflection.printStackTraceWhenAccessFails()) {
+            e.printStackTrace(System.err);
+        }
+        throw e;
+    }
+
+    private void printStackTraceIfOpenedReflectively(Module module,
+                                                     String pn,
+                                                     Module other) {
+        printStackTraceIfExposedReflectively(module, pn, other, true);
+    }
+
+    private void printStackTraceIfExportedReflectively(Module module,
+                                                       String pn,
+                                                       Module other) {
+        printStackTraceIfExposedReflectively(module, pn, other, false);
+    }
+
+    private void printStackTraceIfExposedReflectively(Module module,
+                                                      String pn,
+                                                      Module other,
+                                                      boolean open)
+    {
+        if (Reflection.printStackTraceWhenAccessSucceeds()
+            && !module.isStaticallyExportedOrOpen(pn, other, open))
+        {
+            String msg = other + " allowed to invoke setAccessible on ";
+            if (this instanceof Field)
+                msg += "field ";
+            msg += this;
+            new Exception(msg) {
+                private static final long serialVersionUID = 42L;
+                public String toString() {
+                    return "WARNING: " + getMessage();
+                }
+            }.printStackTrace(System.err);
+        }
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Mon Dec 19 16:05:38 2016 +0000
@@ -246,7 +246,6 @@
          */
         public Controller addOpens(Module source, String pn, Module target) {
             Objects.requireNonNull(source);
-            Objects.requireNonNull(source);
             Objects.requireNonNull(target);
             ensureInLayer(source);
             Modules.addOpens(source, pn, target);
@@ -541,7 +540,7 @@
      * {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to
      * avoid deadlocks during class loading. In addition, the entity creating
      * a new layer with this method should arrange that the class loaders are
-     * ready to load from these module before there are any attempts to load
+     * ready to load from these modules before there are any attempts to load
      * classes or resources.
      *
      * <p> Creating a {@code Layer} can fail for the following reasons: </p>
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Mon Dec 19 16:05:38 2016 +0000
@@ -559,7 +559,7 @@
      * Returns {@code true} if this module exports or opens a package to
      * the given module via its module declaration.
      */
-    private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
+    boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
         // package is open to everyone or <other>
         Map<String, Set<Module>> openPackages = this.openPackages;
         if (openPackages != null) {
@@ -643,6 +643,12 @@
      * <em>open</em>) to the given module. It also has no effect if
      * invoked on an {@link ModuleDescriptor#isOpen open} module. </p>
      *
+     * @apiNote As specified in section 5.4.3 of the <cite>The Java&trade;
+     * Virtual Machine Specification </cite>, if an attempt to resolve a
+     * symbolic reference fails because of a linkage error, then subsequent
+     * attempts to resolve the reference always fail with the same error that
+     * was thrown as a result of the initial resolution attempt.
+     *
      * @param  pn
      *         The package name
      * @param  other
@@ -656,6 +662,7 @@
      * @throws IllegalStateException
      *         If this is a named module and the caller is not this module
      *
+     * @jvms 5.4.3 Resolution
      * @see #isExported(String,Module)
      */
     @CallerSensitive
@@ -676,8 +683,8 @@
     }
 
     /**
-     * If the caller's module is this module then update this module to
-     * <em>open</em> the given package to the given module.
+     * If this module has <em>opened</em> a package to at least the caller
+     * module then update this module to open the package to the given module.
      * Opening a package with this method allows all types in the package,
      * and all their members, not just public types and their public members,
      * to be reflected on by the given module when using APIs that support
@@ -699,7 +706,8 @@
      *         If {@code pn} is {@code null}, or this is a named module and the
      *         package {@code pn} is not a package in this module
      * @throws IllegalStateException
-     *         If this is a named module and the caller is not this module
+     *         If this is a named module and this module has not opened the
+     *         package to at least the caller
      *
      * @see #isOpen(String,Module)
      * @see AccessibleObject#setAccessible(boolean)
@@ -713,9 +721,8 @@
 
         if (isNamed() && !descriptor.isOpen()) {
             Module caller = Reflection.getCallerClass().getModule();
-            if (caller != this) {
-                throw new IllegalStateException(caller + " != " + this);
-            }
+            if (caller != this && !isOpen(pn, caller))
+                throw new IllegalStateException(pn + " is not open to " + caller);
             implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
         }
 
@@ -1568,6 +1575,10 @@
                 public Stream<Layer> layers(ClassLoader loader) {
                     return Layer.layers(loader);
                 }
+                @Override
+                public boolean isStaticallyExported(Module module, String pn, Module other) {
+                    return module.isStaticallyExportedOrOpen(pn, other, false);
+                }
             });
     }
 }
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java	Mon Dec 19 16:05:38 2016 +0000
@@ -27,6 +27,8 @@
 
 import java.nio.ByteBuffer;
 import java.nio.ReadOnlyBufferException;
+import java.util.List;
+import java.util.function.BiFunction;
 
 
 /**
@@ -1332,4 +1334,89 @@
     public String getHandshakeApplicationProtocol() {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * Registers a callback function that selects an application protocol
+     * value for a SSL/TLS/DTLS handshake.
+     * The function overrides any values set using
+     * {@link SSLParameters#setApplicationProtocols
+     * SSLParameters.setApplicationProtocols} and it supports the following
+     * type parameters:
+     * <blockquote>
+     * <dl>
+     * <dt> {@code SSLEngine}
+     * <dd> The function's first argument allows the current {@code SSLEngine}
+     *      to be inspected, including the handshake session and configuration
+     *      settings.
+     * <dt> {@code List<String>}
+     * <dd> The function's second argument lists the application protocol names
+     *      advertised by the TLS peer.
+     * <dt> {@code String}
+     * <dd> The function's result is an application protocol name, or null to
+     *      indicate that none of the advertised names are acceptable.
+     *      If the return value is null (no value chosen) or is a value that
+     *      was not advertised by the peer, the underlying protocol will
+     *      determine what action to take. (For example, ALPN will send a
+     *      "no_application_protocol" alert and terminate the connection.)
+     * </dl>
+     * </blockquote>
+     *
+     * For example, the following call registers a callback function that
+     * examines the TLS handshake parameters and selects an application protocol
+     * name:
+     * <pre>{@code
+     *     serverEngine.setHandshakeApplicationProtocolSelector(
+     *         (serverEngine, clientProtocols) -> {
+     *             SSLSession session = serverEngine.getHandshakeSession();
+     *             return chooseApplicationProtocol(
+     *                 serverEngine,
+     *                 clientProtocols,
+     *                 session.getProtocol(),
+     *                 session.getCipherSuite());
+     *         });
+     * }</pre>
+     *
+     * @apiNote
+     * This method should be called by TLS server applications before the TLS
+     * handshake begins. Also, this {@code SSLEngine} should be configured with
+     * parameters that are compatible with the application protocol selected by
+     * the callback function. For example, enabling a poor choice of cipher
+     * suites could result in no suitable application protocol.
+     * See {@link SSLParameters}.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @param selector the callback function, or null to disable the callback
+     *         functionality.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public void setHandshakeApplicationProtocolSelector(
+            BiFunction<SSLEngine, List<String>, String> selector) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the callback function that selects an application protocol
+     * value during a SSL/TLS/DTLS handshake.
+     * See {@link #setHandshakeApplicationProtocolSelector
+     * setHandshakeApplicationProtocolSelector}
+     * for the function's type parameters.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return the callback function, or null if none has been set.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public BiFunction<SSLEngine, List<String>, String>
+            getHandshakeApplicationProtocolSelector() {
+        throw new UnsupportedOperationException();
+    }
 }
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocket.java	Mon Dec 19 16:05:38 2016 +0000
@@ -28,6 +28,8 @@
 
 import java.io.IOException;
 import java.net.*;
+import java.util.List;
+import java.util.function.BiFunction;
 
 /**
  * This class extends <code>Socket</code>s and provides secure
@@ -742,4 +744,89 @@
     public String getHandshakeApplicationProtocol() {
         throw new UnsupportedOperationException();
     }
+
+
+    /**
+     * Registers a callback function that selects an application protocol
+     * value for a SSL/TLS/DTLS handshake.
+     * The function overrides any values set using
+     * {@link SSLParameters#setApplicationProtocols
+     * SSLParameters.setApplicationProtocols} and it supports the following
+     * type parameters:
+     * <blockquote>
+     * <dl>
+     * <dt> {@code SSLSocket}
+     * <dd> The function's first argument allows the current {@code SSLSocket}
+     *      to be inspected, including the handshake session and configuration
+     *      settings.
+     * <dt> {@code List<String>}
+     * <dd> The function's second argument lists the application protocol names
+     *      advertised by the TLS peer.
+     * <dt> {@code String}
+     * <dd> The function's result is an application protocol name, or null to
+     *      indicate that none of the advertised names are acceptable.
+     *      If the return value is null (no value chosen) or is a value that
+     *      was not advertised by the peer, the underlying protocol will
+     *      determine what action to take. (For example, ALPN will send a
+     *      "no_application_protocol" alert and terminate the connection.)
+     * </dl>
+     * </blockquote>
+     *
+     * For example, the following call registers a callback function that
+     * examines the TLS handshake parameters and selects an application protocol
+     * name:
+     * <pre>{@code
+     *     serverSocket.setHandshakeApplicationProtocolSelector(
+     *         (serverSocket, clientProtocols) -> {
+     *             SSLSession session = serverSocket.getHandshakeSession();
+     *             return chooseApplicationProtocol(
+     *                 serverSocket,
+     *                 clientProtocols,
+     *                 session.getProtocol(),
+     *                 session.getCipherSuite());
+     *         });
+     * }</pre>
+     *
+     * @apiNote
+     * This method should be called by TLS server applications before the TLS
+     * handshake begins. Also, this {@code SSLSocket} should be configured with
+     * parameters that are compatible with the application protocol selected by
+     * the callback function. For example, enabling a poor choice of cipher
+     * suites could result in no suitable application protocol.
+     * See {@link SSLParameters}.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @param selector the callback function, or null to de-register.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public void setHandshakeApplicationProtocolSelector(
+            BiFunction<SSLSocket, List<String>, String> selector) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the callback function that selects an application protocol
+     * value during a SSL/TLS/DTLS handshake.
+     * See {@link #setHandshakeApplicationProtocolSelector
+     * setHandshakeApplicationProtocolSelector}
+     * for the function's type parameters.
+     *
+     * @implSpec
+     * The implementation in this class throws
+     * {@code UnsupportedOperationException} and performs no other action.
+     *
+     * @return the callback function, or null if none has been set.
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
+     * @since 9
+     */
+    public BiFunction<SSLSocket, List<String>, String>
+            getHandshakeApplicationProtocolSelector() {
+        throw new UnsupportedOperationException();
+    }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java	Mon Dec 19 16:05:38 2016 +0000
@@ -64,8 +64,10 @@
     private static final int CONSTANT_MethodHandle = 15;
     private static final int CONSTANT_MethodType = 16;
     private static final int CONSTANT_InvokeDynamic = 18;
+    private static final int CONSTANT_Module = 19;
+    private static final int CONSTANT_Package = 20;
 
-    private static final int[] SIZES = new int[20];
+    private static final int[] SIZES = new int[21];
 
     static {
 
@@ -83,6 +85,8 @@
         SIZES[CONSTANT_MethodHandle] = 3;
         SIZES[CONSTANT_MethodType] = 2;
         SIZES[CONSTANT_InvokeDynamic] = 4;
+        SIZES[CONSTANT_Module] = 2;
+        SIZES[CONSTANT_Package] = 2;
     }
 
     public static int[] getSizes() {
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Mon Dec 19 16:05:38 2016 +0000
@@ -38,10 +38,8 @@
 import java.lang.module.ModuleReference;
 import java.net.URI;
 import java.nio.file.Path;
-import java.util.Map;
 import java.util.Collection;
 import java.util.List;
-import java.util.Optional;
 import java.util.Set;
 import java.util.function.Supplier;
 
@@ -59,21 +57,28 @@
      * @param strict
      *        Indicates whether module names are checked or not
      */
-    ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict);
+    ModuleDescriptor.Builder newModuleBuilder(String mn,
+                                              boolean strict,
+                                              boolean open,
+                                              boolean synthetic);
 
     /**
-     * Creates a builder for building an open module with the given module name.
-     *
-     * @param strict
-     *        Indicates whether module names are checked or not
+     * Returns the set of packages that are exported (unconditionally or
+     * unconditionally).
      */
-    ModuleDescriptor.Builder newOpenModuleBuilder(String mn, boolean strict);
+    Set<String> exportedPackages(ModuleDescriptor.Builder builder);
+
+    /**
+     * Returns the set of packages that are opened (unconditionally or
+     * unconditionally).
+     */
+    Set<String> openPackages(ModuleDescriptor.Builder builder);
 
     /**
      * Returns a {@code ModuleDescriptor.Requires} of the given modifiers
      * and module name.
      */
-    Requires newRequires(Set<Requires.Modifier> ms, String mn);
+    Requires newRequires(Set<Requires.Modifier> ms, String mn, Version v);
 
     /**
      * Returns an unqualified {@code ModuleDescriptor.Exports}
@@ -122,6 +127,7 @@
      * Returns a new {@code ModuleDescriptor} instance.
      */
     ModuleDescriptor newModuleDescriptor(String name,
+                                         Version version,
                                          boolean open,
                                          boolean automatic,
                                          boolean synthetic,
@@ -130,21 +136,14 @@
                                          Set<Opens> opens,
                                          Set<String> uses,
                                          Set<Provides> provides,
-                                         Version version,
+                                         Set<String> packages,
                                          String mainClass,
                                          String osName,
                                          String osArch,
                                          String osVersion,
-                                         Set<String> packages,
-                                         ModuleHashes hashes,
                                          int hashCode);
 
     /**
-     * Returns the object with the hashes of other modules
-     */
-    Optional<ModuleHashes> hashes(ModuleDescriptor descriptor);
-
-    /**
      * Resolves a collection of root modules, with service binding
      * and the empty configuration as the parent. The post resolution
      * checks are optionally run.
@@ -154,18 +153,4 @@
                                          boolean check,
                                          PrintStream traceOutput);
 
-    /**
-     * Creates a ModuleReference to a "patched" module.
-     */
-    ModuleReference newPatchedModule(ModuleDescriptor descriptor,
-                                     URI location,
-                                     Supplier<ModuleReader> readerSupplier);
-
-    /**
-     * Creates a ModuleFinder for a module path.
-     */
-    ModuleFinder newModulePath(Runtime.Version version,
-                               boolean isLinkPhase,
-                               Path... entries);
-
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Mon Dec 19 16:05:38 2016 +0000
@@ -123,4 +123,12 @@
      * given class loader.
      */
     Stream<Layer> layers(ClassLoader loader);
+
+    /**
+     * Tests if a module exports a package at least {@code other} via its
+     * module declaration.
+     *
+     * @apiNote This is a temporary method for debugging features.
+     */
+    boolean isStaticallyExported(Module module, String pn, Module other);
 }
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Mon Dec 19 16:05:38 2016 +0000
@@ -30,11 +30,8 @@
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Version;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import jdk.internal.misc.JavaLangModuleAccess;
@@ -52,7 +49,7 @@
  * SystemModules should contain modules for the boot layer.
  */
 final class Builder {
-    private static final JavaLangModuleAccess jlma =
+    private static final JavaLangModuleAccess JLMA =
         SharedSecrets.getJavaLangModuleAccess();
 
     // Static cache of the most recently seen Version to cheaply deduplicate
@@ -60,13 +57,36 @@
     static Version cachedVersion;
 
     /**
-     * Returns a {@link Requires} for a dependence on a module
-     * with the given (and possibly empty) set of modifiers.
+     * Returns a {@link Requires} for a dependence on a module with the given
+     * (and possibly empty) set of modifiers, and optionally the version
+     * recorded at compile time.
+     */
+    public static Requires newRequires(Set<Requires.Modifier> mods,
+                                       String mn,
+                                       String compiledVersion)
+    {
+        Version version = null;
+        if (compiledVersion != null) {
+            // use the cached version if the same version string
+            Version ver = cachedVersion;
+            if (ver != null && compiledVersion.equals(ver.toString())) {
+                version = ver;
+            } else {
+                version = Version.parse(compiledVersion);
+            }
+        }
+        return JLMA.newRequires(mods, mn, version);
+    }
+
+    /**
+     * Returns a {@link Requires} for a dependence on a module with the given
+     * (and possibly empty) set of modifiers, and optionally the version
+     * recorded at compile time.
      */
     public static Requires newRequires(Set<Requires.Modifier> mods,
                                        String mn)
     {
-        return jlma.newRequires(mods, mn);
+        return newRequires(mods, mn, null);
     }
 
     /**
@@ -77,7 +97,7 @@
     public static Exports newExports(Set<Exports.Modifier> ms,
                                      String pn,
                                      Set<String> targets) {
-        return jlma.newExports(ms, pn, targets);
+        return JLMA.newExports(ms, pn, targets);
     }
 
     /**
@@ -85,7 +105,7 @@
      * modifiers.
      */
     public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
-        return jlma.newOpens(ms, pn);
+        return JLMA.newOpens(ms, pn);
     }
 
     /**
@@ -96,7 +116,7 @@
     public static Opens newOpens(Set<Opens.Modifier> ms,
                                  String pn,
                                  Set<String> targets) {
-        return jlma.newOpens(ms, pn, targets);
+        return JLMA.newOpens(ms, pn, targets);
     }
 
     /**
@@ -104,7 +124,7 @@
      * of modifiers.
      */
     public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
-        return jlma.newExports(ms, pn);
+        return JLMA.newExports(ms, pn);
     }
 
     /**
@@ -112,7 +132,7 @@
      * implementation classes.
      */
     public static Provides newProvides(String st, List<String> pcs) {
-        return jlma.newProvides(st, pcs);
+        return JLMA.newProvides(st, pcs);
     }
 
     final String name;
@@ -130,8 +150,6 @@
     String osName;
     String osArch;
     String osVersion;
-    String algorithm;
-    Map<String, byte[]> hashes;
 
     Builder(String name) {
         this.name = name;
@@ -275,34 +293,13 @@
     }
 
     /**
-     * Sets the algorithm of the module hashes
-     */
-    public Builder algorithm(String algorithm) {
-        this.algorithm = algorithm;
-        return this;
-    }
-
-    /**
-     * Sets the module hash for the given module name
-     */
-    public Builder moduleHash(String mn, byte[] hash) {
-        if (hashes == null)
-            hashes = new HashMap<>();
-
-        hashes.put(mn, hash);
-        return this;
-    }
-
-    /**
      * Builds a {@code ModuleDescriptor} from the components.
      */
     public ModuleDescriptor build(int hashCode) {
         assert name != null;
 
-        ModuleHashes moduleHashes =
-            hashes != null ? new ModuleHashes(algorithm, hashes) : null;
-
-        return jlma.newModuleDescriptor(name,
+        return JLMA.newModuleDescriptor(name,
+                                        version,
                                         open,
                                         automatic,
                                         synthetic,
@@ -311,13 +308,11 @@
                                         opens,
                                         uses,
                                         provides,
-                                        version,
+                                        packages,
                                         mainClass,
                                         osName,
                                         osArch,
                                         osVersion,
-                                        packages,
-                                        moduleHashes,
                                         hashCode);
     }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java	Mon Dec 19 16:05:38 2016 +0000
@@ -25,79 +25,200 @@
 
 package jdk.internal.module;
 
+/**
+ * Utility class for checking module name and binary names.
+ */
+
 public final class Checks {
 
     private Checks() { }
 
-    private static void fail(String what, String id, int i) {
-        throw new IllegalArgumentException(id
-                                           + ": Invalid " + what + ": "
-                                           + " Illegal character"
-                                           + " at index " + i);
+    /**
+     * Checks a name to ensure that it's a legal module name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         module name
+     */
+    public static String requireModuleName(String name) {
+        if (name == null)
+            throw new IllegalArgumentException("Null module name");
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1) {
+                String id = name.substring(off, next);
+                throw new IllegalArgumentException(name + ": Invalid module name"
+                        + ": '" + id + "' is not a Java identifier");
+            }
+            off = next+1;
+        }
+        int last = isJavaIdentifier(name, off, name.length() - off);
+        if (last == -1) {
+            String id = name.substring(off);
+            throw new IllegalArgumentException(name + ": Invalid module name"
+                    + ": '" + id + "' is not a Java identifier");
+        }
+        //if (!Character.isJavaIdentifierStart(last))
+        //    throw new IllegalArgumentException(name + ": Module name ends in digit");
+        return name;
     }
 
     /**
-     * Returns {@code true} if the given identifier is a legal Java identifier.
+     * Returns {@code true} if the given name is a legal module name.
      */
-    public static boolean isJavaIdentifier(String id) {
-        int n = id.length();
-        if (n == 0)
-            return false;
-        if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
+    public static boolean isModuleName(String name) {
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1)
+                return false;
+            off = next+1;
+        }
+        int last = isJavaIdentifier(name, off, name.length() - off);
+        if (last == -1)
             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;
-
+        //if (!Character.isJavaIdentifierStart(last))
+        //    return false;
         return true;
     }
 
     /**
-     * Checks if a given identifier is a legal Java identifier.
+     * Checks a name to ensure that it's a legal package name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         package name
+     */
+    public static String requirePackageName(String name) {
+        return requireBinaryName("package name", name);
+    }
+
+    /**
+     * Checks a name to ensure that it's a legal type name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         type name
+     */
+    public static String requireServiceTypeName(String name) {
+        return requireBinaryName("service type name", name);
+    }
+
+    /**
+     * Checks a name to ensure that it's a legal type name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         type name
      */
-    public static String requireJavaIdentifier(String what, String id) {
-        if (id == null)
-            throw new IllegalArgumentException("Null " + what);
-        int n = id.length();
-        if (n == 0)
-            throw new IllegalArgumentException("Empty " + what);
-        if (!Character.isJavaIdentifierStart(id.codePointAt(0)))
-            fail(what, id, 0);
-        int cp = id.codePointAt(0);
-        int i = Character.charCount(cp);
-        int last = 0;
-        for (; i < n; i += Character.charCount(cp)) {
-            cp = id.codePointAt(i);
-            if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.')
-                fail(what, id, i);
-            last = i;
+    public static String requireServiceProviderName(String name) {
+        return requireBinaryName("service provider name", name);
+    }
+
+    /**
+     * Returns {@code true} if the given name is a legal binary name.
+     */
+    public static boolean isJavaIdentifier(String name) {
+        return isBinaryName(name);
+    }
+
+    /**
+     * Returns {@code true} if the given name is a legal binary name.
+     */
+    public static boolean isBinaryName(String name) {
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1)
+                return false;
+            off = next+1;
         }
-        if (cp == '.')
-            fail(what, id, last);
-
-        return id;
+        int count = name.length() - off;
+        return (isJavaIdentifier(name, off, count) != -1);
     }
 
-    public static String requireModuleName(String id) {
-        return requireJavaIdentifier("module name", id);
-    }
-
-    public static String requirePackageName(String id) {
-        return requireJavaIdentifier("package name", id);
+    /**
+     * Checks if the given name is a legal binary name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         binary name
+     */
+    public static String requireBinaryName(String what, String name) {
+        if (name == null)
+            throw new IllegalArgumentException("Null " + what);
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            if (isJavaIdentifier(name, off, (next - off)) == -1) {
+                String id = name.substring(off, next);
+                throw new IllegalArgumentException(name + ": Invalid " + what
+                        + ": '" + id + "' is not a Java identifier");
+            }
+            off = next + 1;
+        }
+        if (isJavaIdentifier(name, off, name.length() - off) == -1) {
+            String id = name.substring(off, name.length());
+            throw new IllegalArgumentException(name + ": Invalid " + what
+                    + ": '" + id + "' is not a Java identifier");
+        }
+        return name;
     }
 
-    public static String requireServiceTypeName(String id) {
-        return requireJavaIdentifier("service type name", id);
+    /**
+     * Returns {@code true} if the last character of the given name is legal
+     * as the last character of a module name.
+     *
+     * @throws IllegalArgumentException if name is empty
+     */
+    public static boolean hasLegalModuleNameLastCharacter(String name) {
+        if (name.isEmpty())
+            throw new IllegalArgumentException("name is empty");
+        int len = name.length();
+        if (isASCIIString(name)) {
+            char c = name.charAt(len-1);
+            return Character.isJavaIdentifierStart(c);
+        } else {
+            int i = 0;
+            int cp = -1;
+            while (i < len) {
+                cp = name.codePointAt(i);
+                i += Character.charCount(cp);
+            }
+            return Character.isJavaIdentifierStart(cp);
+        }
     }
 
-    public static String requireServiceProviderName(String id) {
-        return requireJavaIdentifier("service provider name", id);
+    /**
+     * Returns true if the given string only contains ASCII characters.
+     */
+    private static boolean isASCIIString(String s) {
+        int i = 0;
+        while (i < s.length()) {
+            int c = s.charAt(i);
+            if (c > 0x7F)
+                return false;
+            i++;
+        }
+        return true;
     }
 
+    /**
+     * Checks if a char sequence is a legal Java identifier, returning the code
+     * point of the last character if legal or {@code -1} if not legal.
+     */
+    private static int isJavaIdentifier(CharSequence cs, int offset, int count) {
+        if (count == 0)
+            return -1;
+        int first = Character.codePointAt(cs, offset);
+        if (!Character.isJavaIdentifierStart(first))
+            return -1;
+
+        int cp = first;
+        int i = Character.charCount(first);
+        while (i < count) {
+            cp = Character.codePointAt(cs, offset+i);
+            if (!Character.isJavaIdentifierPart(cp))
+                return -1;
+            i += Character.charCount(cp);
+        }
+
+        return cp;
+    }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Mon Dec 19 16:05:38 2016 +0000
@@ -68,12 +68,18 @@
             = SharedSecrets.getJavaLangModuleAccess();
 
         private ModuleDescriptor descriptor;
+        private Version replacementVersion;
 
         public ModuleAttribute(ModuleDescriptor descriptor) {
             super(MODULE);
             this.descriptor = descriptor;
         }
 
+        public ModuleAttribute(Version v) {
+            super(MODULE);
+            this.replacementVersion = v;
+        }
+
         public ModuleAttribute() {
             super(MODULE);
         }
@@ -86,46 +92,70 @@
                                  int codeOff,
                                  Label[] labels)
         {
-            ModuleAttribute attr = new ModuleAttribute();
-
-            // module_name
-            String mn = cr.readUTF8(off, buf).replace('/', '.');
+            // module_name (CONSTANT_Module_info)
+            String mn = cr.readModule(off, buf);
             off += 2;
 
             // module_flags
             int module_flags = cr.readUnsignedShort(off);
             boolean open = ((module_flags & ACC_OPEN) != 0);
+            boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
             off += 2;
 
-            ModuleDescriptor.Builder builder;
-            if (open) {
-                builder = JLMA.newOpenModuleBuilder(mn, false);
-            } else {
-                builder = JLMA.newModuleBuilder(mn, false);
+            ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn,
+                                                                     false,
+                                                                     open,
+                                                                     synthetic);
+
+            // module_version
+            String module_version = cr.readUTF8(off, buf);
+            off += 2;
+            if (replacementVersion != null) {
+                builder.version(replacementVersion);
+            } else if (module_version != null) {
+                builder.version(module_version);
             }
 
             // requires_count and requires[requires_count]
             int requires_count = cr.readUnsignedShort(off);
             off += 2;
             for (int i=0; i<requires_count; i++) {
-                String dn = cr.readUTF8(off, buf).replace('/', '.');
-                int flags = cr.readUnsignedShort(off + 2);
+                // CONSTANT_Module_info
+                String dn = cr.readModule(off, buf);
+                off += 2;
+
+                // requires_flags
+                int requires_flags = cr.readUnsignedShort(off);
+                off += 2;
                 Set<Requires.Modifier> mods;
-                if (flags == 0) {
+                if (requires_flags == 0) {
                     mods = Collections.emptySet();
                 } else {
                     mods = new HashSet<>();
-                    if ((flags & ACC_TRANSITIVE) != 0)
+                    if ((requires_flags & ACC_TRANSITIVE) != 0)
                         mods.add(Requires.Modifier.TRANSITIVE);
-                    if ((flags & ACC_STATIC_PHASE) != 0)
+                    if ((requires_flags & ACC_STATIC_PHASE) != 0)
                         mods.add(Requires.Modifier.STATIC);
-                    if ((flags & ACC_SYNTHETIC) != 0)
+                    if ((requires_flags & ACC_SYNTHETIC) != 0)
                         mods.add(Requires.Modifier.SYNTHETIC);
-                    if ((flags & ACC_MANDATED) != 0)
+                    if ((requires_flags & ACC_MANDATED) != 0)
                         mods.add(Requires.Modifier.MANDATED);
                 }
-                builder.requires(mods, dn);
-                off += 4;
+
+
+                // requires_version
+                Version compiledVersion = null;
+                String requires_version = cr.readUTF8(off, buf);
+                off += 2;
+                if (requires_version != null) {
+                    compiledVersion = Version.parse(requires_version);
+                }
+
+                if (compiledVersion == null) {
+                    builder.requires(mods, dn);
+                } else {
+                    builder.requires(mods, dn, compiledVersion);
+                }
             }
 
             // exports_count and exports[exports_count]
@@ -133,19 +163,20 @@
             off += 2;
             if (exports_count > 0) {
                 for (int i=0; i<exports_count; i++) {
-                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    // CONSTANT_Package_info
+                    String pkg = cr.readPackage(off, buf).replace('/', '.');
                     off += 2;
 
-                    int flags = cr.readUnsignedShort(off);
+                    int exports_flags = cr.readUnsignedShort(off);
                     off += 2;
                     Set<Exports.Modifier> mods;
-                    if (flags == 0) {
+                    if (exports_flags == 0) {
                         mods = Collections.emptySet();
                     } else {
                         mods = new HashSet<>();
-                        if ((flags & ACC_SYNTHETIC) != 0)
+                        if ((exports_flags & ACC_SYNTHETIC) != 0)
                             mods.add(Exports.Modifier.SYNTHETIC);
-                        if ((flags & ACC_MANDATED) != 0)
+                        if ((exports_flags & ACC_MANDATED) != 0)
                             mods.add(Exports.Modifier.MANDATED);
                     }
 
@@ -154,7 +185,7 @@
                     if (exports_to_count > 0) {
                         Set<String> targets = new HashSet<>();
                         for (int j=0; j<exports_to_count; j++) {
-                            String t = cr.readUTF8(off, buf).replace('/', '.');
+                            String t = cr.readModule(off, buf);
                             off += 2;
                             targets.add(t);
                         }
@@ -170,19 +201,20 @@
             off += 2;
             if (open_count > 0) {
                 for (int i=0; i<open_count; i++) {
-                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    // CONSTANT_Package_info
+                    String pkg = cr.readPackage(off, buf).replace('/', '.');
                     off += 2;
 
-                    int flags = cr.readUnsignedShort(off);
+                    int opens_flags = cr.readUnsignedShort(off);
                     off += 2;
                     Set<Opens.Modifier> mods;
-                    if (flags == 0) {
+                    if (opens_flags == 0) {
                         mods = Collections.emptySet();
                     } else {
                         mods = new HashSet<>();
-                        if ((flags & ACC_SYNTHETIC) != 0)
+                        if ((opens_flags & ACC_SYNTHETIC) != 0)
                             mods.add(Opens.Modifier.SYNTHETIC);
-                        if ((flags & ACC_MANDATED) != 0)
+                        if ((opens_flags & ACC_MANDATED) != 0)
                             mods.add(Opens.Modifier.MANDATED);
                     }
 
@@ -191,7 +223,7 @@
                     if (opens_to_count > 0) {
                         Set<String> targets = new HashSet<>();
                         for (int j=0; j<opens_to_count; j++) {
-                            String t = cr.readUTF8(off, buf).replace('/', '.');
+                            String t = cr.readModule(off, buf);
                             off += 2;
                             targets.add(t);
                         }
@@ -232,8 +264,7 @@
                 }
             }
 
-            attr.descriptor = builder.build();
-            return attr;
+            return new ModuleAttribute(builder.build());
         }
 
         @Override
@@ -248,7 +279,7 @@
 
             // module_name
             String mn = descriptor.name();
-            int module_name_index = cw.newUTF8(mn.replace('.', '/'));
+            int module_name_index = cw.newModule(mn);
             attr.putShort(module_name_index);
 
             // module_flags
@@ -259,66 +290,83 @@
                 module_flags |= ACC_SYNTHETIC;
             attr.putShort(module_flags);
 
+            // module_version
+            Version v = descriptor.version().orElse(null);
+            if (v == null) {
+                attr.putShort(0);
+            } else {
+                int module_version_index = cw.newUTF8(v.toString());
+                attr.putShort(module_version_index);
+            }
+
             // requires_count
             attr.putShort(descriptor.requires().size());
 
             // requires[requires_count]
-            for (Requires md : descriptor.requires()) {
-                String dn = md.name();
-                int flags = 0;
-                if (md.modifiers().contains(Requires.Modifier.TRANSITIVE))
-                    flags |= ACC_TRANSITIVE;
-                if (md.modifiers().contains(Requires.Modifier.STATIC))
-                    flags |= ACC_STATIC_PHASE;
-                if (md.modifiers().contains(Requires.Modifier.SYNTHETIC))
-                    flags |= ACC_SYNTHETIC;
-                if (md.modifiers().contains(Requires.Modifier.MANDATED))
-                    flags |= ACC_MANDATED;
-                int index = cw.newUTF8(dn.replace('.', '/'));
-                attr.putShort(index);
-                attr.putShort(flags);
+            for (Requires r : descriptor.requires()) {
+                int requires_index = cw.newModule(r.name());
+                attr.putShort(requires_index);
+
+                int requires_flags = 0;
+                if (r.modifiers().contains(Requires.Modifier.TRANSITIVE))
+                    requires_flags |= ACC_TRANSITIVE;
+                if (r.modifiers().contains(Requires.Modifier.STATIC))
+                    requires_flags |= ACC_STATIC_PHASE;
+                if (r.modifiers().contains(Requires.Modifier.SYNTHETIC))
+                    requires_flags |= ACC_SYNTHETIC;
+                if (r.modifiers().contains(Requires.Modifier.MANDATED))
+                    requires_flags |= ACC_MANDATED;
+                attr.putShort(requires_flags);
+
+                int requires_version_index;
+                v = r.compiledVersion().orElse(null);
+                if (v == null) {
+                    requires_version_index = 0;
+                } else {
+                    requires_version_index = cw.newUTF8(v.toString());
+                }
+                attr.putShort(requires_version_index);
             }
 
             // exports_count and exports[exports_count];
             attr.putShort(descriptor.exports().size());
             for (Exports e : descriptor.exports()) {
                 String pkg = e.source().replace('.', '/');
-                attr.putShort(cw.newUTF8(pkg));
+                attr.putShort(cw.newPackage(pkg));
 
-                int flags = 0;
+                int exports_flags = 0;
                 if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
-                    flags |= ACC_SYNTHETIC;
+                    exports_flags |= ACC_SYNTHETIC;
                 if (e.modifiers().contains(Exports.Modifier.MANDATED))
-                    flags |= ACC_MANDATED;
-                attr.putShort(flags);
+                    exports_flags |= ACC_MANDATED;
+                attr.putShort(exports_flags);
 
                 if (e.isQualified()) {
                     Set<String> ts = e.targets();
                     attr.putShort(ts.size());
-                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                    ts.forEach(target -> attr.putShort(cw.newModule(target)));
                 } else {
                     attr.putShort(0);
                 }
             }
 
-
             // opens_counts and opens[opens_counts]
             attr.putShort(descriptor.opens().size());
             for (Opens obj : descriptor.opens()) {
                 String pkg = obj.source().replace('.', '/');
-                attr.putShort(cw.newUTF8(pkg));
+                attr.putShort(cw.newPackage(pkg));
 
-                int flags = 0;
+                int opens_flags = 0;
                 if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
-                    flags |= ACC_SYNTHETIC;
+                    opens_flags |= ACC_SYNTHETIC;
                 if (obj.modifiers().contains(Opens.Modifier.MANDATED))
-                    flags |= ACC_MANDATED;
-                attr.putShort(flags);
+                    opens_flags |= ACC_MANDATED;
+                attr.putShort(opens_flags);
 
                 if (obj.isQualified()) {
                     Set<String> ts = obj.targets();
                     attr.putShort(ts.size());
-                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                    ts.forEach(target -> attr.putShort(cw.newModule(target)));
                 } else {
                     attr.putShort(0);
                 }
@@ -369,7 +417,7 @@
      *
      *   // the number of entries in the packages table
      *   u2 packages_count;
-     *   { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
+     *   { // index to CONSTANT_Package_info structure with the package name
      *     u2 package_index
      *   } packages[package_count];
      *
@@ -402,7 +450,7 @@
             // packages
             Set<String> packages = new HashSet<>();
             for (int i=0; i<package_count; i++) {
-                String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                String pkg = cr.readPackage(off, buf).replace('/', '.');
                 packages.add(pkg);
                 off += 2;
             }
@@ -427,7 +475,7 @@
             // packages
             packages.stream()
                 .map(p -> p.replace('.', '/'))
-                .forEach(p -> attr.putShort(cw.newUTF8(p)));
+                .forEach(p -> attr.putShort(cw.newPackage(p)));
 
             return attr;
         }
@@ -435,61 +483,6 @@
     }
 
     /**
-     * ModuleVersion attribute.
-     *
-     * <pre> {@code
-     *
-     * ModuleVersion_attribute {
-     *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ModuleVersion"
-     *   u2 attribute_name_index;
-     *   u4 attribute_length;
-     *
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the version
-     *   u2 version_index;
-     * }
-     *
-     * } </pre>
-     */
-    public static class ModuleVersionAttribute extends Attribute {
-        private final Version version;
-
-        public ModuleVersionAttribute(Version version) {
-            super(MODULE_VERSION);
-            this.version = version;
-        }
-
-        public ModuleVersionAttribute() {
-            this(null);
-        }
-
-        @Override
-        protected Attribute read(ClassReader cr,
-                                 int off,
-                                 int len,
-                                 char[] buf,
-                                 int codeOff,
-                                 Label[] labels)
-        {
-            String value = cr.readUTF8(off, buf);
-            return new ModuleVersionAttribute(Version.parse(value));
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw,
-                                   byte[] code,
-                                   int len,
-                                   int maxStack,
-                                   int maxLocals)
-        {
-            ByteVector attr = new ByteVector();
-            int index = cw.newUTF8(version.toString());
-            attr.putShort(index);
-            return attr;
-        }
-    }
-
-    /**
      * ModuleMainClass attribute.
      *
      * <pre> {@code
@@ -526,7 +519,7 @@
                                  int codeOff,
                                  Label[] labels)
         {
-            String value = cr.readClass(off, buf);
+            String value = cr.readClass(off, buf).replace('/', '.');
             return new ModuleMainClassAttribute(value);
         }
 
@@ -538,7 +531,7 @@
                                    int maxLocals)
         {
             ByteVector attr = new ByteVector();
-            int index = cw.newClass(mainClass);
+            int index = cw.newClass(mainClass.replace('.', '/'));
             attr.putShort(index);
             return attr;
         }
@@ -555,11 +548,11 @@
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS name
+     *   // index to CONSTANT_utf8_info structure with the OS name
      *   u2 os_name_index;
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS arch
+     *   // index to CONSTANT_utf8_info structure with the OS arch
      *   u2 os_arch_index
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS version
+     *   // index to CONSTANT_utf8_info structure with the OS version
      *   u2 os_version_index;
      * }
      *
@@ -656,7 +649,7 @@
      *
      *   // the number of entries in the hashes table
      *   u2 hashes_count;
-     *   {   u2 module_name_index
+     *   {   u2 module_name_index (index to CONSTANT_Module_info structure)
      *       u2 hash_length;
      *       u1 hash[hash_length];
      *   } hashes[hashes_count];
@@ -691,7 +684,7 @@
 
             Map<String, byte[]> map = new HashMap<>();
             for (int i=0; i<hashes_count; i++) {
-                String mn = cr.readUTF8(off, buf).replace('/', '.');
+                String mn = cr.readModule(off, buf);
                 off += 2;
 
                 int hash_length = cr.readUnsignedShort(off);
@@ -728,7 +721,7 @@
             for (String mn : names) {
                 byte[] hash = hashes.hashFor(mn);
                 assert hash != null;
-                attr.putShort(cw.newUTF8(mn.replace('.', '/')));
+                attr.putShort(cw.newModule(mn));
 
                 attr.putShort(hash.length);
                 for (byte b: hash) {
@@ -740,4 +733,58 @@
         }
     }
 
+    /**
+     *  ModuleResolution_attribute {
+     *    u2 attribute_name_index;    // "ModuleResolution"
+     *    u4 attribute_length;        // 2
+     *    u2 resolution_flags;
+     *
+     *  The value of the resolution_flags item is a mask of flags used to denote
+     *  properties of module resolution. The flags are as follows:
+     *
+     *   // Optional
+     *   0x0001 (DO_NOT_RESOLVE_BY_DEFAULT)
+     *
+     *   // At most one of:
+     *   0x0002 (WARN_DEPRECATED)
+     *   0x0004 (WARN_DEPRECATED_FOR_REMOVAL)
+     *   0x0008 (WARN_INCUBATING)
+     */
+    static class ModuleResolutionAttribute extends Attribute {
+        private final int value;
+
+        ModuleResolutionAttribute() {
+            super(MODULE_RESOLUTION);
+            value = 0;
+        }
+
+        ModuleResolutionAttribute(int value) {
+            super(MODULE_RESOLUTION);
+            this.value = value;
+        }
+
+        @Override
+        protected Attribute read(ClassReader cr,
+                                 int off,
+                                 int len,
+                                 char[] buf,
+                                 int codeOff,
+                                 Label[] labels)
+        {
+            int flags = cr.readUnsignedShort(off);
+            return new ModuleResolutionAttribute(flags);
+        }
+
+        @Override
+        protected ByteVector write(ClassWriter cw,
+                                   byte[] code,
+                                   int len,
+                                   int maxStack,
+                                   int maxLocals)
+        {
+            ByteVector attr = new ByteVector();
+            attr.putShort(value);
+            return attr;
+        }
+    }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Mon Dec 19 16:05:38 2016 +0000
@@ -38,10 +38,10 @@
     public static final String SDE                = "SourceDebugExtension";
 
     public static final String MODULE_PACKAGES    = "ModulePackages";
-    public static final String MODULE_VERSION     = "ModuleVersion";
     public static final String MODULE_MAIN_CLASS  = "ModuleMainClass";
     public static final String MODULE_TARGET      = "ModuleTarget";
     public static final String MODULE_HASHES      = "ModuleHashes";
+    public static final String MODULE_RESOLUTION  = "ModuleResolution";
 
     // access, requires, exports, and opens flags
     public static final int ACC_MODULE        = 0x8000;
@@ -51,4 +51,10 @@
     public static final int ACC_SYNTHETIC     = 0x1000;
     public static final int ACC_MANDATED      = 0x8000;
 
+    // ModuleResolution_attribute resolution flags
+    public static final int DO_NOT_RESOLVE_BY_DEFAULT   = 0x0001;
+    public static final int WARN_DEPRECATED             = 0x0002;
+    public static final int WARN_DEPRECATED_FOR_REMOVAL = 0x0004;
+    public static final int WARN_INCUBATING             = 0x0008;
+
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Mon Dec 19 16:05:38 2016 +0000
@@ -195,7 +195,9 @@
         // module is the unnamed module of the application class loader. This
         // is implemented by resolving "java.se" and all (non-java.*) modules
         // that export an API. If "java.se" is not observable then all java.*
-        // modules are resolved.
+        // modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
+        // bit set in their ModuleResolution attribute flags are excluded from
+        // the default set of roots.
         if (mainModule == null || addAllDefaultModules) {
             boolean hasJava = false;
             if (systemModules.find(JAVA_SE).isPresent()) {
@@ -212,6 +214,9 @@
                 if (hasJava && mn.startsWith("java."))
                     continue;
 
+                if (ModuleResolution.doNotResolveByDefault(mref))
+                    continue;
+
                 // add as root if observable and exports at least one package
                 if ((finder == systemModules || finder.find(mn).isPresent())) {
                     ModuleDescriptor descriptor = mref.descriptor();
@@ -231,6 +236,7 @@
             ModuleFinder f = finder;  // observable modules
             systemModules.findAll()
                 .stream()
+                .filter(mref -> !ModuleResolution.doNotResolveByDefault(mref))
                 .map(ModuleReference::descriptor)
                 .map(ModuleDescriptor::name)
                 .filter(mn -> f.find(mn).isPresent())  // observable
@@ -277,6 +283,8 @@
         // time to create configuration
         PerfCounters.resolveTime.addElapsedTimeFrom(t3);
 
+        // check module names and incubating status
+        checkModuleNamesAndStatus(cf);
 
         // mapping of modules to class loaders
         Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
@@ -508,12 +516,12 @@
             String key = e.getKey();
             String[] s = key.split("/");
             if (s.length != 2)
-                fail("Unable to parse: " + key);
+                fail("Unable to parse as <module>/<package>: " + key);
 
             String mn = s[0];
             String pn = s[1];
             if (mn.isEmpty() || pn.isEmpty())
-                fail("Module and package name must be specified:" + key);
+                fail("Module and package name must be specified: " + key);
 
             // The exporting module is in the boot layer
             Module m;
@@ -585,7 +593,7 @@
 
             int pos = value.indexOf('=');
             if (pos == -1)
-                fail("Unable to parse: " + value);
+                fail("Unable to parse as <module>=<value>: " + value);
             if (pos == 0)
                 fail("Missing module name in: " + value);
 
@@ -594,7 +602,7 @@
 
             String rhs = value.substring(pos+1);
             if (rhs.isEmpty())
-                fail("Unable to parse: " + value);
+                fail("Unable to parse as <module>=<value>: " + value);
 
             // value is <module>(,<module>)* or <file>(<pathsep><file>)*
             if (!allowDuplicates && map.containsKey(key))
@@ -627,6 +635,33 @@
     }
 
     /**
+     * Checks the names and resolution bit of each module in the configuration,
+     * emitting warnings if needed.
+     */
+    private static void checkModuleNamesAndStatus(Configuration cf) {
+        String incubating = null;
+        for (ResolvedModule rm : cf.modules()) {
+            ModuleReference mref = rm.reference();
+            String mn = mref.descriptor().name();
+
+            // emit warning if module name ends with a non-Java letter
+            if (!Checks.hasLegalModuleNameLastCharacter(mn))
+                warn("Module name \"" + mn + "\" may soon be illegal");
+
+            // emit warning if the WARN_INCUBATING module resolution bit set
+            if (ModuleResolution.hasIncubatingWarning(mref)) {
+                if (incubating == null) {
+                    incubating = mn;
+                } else {
+                    incubating += ", " + mn;
+                }
+            }
+        }
+        if (incubating != null)
+            warn("Using incubator modules: " + incubating);
+    }
+
+    /**
      * Throws a RuntimeException with the given message
      */
     static void fail(String m) {
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	Mon Dec 19 16:05:38 2016 +0000
@@ -35,6 +35,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -50,7 +51,6 @@
         byte[] generate(String algorithm);
     }
 
-
     private final String algorithm;
     private final Map<String, byte[]> nameToHash;
 
@@ -142,4 +142,37 @@
         }
         return new ModuleHashes(algorithm, nameToHash);
     }
+
+    /**
+     * This is used by jdk.internal.module.SystemModules class
+     * generated at link time.
+     */
+    public static class Builder {
+        final String algorithm;
+        final Map<String, byte[]> nameToHash;
+
+        Builder(String algorithm, int initialCapacity) {
+            this.nameToHash = new HashMap<>(initialCapacity);
+            this.algorithm =  Objects.requireNonNull(algorithm);
+        }
+
+        /**
+         * Sets the module hash for the given module name
+         */
+        public Builder hashForModule(String mn, byte[] hash) {
+            nameToHash.put(mn, hash);
+            return this;
+        }
+
+        /**
+         * Builds a {@code ModuleHashes}.
+         */
+        public ModuleHashes build() {
+            if (!nameToHash.isEmpty()) {
+                return new ModuleHashes(algorithm, nameToHash);
+            } else {
+                return null;
+            }
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,1089 @@
+/*
+ * Copyright (c) 2014, 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.module;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.module.ModuleDescriptor.Version;
+import java.nio.ByteBuffer;
+import java.nio.BufferUnderflowException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleResolution;
+
+import static jdk.internal.module.ClassFileConstants.*;
+
+
+/**
+ * Read module information from a {@code module-info} class file.
+ *
+ * @implNote The rationale for the hand-coded reader is startup performance
+ * and fine control over the throwing of InvalidModuleDescriptorException.
+ */
+
+public final class ModuleInfo {
+
+    private static final JavaLangModuleAccess JLMA
+        = SharedSecrets.getJavaLangModuleAccess();
+
+    // supplies the set of packages when ModulePackages attribute not present
+    private final Supplier<Set<String>> packageFinder;
+
+    // indicates if the ModuleHashes attribute should be parsed
+    private final boolean parseHashes;
+
+    private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
+        packageFinder = pf;
+        parseHashes = ph;
+    }
+
+    private ModuleInfo(Supplier<Set<String>> pf) {
+        this(pf, true);
+    }
+
+    /**
+     * A holder class for the ModuleDescriptor that is created by reading the
+     * Module and other standard class file attributes. It also holds the objects
+     * that represent the non-standard class file attributes that are read from
+     * the class file.
+     */
+    public static final class Attributes {
+        private final ModuleDescriptor descriptor;
+        private final ModuleHashes recordedHashes;
+        private final ModuleResolution moduleResolution;
+        Attributes(ModuleDescriptor descriptor,
+                   ModuleHashes recordedHashes,
+                   ModuleResolution moduleResolution) {
+            this.descriptor = descriptor;
+            this.recordedHashes = recordedHashes;
+            this.moduleResolution = moduleResolution;
+        }
+        public ModuleDescriptor descriptor() {
+            return descriptor;
+        }
+        public ModuleHashes recordedHashes() {
+            return recordedHashes;
+        }
+        public ModuleResolution moduleResolution() {
+            return moduleResolution;
+        }
+    }
+
+
+    /**
+     * Reads a {@code module-info.class} from the given input stream.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws IOException
+     */
+    public static Attributes read(InputStream in, Supplier<Set<String>> pf)
+        throws IOException
+    {
+        try {
+            return new ModuleInfo(pf).doRead(new DataInputStream(in));
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        }
+    }
+
+    /**
+     * Reads a {@code module-info.class} from the given byte buffer.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws UncheckedIOException
+     */
+    public static Attributes read(ByteBuffer bb, Supplier<Set<String>> pf) {
+        try {
+            return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Reads a {@code module-info.class} from the given byte buffer
+     * but ignore the {@code ModuleHashes} attribute.
+     *
+     * @throws InvalidModuleDescriptorException
+     * @throws UncheckedIOException
+     */
+    public static Attributes readIgnoringHashes(ByteBuffer bb, Supplier<Set<String>> pf) {
+        try {
+            return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
+        } catch (EOFException x) {
+            throw truncatedModuleDescriptor();
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Reads the input as a module-info class file.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
+     * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder
+     *         because an identifier is not a legal Java identifier, duplicate
+     *         exports, and many other reasons
+     */
+    private Attributes doRead(DataInput in) throws IOException {
+
+        int magic = in.readInt();
+        if (magic != 0xCAFEBABE)
+            throw invalidModuleDescriptor("Bad magic number");
+
+        int minor_version = in.readUnsignedShort();
+        int major_version = in.readUnsignedShort();
+        if (major_version < 53) {
+            throw invalidModuleDescriptor("Must be >= 53.0");
+        }
+
+        ConstantPool cpool = new ConstantPool(in);
+
+        int access_flags = in.readUnsignedShort();
+        if (access_flags != ACC_MODULE)
+            throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
+
+        int this_class = in.readUnsignedShort();
+        String mn = cpool.getClassName(this_class);
+        if (!"module-info".equals(mn))
+            throw invalidModuleDescriptor("this_class should be module-info");
+
+        int super_class = in.readUnsignedShort();
+        if (super_class > 0)
+            throw invalidModuleDescriptor("bad #super_class");
+
+        int interfaces_count = in.readUnsignedShort();
+        if (interfaces_count > 0)
+            throw invalidModuleDescriptor("Bad #interfaces");
+
+        int fields_count = in.readUnsignedShort();
+        if (fields_count > 0)
+            throw invalidModuleDescriptor("Bad #fields");
+
+        int methods_count = in.readUnsignedShort();
+        if (methods_count > 0)
+            throw invalidModuleDescriptor("Bad #methods");
+
+        int attributes_count = in.readUnsignedShort();
+
+        // the names of the attributes found in the class file
+        Set<String> attributes = new HashSet<>();
+
+        Builder builder = null;
+        Set<String> packages = null;
+        String mainClass = null;
+        String[] osValues = null;
+        ModuleHashes hashes = null;
+        ModuleResolution moduleResolution = null;
+
+        for (int i = 0; i < attributes_count ; i++) {
+            int name_index = in.readUnsignedShort();
+            String attribute_name = cpool.getUtf8(name_index);
+            int length = in.readInt();
+
+            boolean added = attributes.add(attribute_name);
+            if (!added && isAttributeAtMostOnce(attribute_name)) {
+                throw invalidModuleDescriptor("More than one "
+                                              + attribute_name + " attribute");
+            }
+
+            switch (attribute_name) {
+
+                case MODULE :
+                    builder = readModuleAttribute(in, cpool);
+                    break;
+
+                case MODULE_PACKAGES :
+                    packages = readModulePackagesAttribute(in, cpool);
+                    break;
+
+                case MODULE_MAIN_CLASS :
+                    mainClass = readModuleMainClassAttribute(in, cpool);
+                    break;
+
+                case MODULE_TARGET :
+                    osValues = readModuleTargetAttribute(in, cpool);
+                    break;
+
+                case MODULE_HASHES :
+                    if (parseHashes) {
+                        hashes = readModuleHashesAttribute(in, cpool);
+                    } else {
+                        in.skipBytes(length);
+                    }
+                    break;
+
+                case MODULE_RESOLUTION :
+                    moduleResolution = readModuleResolution(in, cpool);
+                    break;
+
+                default:
+                    if (isAttributeDisallowed(attribute_name)) {
+                        throw invalidModuleDescriptor(attribute_name
+                                                      + " attribute not allowed");
+                    } else {
+                        in.skipBytes(length);
+                    }
+
+            }
+        }
+
+        // the Module attribute is required
+        if (builder == null) {
+            throw invalidModuleDescriptor(MODULE + " attribute not found");
+        }
+
+        // If the ModulePackages attribute is not present then the packageFinder
+        // is used to find the set of packages
+        boolean usedPackageFinder = false;
+        if (packages == null && packageFinder != null) {
+            try {
+                packages = new HashSet<>(packageFinder.get());
+            } catch (UncheckedIOException x) {
+                throw x.getCause();
+            }
+            usedPackageFinder = true;
+        }
+        if (packages != null) {
+            Set<String> exportedPackages = JLMA.exportedPackages(builder);
+            Set<String> openPackages = JLMA.openPackages(builder);
+            if (packages.containsAll(exportedPackages)
+                    && packages.containsAll(openPackages)) {
+                packages.removeAll(exportedPackages);
+                packages.removeAll(openPackages);
+            } else {
+                // the set of packages is not complete
+                Set<String> exportedAndOpenPackages = new HashSet<>();
+                exportedAndOpenPackages.addAll(exportedPackages);
+                exportedAndOpenPackages.addAll(openPackages);
+                for (String pn : exportedAndOpenPackages) {
+                    if (!packages.contains(pn)) {
+                        String tail;
+                        if (usedPackageFinder) {
+                            tail = " not found by package finder";
+                        } else {
+                            tail = " missing from ModulePackages attribute";
+                        }
+                        throw invalidModuleDescriptor("Package " + pn + tail);
+                    }
+                }
+                assert false; // should not get here
+            }
+            builder.contains(packages);
+        }
+
+        if (mainClass != null)
+            builder.mainClass(mainClass);
+        if (osValues != null) {
+            if (osValues[0] != null) builder.osName(osValues[0]);
+            if (osValues[1] != null) builder.osArch(osValues[1]);
+            if (osValues[2] != null) builder.osVersion(osValues[2]);
+        }
+
+        ModuleDescriptor descriptor = builder.build();
+        return new Attributes(descriptor, hashes, moduleResolution);
+    }
+
+    /**
+     * Reads the Module attribute, returning the ModuleDescriptor.Builder to
+     * build the corresponding ModuleDescriptor.
+     */
+    private Builder readModuleAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        // module_name
+        int module_name_index = in.readUnsignedShort();
+        String mn = cpool.getModuleName(module_name_index);
+
+        int module_flags = in.readUnsignedShort();
+        boolean open = ((module_flags & ACC_OPEN) != 0);
+        boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
+
+        Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic);
+
+        int module_version_index = in.readUnsignedShort();
+        if (module_version_index != 0) {
+            String vs = cpool.getUtf8(module_version_index);
+            builder.version(vs);
+        }
+
+        int requires_count = in.readUnsignedShort();
+        boolean requiresJavaBase = false;
+        for (int i=0; i<requires_count; i++) {
+            int requires_index = in.readUnsignedShort();
+            String dn = cpool.getModuleName(requires_index);
+
+            int requires_flags = in.readUnsignedShort();
+            Set<Requires.Modifier> mods;
+            if (requires_flags == 0) {
+                mods = Collections.emptySet();
+            } else {
+                mods = new HashSet<>();
+                if ((requires_flags & ACC_TRANSITIVE) != 0)
+                    mods.add(Requires.Modifier.TRANSITIVE);
+                if ((requires_flags & ACC_STATIC_PHASE) != 0)
+                    mods.add(Requires.Modifier.STATIC);
+                if ((requires_flags & ACC_SYNTHETIC) != 0)
+                    mods.add(Requires.Modifier.SYNTHETIC);
+                if ((requires_flags & ACC_MANDATED) != 0)
+                    mods.add(Requires.Modifier.MANDATED);
+            }
+
+            int requires_version_index = in.readUnsignedShort();
+            Version compiledVersion = null;
+            if (requires_version_index != 0) {
+                String vs = cpool.getUtf8(requires_version_index);
+                compiledVersion = Version.parse(vs);
+            }
+
+            if (compiledVersion == null) {
+                builder.requires(mods, dn);
+            } else {
+                builder.requires(mods, dn, compiledVersion);
+            }
+
+            if (dn.equals("java.base"))
+                requiresJavaBase = true;
+        }
+        if (mn.equals("java.base")) {
+            if (requires_count > 0) {
+                throw invalidModuleDescriptor("The requires table for java.base"
+                                              + " must be 0 length");
+            }
+        } else if (!requiresJavaBase) {
+            throw invalidModuleDescriptor("The requires table must have"
+                                          + " an entry for java.base");
+        }
+
+        int exports_count = in.readUnsignedShort();
+        if (exports_count > 0) {
+            for (int i=0; i<exports_count; i++) {
+                int exports_index = in.readUnsignedShort();
+                String pkg = cpool.getPackageName(exports_index);
+
+                Set<Exports.Modifier> mods;
+                int exports_flags = in.readUnsignedShort();
+                if (exports_flags == 0) {
+                    mods = Collections.emptySet();
+                } else {
+                    mods = new HashSet<>();
+                    if ((exports_flags & ACC_SYNTHETIC) != 0)
+                        mods.add(Exports.Modifier.SYNTHETIC);
+                    if ((exports_flags & ACC_MANDATED) != 0)
+                        mods.add(Exports.Modifier.MANDATED);
+                }
+
+                int exports_to_count = in.readUnsignedShort();
+                if (exports_to_count > 0) {
+                    Set<String> targets = new HashSet<>(exports_to_count);
+                    for (int j=0; j<exports_to_count; j++) {
+                        int exports_to_index = in.readUnsignedShort();
+                        targets.add(cpool.getModuleName(exports_to_index));
+                    }
+                    builder.exports(mods, pkg, targets);
+                } else {
+                    builder.exports(mods, pkg);
+                }
+            }
+        }
+
+        int opens_count = in.readUnsignedShort();
+        if (opens_count > 0) {
+            if (open) {
+                throw invalidModuleDescriptor("The opens table for an open"
+                                              + " module must be 0 length");
+            }
+            for (int i=0; i<opens_count; i++) {
+                int opens_index = in.readUnsignedShort();
+                String pkg = cpool.getPackageName(opens_index);
+
+                Set<Opens.Modifier> mods;
+                int opens_flags = in.readUnsignedShort();
+                if (opens_flags == 0) {
+                    mods = Collections.emptySet();
+                } else {
+                    mods = new HashSet<>();
+                    if ((opens_flags & ACC_SYNTHETIC) != 0)
+                        mods.add(Opens.Modifier.SYNTHETIC);
+                    if ((opens_flags & ACC_MANDATED) != 0)
+                        mods.add(Opens.Modifier.MANDATED);
+                }
+
+                int open_to_count = in.readUnsignedShort();
+                if (open_to_count > 0) {
+                    Set<String> targets = new HashSet<>(open_to_count);
+                    for (int j=0; j<open_to_count; j++) {
+                        int opens_to_index = in.readUnsignedShort();
+                        targets.add(cpool.getModuleName(opens_to_index));
+                    }
+                    builder.opens(mods, pkg, targets);
+                } else {
+                    builder.opens(mods, pkg);
+                }
+            }
+        }
+
+        int uses_count = in.readUnsignedShort();
+        if (uses_count > 0) {
+            for (int i=0; i<uses_count; i++) {
+                int index = in.readUnsignedShort();
+                String sn = cpool.getClassName(index);
+                builder.uses(sn);
+            }
+        }
+
+        int provides_count = in.readUnsignedShort();
+        if (provides_count > 0) {
+            for (int i=0; i<provides_count; i++) {
+                int index = in.readUnsignedShort();
+                String sn = cpool.getClassName(index);
+                int with_count = in.readUnsignedShort();
+                List<String> providers = new ArrayList<>(with_count);
+                for (int j=0; j<with_count; j++) {
+                    index = in.readUnsignedShort();
+                    String pn = cpool.getClassName(index);
+                    providers.add(pn);
+                }
+                builder.provides(sn, providers);
+            }
+        }
+
+        return builder;
+    }
+
+    /**
+     * Reads the ModulePackages attribute
+     */
+    private Set<String> readModulePackagesAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int package_count = in.readUnsignedShort();
+        Set<String> packages = new HashSet<>(package_count);
+        for (int i=0; i<package_count; i++) {
+            int index = in.readUnsignedShort();
+            String pn = cpool.getPackageName(index);
+            boolean added = packages.add(pn);
+            if (!added) {
+                throw invalidModuleDescriptor("Package " + pn + " in ModulePackages"
+                                              + "attribute more than once");
+            }
+        }
+        return packages;
+    }
+
+    /**
+     * Reads the ModuleMainClass attribute
+     */
+    private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int index = in.readUnsignedShort();
+        return cpool.getClassName(index);
+    }
+
+    /**
+     * Reads the ModuleTarget attribute
+     */
+    private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        String[] values = new String[3];
+
+        int name_index = in.readUnsignedShort();
+        if (name_index != 0)
+            values[0] = cpool.getUtf8(name_index);
+
+        int arch_index = in.readUnsignedShort();
+        if (arch_index != 0)
+            values[1] = cpool.getUtf8(arch_index);
+
+        int version_index = in.readUnsignedShort();
+        if (version_index != 0)
+            values[2] = cpool.getUtf8(version_index);
+
+        return values;
+    }
+
+
+    /**
+     * Reads the ModuleHashes attribute
+     */
+    private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
+        throws IOException
+    {
+        int algorithm_index = in.readUnsignedShort();
+        String algorithm = cpool.getUtf8(algorithm_index);
+
+        int hash_count = in.readUnsignedShort();
+        Map<String, byte[]> map = new HashMap<>(hash_count);
+        for (int i=0; i<hash_count; i++) {
+            int module_name_index = in.readUnsignedShort();
+            String mn = cpool.getModuleName(module_name_index);
+            int hash_length = in.readUnsignedShort();
+            if (hash_length == 0) {
+                throw invalidModuleDescriptor("hash_length == 0");
+            }
+            byte[] hash = new byte[hash_length];
+            in.readFully(hash);
+            map.put(mn, hash);
+        }
+
+        return new ModuleHashes(algorithm, map);
+    }
+
+    /**
+     * Reads the ModuleResolution attribute.
+     */
+    private ModuleResolution readModuleResolution(DataInput in,
+                                                  ConstantPool cpool)
+        throws IOException
+    {
+        int flags = in.readUnsignedShort();
+
+        int reason = 0;
+        if ((flags & WARN_DEPRECATED) != 0)
+            reason = WARN_DEPRECATED;
+        if ((flags & WARN_DEPRECATED_FOR_REMOVAL) != 0) {
+            if (reason != 0)
+                throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
+            reason = WARN_DEPRECATED_FOR_REMOVAL;
+        }
+        if ((flags & WARN_INCUBATING) != 0) {
+            if (reason != 0)
+                throw invalidModuleDescriptor("Bad module resolution flags:" + flags);
+        }
+
+        return new ModuleResolution(flags);
+    }
+
+
+    /**
+     * Returns true if the given attribute can be present at most once
+     * in the class file. Returns false otherwise.
+     */
+    private static boolean isAttributeAtMostOnce(String name) {
+
+        if (name.equals(MODULE) ||
+                name.equals(SOURCE_FILE) ||
+                name.equals(SDE) ||
+                name.equals(MODULE_PACKAGES) ||
+                name.equals(MODULE_MAIN_CLASS) ||
+                name.equals(MODULE_TARGET) ||
+                name.equals(MODULE_HASHES) ||
+                name.equals(MODULE_RESOLUTION))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Return true if the given attribute name is the name of a pre-defined
+     * attribute that is not allowed in the class file.
+     *
+     * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
+     * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
+     */
+    private static boolean isAttributeDisallowed(String name) {
+        Set<String> notAllowed = predefinedNotAllowed;
+        if (notAllowed == null) {
+            notAllowed = Set.of(
+                    "ConstantValue",
+                    "Code",
+                    "StackMapTable",
+                    "Exceptions",
+                    "EnclosingMethod",
+                    "Signature",
+                    "LineNumberTable",
+                    "LocalVariableTable",
+                    "LocalVariableTypeTable",
+                    "RuntimeVisibleParameterAnnotations",
+                    "RuntimeInvisibleParameterAnnotations",
+                    "RuntimeVisibleTypeAnnotations",
+                    "RuntimeInvisibleTypeAnnotations",
+                    "Synthetic",
+                    "AnnotationDefault",
+                    "BootstrapMethods",
+                    "MethodParameters");
+            predefinedNotAllowed = notAllowed;
+        }
+        return notAllowed.contains(name);
+    }
+
+    // lazily created set the pre-defined attributes that are not allowed
+    private static volatile Set<String> predefinedNotAllowed;
+
+
+    /**
+     * The constant pool in a class file.
+     */
+    private static class ConstantPool {
+        static final int CONSTANT_Utf8 = 1;
+        static final int CONSTANT_Integer = 3;
+        static final int CONSTANT_Float = 4;
+        static final int CONSTANT_Long = 5;
+        static final int CONSTANT_Double = 6;
+        static final int CONSTANT_Class = 7;
+        static final int CONSTANT_String = 8;
+        static final int CONSTANT_Fieldref = 9;
+        static final int CONSTANT_Methodref = 10;
+        static final int CONSTANT_InterfaceMethodref = 11;
+        static final int CONSTANT_NameAndType = 12;
+        static final int CONSTANT_MethodHandle = 15;
+        static final int CONSTANT_MethodType = 16;
+        static final int CONSTANT_InvokeDynamic = 18;
+        static final int CONSTANT_Module = 19;
+        static final int CONSTANT_Package = 20;
+
+        private static class Entry {
+            protected Entry(int tag) {
+                this.tag = tag;
+            }
+            final int tag;
+        }
+
+        private static class IndexEntry extends Entry {
+            IndexEntry(int tag, int index) {
+                super(tag);
+                this.index = index;
+            }
+            final int index;
+        }
+
+        private static class Index2Entry extends Entry {
+            Index2Entry(int tag, int index1, int index2) {
+                super(tag);
+                this.index1 = index1;
+                this.index2 = index2;
+            }
+            final int index1,  index2;
+        }
+
+        private static class ValueEntry extends Entry {
+            ValueEntry(int tag, Object value) {
+                super(tag);
+                this.value = value;
+            }
+            final Object value;
+        }
+
+        final Entry[] pool;
+
+        ConstantPool(DataInput in) throws IOException {
+            int count = in.readUnsignedShort();
+            pool = new Entry[count];
+
+            for (int i = 1; i < count; i++) {
+                int tag = in.readUnsignedByte();
+                switch (tag) {
+
+                    case CONSTANT_Utf8:
+                        String svalue = in.readUTF();
+                        pool[i] = new ValueEntry(tag, svalue);
+                        break;
+
+                    case CONSTANT_Class:
+                    case CONSTANT_Package:
+                    case CONSTANT_Module:
+                    case CONSTANT_String:
+                        int index = in.readUnsignedShort();
+                        pool[i] = new IndexEntry(tag, index);
+                        break;
+
+                    case CONSTANT_Double:
+                        double dvalue = in.readDouble();
+                        pool[i] = new ValueEntry(tag, dvalue);
+                        i++;
+                        break;
+
+                    case CONSTANT_Fieldref:
+                    case CONSTANT_InterfaceMethodref:
+                    case CONSTANT_Methodref:
+                    case CONSTANT_InvokeDynamic:
+                    case CONSTANT_NameAndType:
+                        int index1 = in.readUnsignedShort();
+                        int index2 = in.readUnsignedShort();
+                        pool[i] = new Index2Entry(tag, index1, index2);
+                        break;
+
+                    case CONSTANT_MethodHandle:
+                        int refKind = in.readUnsignedByte();
+                        index = in.readUnsignedShort();
+                        pool[i] = new Index2Entry(tag, refKind, index);
+                        break;
+
+                    case CONSTANT_MethodType:
+                        index = in.readUnsignedShort();
+                        pool[i] = new IndexEntry(tag, index);
+                        break;
+
+                    case CONSTANT_Float:
+                        float fvalue = in.readFloat();
+                        pool[i] = new ValueEntry(tag, fvalue);
+                        break;
+
+                    case CONSTANT_Integer:
+                        int ivalue = in.readInt();
+                        pool[i] = new ValueEntry(tag, ivalue);
+                        break;
+
+                    case CONSTANT_Long:
+                        long lvalue = in.readLong();
+                        pool[i] = new ValueEntry(tag, lvalue);
+                        i++;
+                        break;
+
+                    default:
+                        throw invalidModuleDescriptor("Bad constant pool entry: "
+                                                      + i);
+                }
+            }
+        }
+
+        String getClassName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Class) {
+                throw invalidModuleDescriptor("CONSTANT_Class expected at entry: "
+                                              + index);
+            }
+            String value = getUtf8(((IndexEntry) e).index);
+            checkUnqualifiedName("CONSTANT_Class", index, value);
+            return value.replace('/', '.');  // internal form -> binary name
+        }
+
+        String getPackageName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Package) {
+                throw invalidModuleDescriptor("CONSTANT_Package expected at entry: "
+                                              + index);
+            }
+            String value = getUtf8(((IndexEntry) e).index);
+            checkUnqualifiedName("CONSTANT_Package", index, value);
+            return value.replace('/', '.');  // internal form -> binary name
+        }
+
+        String getModuleName(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Module) {
+                throw invalidModuleDescriptor("CONSTANT_Module expected at entry: "
+                                              + index);
+            }
+            String value = getUtf8(((IndexEntry) e).index);
+            return decodeModuleName(index, value);
+        }
+
+        String getUtf8(int index) {
+            checkIndex(index);
+            Entry e = pool[index];
+            if (e.tag != CONSTANT_Utf8) {
+                throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: "
+                                              + index);
+            }
+            return (String) (((ValueEntry) e).value);
+        }
+
+        void checkIndex(int index) {
+            if (index < 1 || index >= pool.length)
+                throw invalidModuleDescriptor("Index into constant pool out of range");
+        }
+
+        void checkUnqualifiedName(String what, int index, String value) {
+            int len = value.length();
+            if (len == 0) {
+                throw invalidModuleDescriptor(what + " at entry " + index
+                                              + " has zero length");
+            }
+            for (int i=0; i<len; i++) {
+                char c = value.charAt(i);
+                if (c == '.' || c == ';' || c == '[') {
+                    throw invalidModuleDescriptor(what + " at entry " + index
+                                                  + " has illegal character: '"
+                                                  + c + "'");
+                }
+            }
+        }
+
+        /**
+         * "Decode" a module name that has been read from the constant pool.
+         */
+        String decodeModuleName(int index, String value) {
+            int len = value.length();
+            if (len == 0) {
+                throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                              + index + " is zero length");
+            }
+            int i = 0;
+            while (i < len) {
+                int cp = value.codePointAt(i);
+                if (cp == ':' || cp == '@' || cp < 0x20) {
+                    throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                  + index + " has illegal character: "
+                                                  + Character.getName(cp));
+                }
+
+                // blackslash is the escape character
+                if (cp == '\\')
+                    return decodeModuleName(index, i, value);
+
+                i += Character.charCount(cp);
+            }
+            return value;
+        }
+
+        /**
+         * "Decode" a module name that has been read from the constant pool and
+         * partly checked for illegal characters (up to position {@code i}).
+         */
+        String decodeModuleName(int index, int i, String value) {
+            StringBuilder sb = new StringBuilder();
+
+            // copy the code points that have been checked
+            int j = 0;
+            while (j < i) {
+                int cp = value.codePointAt(j);
+                sb.appendCodePoint(cp);
+                j += Character.charCount(cp);
+            }
+
+            // decode from position {@code i} to end
+            int len = value.length();
+            while (i < len) {
+                int cp = value.codePointAt(i);
+                if (cp == ':' || cp == '@' || cp < 0x20) {
+                    throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                  + index + " has illegal character: "
+                                                  + Character.getName(cp));
+                }
+
+                // blackslash is the escape character
+                if (cp == '\\') {
+                    j = i + Character.charCount(cp);
+                    if (j >= len) {
+                        throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                       + index + " has illegal "
+                                                       + "escape sequence");
+                    }
+                    int next = value.codePointAt(j);
+                    if (next != '\\' && next != ':' && next != '@') {
+                        throw invalidModuleDescriptor("CONSTANT_Module at entry "
+                                                      + index + " has illegal "
+                                                      + "escape sequence");
+                    }
+                    sb.appendCodePoint(next);
+                    i += Character.charCount(next);
+                } else {
+                    sb.appendCodePoint(cp);
+                }
+
+                i += Character.charCount(cp);
+            }
+            return sb.toString();
+        }
+    }
+
+    /**
+     * A DataInput implementation that reads from a ByteBuffer.
+     */
+    private static class DataInputWrapper implements DataInput {
+        private final ByteBuffer bb;
+
+        DataInputWrapper(ByteBuffer bb) {
+            this.bb = bb;
+        }
+
+        @Override
+        public void readFully(byte b[]) throws IOException {
+            readFully(b, 0, b.length);
+        }
+
+        @Override
+        public void readFully(byte b[], int off, int len) throws IOException {
+            try {
+                bb.get(b, off, len);
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int skipBytes(int n) {
+            int skip = Math.min(n, bb.remaining());
+            bb.position(bb.position() + skip);
+            return skip;
+        }
+
+        @Override
+        public boolean readBoolean() throws IOException {
+            try {
+                int ch = bb.get();
+                return (ch != 0);
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public byte readByte() throws IOException {
+            try {
+                return bb.get();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int readUnsignedByte() throws IOException {
+            try {
+                return ((int) bb.get()) & 0xff;
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public short readShort() throws IOException {
+            try {
+                return bb.getShort();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int readUnsignedShort() throws IOException {
+            try {
+                return ((int) bb.getShort()) & 0xffff;
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public char readChar() throws IOException {
+            try {
+                return bb.getChar();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public int readInt() throws IOException {
+            try {
+                return bb.getInt();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public long readLong() throws IOException {
+            try {
+                return bb.getLong();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public float readFloat() throws IOException {
+            try {
+                return bb.getFloat();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public double readDouble() throws IOException {
+            try {
+                return bb.getDouble();
+            } catch (BufferUnderflowException e) {
+                throw new EOFException(e.getMessage());
+            }
+        }
+
+        @Override
+        public String readLine() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public String readUTF() throws IOException {
+            // ### Need to measure the performance and feasibility of using
+            // the UTF-8 decoder instead.
+            return DataInputStream.readUTF(this);
+        }
+    }
+
+    /**
+     * Returns an InvalidModuleDescriptorException with the given detail
+     * message
+     */
+    private static InvalidModuleDescriptorException
+    invalidModuleDescriptor(String msg) {
+        return new InvalidModuleDescriptorException(msg);
+    }
+
+    /**
+     * Returns an InvalidModuleDescriptorException with a detail message to
+     * indicate that the class file is truncated.
+     */
+    private static InvalidModuleDescriptorException truncatedModuleDescriptor() {
+        return invalidModuleDescriptor("Truncated module-info.class");
+    }
+
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Mon Dec 19 16:05:38 2016 +0000
@@ -70,6 +70,9 @@
     // the hashes for the Hashes attribute
     private ModuleHashes hashes;
 
+    // the value of the ModuleResolution attribute
+    private ModuleResolution moduleResolution;
+
     private ModuleInfoExtender(InputStream in) {
         this.in = in;
     }
@@ -121,6 +124,14 @@
     }
 
     /**
+     * Sets the value for the ModuleResolution attribute.
+     */
+    public ModuleInfoExtender moduleResolution(ModuleResolution mres) {
+        this.moduleResolution = mres;
+        return this;
+    }
+
+    /**
      * A ClassVisitor that supports adding class file attributes. If an
      * attribute already exists then the first occurence of the attribute
      * is replaced.
@@ -183,21 +194,20 @@
 
         if (packages != null)
             cv.addAttribute(new ModulePackagesAttribute(packages));
-        if (version != null)
-            cv.addAttribute(new ModuleVersionAttribute(version));
         if (mainClass != null)
             cv.addAttribute(new ModuleMainClassAttribute(mainClass));
         if (osName != null || osArch != null || osVersion != null)
             cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
         if (hashes != null)
             cv.addAttribute(new ModuleHashesAttribute(hashes));
+        if (moduleResolution != null)
+            cv.addAttribute(new ModuleResolutionAttribute(moduleResolution.value()));
 
         List<Attribute> attrs = new ArrayList<>();
 
         // prototypes of attributes that should be parsed
-        attrs.add(new ModuleAttribute());
+        attrs.add(new ModuleAttribute(version));
         attrs.add(new ModulePackagesAttribute());
-        attrs.add(new ModuleVersionAttribute());
         attrs.add(new ModuleMainClassAttribute());
         attrs.add(new ModuleTargetAttribute());
         attrs.add(new ModuleHashesAttribute());
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Mon Dec 19 16:05:38 2016 +0000
@@ -49,13 +49,12 @@
      * returning it in a byte array.
      */
     private static byte[] toModuleInfo(ModuleDescriptor md) {
-
         ClassWriter cw = new ClassWriter(0);
-        cw.visit(Opcodes.V1_9, ACC_MODULE, null, null, null, null);
+        cw.visit(Opcodes.V1_9, ACC_MODULE, "module-info", null, null, null);
         cw.visitAttribute(new ModuleAttribute(md));
 
-        // for tests: write the Packages attribute when there are packages that
-        // aren't exported or open
+        // for tests: write the ModulePackages attribute when there are packages
+        // that aren't exported or open
         Stream<String> exported = md.exports().stream()
                 .map(ModuleDescriptor.Exports::source);
         Stream<String> open = md.opens().stream()
@@ -64,10 +63,10 @@
         if (md.packages().size() > exportedOrOpen)
             cw.visitAttribute(new ModulePackagesAttribute(md.packages()));
 
-        md.version().ifPresent(v -> cw.visitAttribute(new ModuleVersionAttribute(v)));
+        // write ModuleMainClass if the module has a main class
         md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
 
-        // write the TargetPlatform attribute if have any of OS name/arch/version
+        // write ModuleTarget attribute if have any of OS name/arch/version
         String osName = md.osName().orElse(null);
         String osArch = md.osArch().orElse(null);
         String osVersion = md.osVersion().orElse(null);
@@ -76,7 +75,6 @@
         }
 
         cw.visitEnd();
-
         return cw.toByteArray();
     }
 
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Mon Dec 19 16:05:38 2016 +0000
@@ -149,9 +149,22 @@
 
         // return a module reference to the patched module
         URI location = mref.location().orElse(null);
-        return JLMA.newPatchedModule(descriptor,
-                                     location,
-                                     () -> new PatchedModuleReader(paths, mref));
+
+        ModuleHashes recordedHashes = null;
+        ModuleResolution mres = null;
+        if (mref instanceof ModuleReferenceImpl) {
+            ModuleReferenceImpl impl = (ModuleReferenceImpl)mref;
+            recordedHashes = impl.recordedHashes();
+            mres = impl.moduleResolution();
+        }
+
+        return new ModuleReferenceImpl(descriptor,
+                                       location,
+                                       () -> new PatchedModuleReader(paths, mref),
+                                       this,
+                                       recordedHashes,
+                                       null,
+                                       mres);
 
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2014, 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.module;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
+import java.lang.module.FindException;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.zip.ZipFile;
+
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.jmod.JmodFile.Section;
+import jdk.internal.perf.PerfCounter;
+import jdk.internal.util.jar.VersionedStream;
+
+
+/**
+ * A {@code ModuleFinder} that locates modules on the file system by searching
+ * a sequence of directories or packaged modules.
+ *
+ * The {@code ModuleFinder} can be created to work in either the run-time
+ * or link-time phases. In both cases it locates modular JAR and exploded
+ * modules. When created for link-time then it additionally locates
+ * modules in JMOD files.
+ */
+
+public class ModulePath implements ModuleFinder {
+    private static final String MODULE_INFO = "module-info.class";
+
+    // the version to use for multi-release modular JARs
+    private final Runtime.Version releaseVersion;
+
+    // true for the link phase (supports modules packaged in JMOD format)
+    private final boolean isLinkPhase;
+
+    // the entries on this module path
+    private final Path[] entries;
+    private int next;
+
+    // map of module name to module reference map for modules already located
+    private final Map<String, ModuleReference> cachedModules = new HashMap<>();
+
+    public ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
+        this.releaseVersion = version;
+        this.isLinkPhase = isLinkPhase;
+        this.entries = entries.clone();
+        for (Path entry : this.entries) {
+            Objects.requireNonNull(entry);
+        }
+    }
+
+    public ModulePath(Path... entries) {
+        this(JarFile.runtimeVersion(), false, entries);
+    }
+
+    @Override
+    public Optional<ModuleReference> find(String name) {
+        Objects.requireNonNull(name);
+
+        // try cached modules
+        ModuleReference m = cachedModules.get(name);
+        if (m != null)
+            return Optional.of(m);
+
+        // the module may not have been encountered yet
+        while (hasNextEntry()) {
+            scanNextEntry();
+            m = cachedModules.get(name);
+            if (m != null)
+                return Optional.of(m);
+        }
+        return Optional.empty();
+    }
+
+    @Override
+    public Set<ModuleReference> findAll() {
+        // need to ensure that all entries have been scanned
+        while (hasNextEntry()) {
+            scanNextEntry();
+        }
+        return cachedModules.values().stream().collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns {@code true} if there are additional entries to scan
+     */
+    private boolean hasNextEntry() {
+        return next < entries.length;
+    }
+
+    /**
+     * Scans the next entry on the module path. A no-op if all entries have
+     * already been scanned.
+     *
+     * @throws FindException if an error occurs scanning the next entry
+     */
+    private void scanNextEntry() {
+        if (hasNextEntry()) {
+
+            long t0 = System.nanoTime();
+
+            Path entry = entries[next];
+            Map<String, ModuleReference> modules = scan(entry);
+            next++;
+
+            // update cache, ignoring duplicates
+            int initialSize = cachedModules.size();
+            for (Map.Entry<String, ModuleReference> e : modules.entrySet()) {
+                cachedModules.putIfAbsent(e.getKey(), e.getValue());
+            }
+
+            // update counters
+            int added = cachedModules.size() - initialSize;
+            moduleCount.add(added);
+
+            scanTime.addElapsedTimeFrom(t0);
+        }
+    }
+
+
+    /**
+     * Scan the given module path entry. If the entry is a directory then it is
+     * a directory of modules or an exploded module. If the entry is a regular
+     * file then it is assumed to be a packaged module.
+     *
+     * @throws FindException if an error occurs scanning the entry
+     */
+    private Map<String, ModuleReference> scan(Path entry) {
+
+        BasicFileAttributes attrs;
+        try {
+            attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+        } catch (NoSuchFileException e) {
+            return Collections.emptyMap();
+        } catch (IOException ioe) {
+            throw new FindException(ioe);
+        }
+
+        try {
+
+            if (attrs.isDirectory()) {
+                Path mi = entry.resolve(MODULE_INFO);
+                if (!Files.exists(mi)) {
+                    // does not exist or unable to determine so assume a
+                    // directory of modules
+                    return scanDirectory(entry);
+                }
+            }
+
+            // packaged or exploded module
+            ModuleReference mref = readModule(entry, attrs);
+            if (mref != null) {
+                String name = mref.descriptor().name();
+                return Collections.singletonMap(name, mref);
+            } else {
+                // skipped
+                return Collections.emptyMap();
+            }
+
+        } catch (IOException ioe) {
+            throw new FindException(ioe);
+        }
+    }
+
+
+    /**
+     * Scans the given directory for packaged or exploded modules.
+     *
+     * @return a map of module name to ModuleReference for the modules found
+     *         in the directory
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws FindException if an error occurs scanning the entry or the
+     *         directory contains two or more modules with the same name
+     */
+    private Map<String, ModuleReference> scanDirectory(Path dir)
+        throws IOException
+    {
+        // The map of name -> mref of modules found in this directory.
+        Map<String, ModuleReference> nameToReference = new HashMap<>();
+
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+            for (Path entry : stream) {
+                BasicFileAttributes attrs;
+                try {
+                    attrs = Files.readAttributes(entry, BasicFileAttributes.class);
+                } catch (NoSuchFileException ignore) {
+                    // file has been removed or moved, ignore for now
+                    continue;
+                }
+
+                ModuleReference mref = readModule(entry, attrs);
+
+                // module found
+                if (mref != null) {
+                    // can have at most one version of a module in the directory
+                    String name = mref.descriptor().name();
+                    ModuleReference previous = nameToReference.put(name, mref);
+                    if (previous != null) {
+                        String fn1 = fileName(mref);
+                        String fn2 = fileName(previous);
+                        throw new FindException("Two versions of module "
+                                                 + name + " found in " + dir
+                                                 + " (" + fn1 + " and " + fn2 + ")");
+                    }
+                }
+            }
+        }
+
+        return nameToReference;
+    }
+
+
+    /**
+     * Locates a packaged or exploded module, returning a {@code ModuleReference}
+     * to the module. Returns {@code null} if the entry is skipped because it is
+     * to a directory that does not contain a module-info.class or it's a hidden
+     * file.
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws FindException if the file is not recognized as a module or an
+     *         error occurs parsing its module descriptor
+     */
+    private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
+        throws IOException
+    {
+        try {
+
+            if (attrs.isDirectory()) {
+                return readExplodedModule(entry); // may return null
+            }
+
+            String fn = entry.getFileName().toString();
+            if (attrs.isRegularFile()) {
+                if (fn.endsWith(".jar")) {
+                    return readJar(entry);
+                } else if (fn.endsWith(".jmod")) {
+                    if (isLinkPhase)
+                        return readJMod(entry);
+                    throw new FindException("JMOD files not supported: " + entry);
+                }
+            }
+
+            // skip hidden files
+            if (fn.startsWith(".") || Files.isHidden(entry)) {
+                return null;
+            } else {
+                throw new FindException("Unrecognized module: " + entry);
+            }
+
+        } catch (InvalidModuleDescriptorException e) {
+            throw new FindException("Error reading module: " + entry, e);
+        }
+    }
+
+
+    /**
+     * Returns a string with the file name of the module if possible.
+     * If the module location is not a file URI then return the URI
+     * as a string.
+     */
+    private String fileName(ModuleReference mref) {
+        URI uri = mref.location().orElse(null);
+        if (uri != null) {
+            if (uri.getScheme().equalsIgnoreCase("file")) {
+                Path file = Paths.get(uri);
+                return file.getFileName().toString();
+            } else {
+                return uri.toString();
+            }
+        } else {
+            return "<unknown>";
+        }
+    }
+
+    // -- jmod files --
+
+    private Set<String> jmodPackages(JmodFile jf) {
+        return jf.stream()
+            .filter(e -> e.section() == Section.CLASSES)
+            .map(JmodFile.Entry::name)
+            .map(this::toPackageName)
+            .flatMap(Optional::stream)
+            .collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns a {@code ModuleReference} to a module in jmod file on the
+     * file system.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
+     */
+    private ModuleReference readJMod(Path file) throws IOException {
+        try (JmodFile jf = new JmodFile(file)) {
+            ModuleInfo.Attributes attrs;
+            try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
+                attrs  = ModuleInfo.read(in, () -> jmodPackages(jf));
+            }
+            return ModuleReferences.newJModModule(attrs, file);
+        }
+    }
+
+
+    // -- JAR files --
+
+    private static final String SERVICES_PREFIX = "META-INF/services/";
+
+    /**
+     * Returns the service type corresponding to the name of a services
+     * configuration file if it is a valid Java identifier.
+     *
+     * 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 (Checks.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;
+    }
+
+    /**
+     * Treat the given JAR file as a module as follows:
+     *
+     * 1. The module name (and optionally the version) is derived from the file
+     *    name of the JAR file
+     * 2. All packages are exported and open
+     * 3. It has no non-exported/non-open packages
+     * 4. The contents of any META-INF/services configuration files are mapped
+     *    to "provides" declarations
+     * 5. The Main-Class attribute in the main attributes of the JAR manifest
+     *    is mapped to the module descriptor mainClass
+     */
+    private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
+        throws IOException
+    {
+        // Derive module name and version from JAR file name
+
+        String fn = jf.getName();
+        int i = fn.lastIndexOf(File.separator);
+        if (i != -1)
+            fn = fn.substring(i+1);
+
+        // drop .jar
+        String mn = fn.substring(0, fn.length()-4);
+        String vs = null;
+
+        // find first occurrence of -${NUMBER}. or -${NUMBER}$
+        Matcher matcher = Patterns.DASH_VERSION.matcher(mn);
+        if (matcher.find()) {
+            int start = matcher.start();
+
+            // attempt to parse the tail as a version string
+            try {
+                String tail = mn.substring(start+1);
+                ModuleDescriptor.Version.parse(tail);
+                vs = tail;
+            } catch (IllegalArgumentException ignore) { }
+
+            mn = mn.substring(0, start);
+        }
+
+        // finally clean up the module name
+        mn = cleanModuleName(mn);
+
+        // Builder throws IAE if module name is empty or invalid
+        ModuleDescriptor.Builder builder
+            = ModuleDescriptor.automaticModule(mn)
+                .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
+        if (vs != null)
+            builder.version(vs);
+
+        // scan the names of the entries in the JAR file
+        Map<Boolean, Set<String>> map = VersionedStream.stream(jf)
+                .filter(e -> !e.isDirectory())
+                .map(JarEntry::getName)
+                .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
+                                                   Collectors.toSet()));
+
+        Set<String> resources = map.get(Boolean.FALSE);
+        Set<String> configFiles = map.get(Boolean.TRUE);
+        // all packages are exported and open
+        resources.stream()
+                .map(this::toPackageName)
+                .flatMap(Optional::stream)
+                .distinct()
+                .forEach(pn -> builder.exports(pn).opens(pn));
+
+        // map names of service configuration files to service names
+        Set<String> serviceNames = configFiles.stream()
+                .map(this::toServiceName)
+                .flatMap(Optional::stream)
+                .collect(Collectors.toSet());
+
+        // parse each service configuration file
+        for (String sn : serviceNames) {
+            JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
+            List<String> providerClasses = new ArrayList<>();
+            try (InputStream in = jf.getInputStream(entry)) {
+                BufferedReader reader
+                    = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+                String cn;
+                while ((cn = nextLine(reader)) != null) {
+                    if (cn.length() > 0) {
+                        providerClasses.add(cn);
+                    }
+                }
+            }
+            if (!providerClasses.isEmpty())
+                builder.provides(sn, providerClasses);
+        }
+
+        // Main-Class attribute if it exists
+        Manifest man = jf.getManifest();
+        if (man != null) {
+            Attributes attrs = man.getMainAttributes();
+            String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
+            if (mainClass != null)
+                builder.mainClass(mainClass.replace("/", "."));
+        }
+
+        return builder.build();
+    }
+
+    /**
+     * Patterns used to derive the module name from a JAR file name.
+     */
+    private static class Patterns {
+        static final Pattern DASH_VERSION = Pattern.compile("-(\\d+(\\.|$))");
+        static final Pattern TRAILING_VERSION = Pattern.compile("(\\.|\\d)*$");
+        static final Pattern NON_ALPHANUM = Pattern.compile("[^A-Za-z0-9]");
+        static final Pattern REPEATING_DOTS = Pattern.compile("(\\.)(\\1)+");
+        static final Pattern LEADING_DOTS = Pattern.compile("^\\.");
+        static final Pattern TRAILING_DOTS = Pattern.compile("\\.$");
+    }
+
+    /**
+     * Clean up candidate module name derived from a JAR file name.
+     */
+    private static String cleanModuleName(String mn) {
+        // drop trailing version from name
+        mn = Patterns.TRAILING_VERSION.matcher(mn).replaceAll("");
+
+        // replace non-alphanumeric
+        mn = Patterns.NON_ALPHANUM.matcher(mn).replaceAll(".");
+
+        // collapse repeating dots
+        mn = Patterns.REPEATING_DOTS.matcher(mn).replaceAll(".");
+
+        // drop leading dots
+        if (mn.length() > 0 && mn.charAt(0) == '.')
+            mn = Patterns.LEADING_DOTS.matcher(mn).replaceAll("");
+
+        // drop trailing dots
+        int len = mn.length();
+        if (len > 0 && mn.charAt(len-1) == '.')
+            mn = Patterns.TRAILING_DOTS.matcher(mn).replaceAll("");
+
+        return mn;
+    }
+
+    private Set<String> jarPackages(JarFile jf) {
+        return VersionedStream.stream(jf)
+                .filter(e -> !e.isDirectory())
+                .map(JarEntry::getName)
+                .map(this::toPackageName)
+                .flatMap(Optional::stream)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * Returns a {@code ModuleReference} to a module in modular JAR file on
+     * the file system.
+     *
+     * @throws IOException
+     * @throws FindException
+     * @throws InvalidModuleDescriptorException
+     */
+    private ModuleReference readJar(Path file) throws IOException {
+        try (JarFile jf = new JarFile(file.toFile(),
+                                      true,               // verify
+                                      ZipFile.OPEN_READ,
+                                      releaseVersion))
+        {
+            ModuleInfo.Attributes attrs;
+            JarEntry entry = jf.getJarEntry(MODULE_INFO);
+            if (entry == null) {
+
+                // no module-info.class so treat it as automatic module
+                try {
+                    ModuleDescriptor md = deriveModuleDescriptor(jf);
+                    attrs = new ModuleInfo.Attributes(md, null, null);
+                } catch (IllegalArgumentException iae) {
+                    throw new FindException(
+                        "Unable to derive module descriptor for: "
+                        + jf.getName(), iae);
+                }
+
+            } else {
+                attrs = ModuleInfo.read(jf.getInputStream(entry),
+                                        () -> jarPackages(jf));
+            }
+
+            return ModuleReferences.newJarModule(attrs, file);
+        }
+    }
+
+
+    // -- exploded directories --
+
+    private Set<String> explodedPackages(Path dir) {
+        try {
+            return Files.find(dir, Integer.MAX_VALUE,
+                              ((path, attrs) -> attrs.isRegularFile()))
+                    .map(path -> dir.relativize(path))
+                    .map(this::toPackageName)
+                    .flatMap(Optional::stream)
+                    .collect(Collectors.toSet());
+        } catch (IOException x) {
+            throw new UncheckedIOException(x);
+        }
+    }
+
+    /**
+     * Returns a {@code ModuleReference} to an exploded module on the file
+     * system or {@code null} if {@code module-info.class} not found.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
+     */
+    private ModuleReference readExplodedModule(Path dir) throws IOException {
+        Path mi = dir.resolve(MODULE_INFO);
+        ModuleInfo.Attributes attrs;
+        try (InputStream in = Files.newInputStream(mi)) {
+            attrs = ModuleInfo.read(new BufferedInputStream(in),
+                                    () -> explodedPackages(dir));
+        } catch (NoSuchFileException e) {
+            // for now
+            return null;
+        }
+        return ModuleReferences.newExplodedModule(attrs, dir);
+    }
+
+    /**
+     * Maps the name of an entry in a JAR or ZIP file to a package name.
+     *
+     * @throws IllegalArgumentException if the name is a class file in
+     *         the top-level directory of the JAR/ZIP file (and it's
+     *         not module-info.class)
+     */
+    private Optional<String> toPackageName(String name) {
+        assert !name.endsWith("/");
+
+        int index = name.lastIndexOf("/");
+        if (index == -1) {
+            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
+                throw new IllegalArgumentException(name
+                        + " found in top-level directory:"
+                        + " (unnamed package not allowed in module)");
+            }
+            return Optional.empty();
+        }
+
+        String pn = name.substring(0, index).replace('/', '.');
+        if (Checks.isJavaIdentifier(pn)) {
+            return Optional.of(pn);
+        } else {
+            // not a valid package name
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Maps the relative path of an entry in an exploded module to a package
+     * name.
+     *
+     * @throws IllegalArgumentException if the name is a class file in
+     *         the top-level directory (and it's not module-info.class)
+     */
+    private Optional<String> toPackageName(Path file) {
+        assert file.getRoot() == null;
+
+        Path parent = file.getParent();
+        if (parent == null) {
+            String name = file.toString();
+            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
+                throw new IllegalArgumentException(name
+                        + " found in in top-level directory"
+                        + " (unnamed package not allowed in module)");
+            }
+            return Optional.empty();
+        }
+
+        String pn = parent.toString().replace(File.separatorChar, '.');
+        if (Checks.isJavaIdentifier(pn)) {
+            return Optional.of(pn);
+        } else {
+            // not a valid package name
+            return Optional.empty();
+        }
+    }
+
+    private static final PerfCounter scanTime
+        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
+    private static final PerfCounter moduleCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,169 @@
+/*
+ * 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.module;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+/**
+ * A ModuleReference implementation that supports referencing a module that
+ * is patched and/or can be tied to other modules by means of hashes.
+ */
+
+public class ModuleReferenceImpl extends ModuleReference {
+
+    private final Supplier<ModuleReader> readerSupplier;
+
+    // non-null if the module is patched
+    private final ModulePatcher patcher;
+
+    // the hashes of other modules recorded in this module
+    private final ModuleHashes recordedHashes;
+
+    // the function that computes the hash of this module
+    private final ModuleHashes.HashSupplier hasher;
+
+    // ModuleResolution flags
+    private final ModuleResolution moduleResolution;
+
+    // cached hash of this module to avoid needing to compute it many times
+    private byte[] cachedHash;
+
+    /**
+     * Constructs a new instance of this class.
+     */
+    ModuleReferenceImpl(ModuleDescriptor descriptor,
+                        URI location,
+                        Supplier<ModuleReader> readerSupplier,
+                        ModulePatcher patcher,
+                        ModuleHashes recordedHashes,
+                        ModuleHashes.HashSupplier hasher,
+                        ModuleResolution moduleResolution)
+    {
+        super(descriptor, Objects.requireNonNull(location));
+        this.readerSupplier = readerSupplier;
+        this.patcher = patcher;
+        this.recordedHashes = recordedHashes;
+        this.hasher = hasher;
+        this.moduleResolution = moduleResolution;
+    }
+
+    @Override
+    public ModuleReader open() throws IOException {
+        try {
+            return readerSupplier.get();
+        } catch (UncheckedIOException e) {
+            throw e.getCause();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this module has been patched via --patch-module.
+     */
+    public boolean isPatched() {
+        return (patcher != null);
+    }
+
+    /**
+     * Returns the hashes recorded in this module or {@code null} if there
+     * are no hashes recorded.
+     */
+    public ModuleHashes recordedHashes() {
+        return recordedHashes;
+    }
+
+    /**
+     * Returns the supplier that computes the hash of this module.
+     */
+    ModuleHashes.HashSupplier hasher() {
+        return hasher;
+    }
+
+    /**
+     * Returns the ModuleResolution flags.
+     */
+    public ModuleResolution moduleResolution() {
+        return moduleResolution;
+    }
+
+    /**
+     * Computes the hash of this module. Returns {@code null} if the hash
+     * cannot be computed.
+     *
+     * @throws java.io.UncheckedIOException if an I/O error occurs
+     */
+    public byte[] computeHash(String algorithm) {
+        byte[] result = cachedHash;
+        if (result != null)
+            return result;
+        if (hasher == null)
+            return null;
+        cachedHash = result = hasher.generate(algorithm);
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        int hc = hash;
+        if (hc == 0) {
+            hc = descriptor().hashCode();
+            hc = 43 * hc + Objects.hashCode(location());
+            hc = 43 * hc + Objects.hashCode(patcher);
+            if (hc == 0)
+                hc = -1;
+            hash = hc;
+        }
+        return hc;
+    }
+
+    private int hash;
+
+    @Override
+    public boolean equals(Object ob) {
+        if (!(ob instanceof ModuleReferenceImpl))
+            return false;
+        ModuleReferenceImpl that = (ModuleReferenceImpl)ob;
+
+        // assume module content, recorded hashes, etc. are the same
+        // when the modules have equal module descriptors, are at the
+        // same location, and are patched by the same patcher.
+        return Objects.equals(this.descriptor(), that.descriptor())
+                && Objects.equals(this.location(), that.location())
+                && Objects.equals(this.patcher, that.patcher);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,448 @@
+/*
+ * 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 jdk.internal.module;
+
+import java.io.File;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Supplier;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipFile;
+
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleHashes.HashSupplier;
+import jdk.internal.util.jar.VersionedStream;
+import sun.net.www.ParseUtil;
+
+
+/**
+ * A factory for creating ModuleReference implementations where the modules are
+ * packaged as modular JAR file, JMOD files or where the modules are exploded
+ * on the file system.
+ */
+
+class ModuleReferences {
+
+    private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
+
+    private ModuleReferences() { }
+
+    /**
+     * Creates a ModuleReference to a module or to patched module when
+     * creating modules for the boot Layer and --patch-module is specified.
+     */
+    private static ModuleReference newModule(ModuleInfo.Attributes attrs,
+                                             URI uri,
+                                             Supplier<ModuleReader> supplier,
+                                             HashSupplier hasher) {
+
+        ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(),
+                                                       uri,
+                                                       supplier,
+                                                       null,
+                                                       attrs.recordedHashes(),
+                                                       hasher,
+                                                       attrs.moduleResolution());
+        if (JLA.getBootLayer() == null)
+            mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
+
+        return mref;
+    }
+
+    /**
+     * Creates a ModuleReference to a module packaged as a modular JAR.
+     */
+    static ModuleReference newJarModule(ModuleInfo.Attributes attrs, Path file) {
+        URI uri = file.toUri();
+        Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
+        return newModule(attrs, uri, supplier, hasher);
+    }
+
+    /**
+     * Creates a ModuleReference to a module packaged as a JMOD.
+     */
+    static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
+        URI uri = file.toUri();
+        Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
+        return newModule(attrs, uri, supplier, hasher);
+    }
+
+    /**
+     * Creates a ModuleReference to an exploded module.
+     */
+    static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, Path dir) {
+        Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
+        return newModule(attrs, dir.toUri(), supplier, null);
+    }
+
+
+    /**
+     * A base module reader that encapsulates machinery required to close the
+     * module reader safely.
+     */
+    static abstract class SafeCloseModuleReader implements ModuleReader {
+
+        // RW lock to support safe close
+        private final ReadWriteLock lock = new ReentrantReadWriteLock();
+        private final Lock readLock = lock.readLock();
+        private final Lock writeLock = lock.writeLock();
+        private boolean closed;
+
+        SafeCloseModuleReader() { }
+
+        /**
+         * Returns a URL to  resource. This method is invoked by the find
+         * method to do the actual work of finding the resource.
+         */
+        abstract Optional<URI> implFind(String name) throws IOException;
+
+        /**
+         * Returns an input stream for reading a resource. This method is
+         * invoked by the open method to do the actual work of opening
+         * an input stream to the resource.
+         */
+        abstract Optional<InputStream> implOpen(String name) throws IOException;
+
+        /**
+         * Returns a stream of the names of resources in the module. This
+         * method is invoked by the list method to do the actual work of
+         * creating the stream.
+         */
+        abstract Stream<String> implList() throws IOException;
+
+        /**
+         * Closes the module reader. This method is invoked by close to do the
+         * actual work of closing the module reader.
+         */
+        abstract void implClose() throws IOException;
+
+        @Override
+        public final Optional<URI> find(String name) throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implFind(name);
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
+            }
+        }
+
+
+        @Override
+        public final Optional<InputStream> open(String name) throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implOpen(name);
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
+            }
+        }
+
+        @Override
+        public final Stream<String> list() throws IOException {
+            readLock.lock();
+            try {
+                if (!closed) {
+                    return implList();
+                } else {
+                    throw new IOException("ModuleReader is closed");
+                }
+            } finally {
+                readLock.unlock();
+            }
+        }
+
+        @Override
+        public final void close() throws IOException {
+            writeLock.lock();
+            try {
+                if (!closed) {
+                    closed = true;
+                    implClose();
+                }
+            } finally {
+                writeLock.unlock();
+            }
+        }
+    }
+
+
+    /**
+     * A ModuleReader for a modular JAR file.
+     */
+    static class JarModuleReader extends SafeCloseModuleReader {
+        private final JarFile jf;
+        private final URI uri;
+
+        static JarFile newJarFile(Path path) {
+            try {
+                return new JarFile(path.toFile(),
+                                   true,               // verify
+                                   ZipFile.OPEN_READ,
+                                   JarFile.runtimeVersion());
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+
+        JarModuleReader(Path path, URI uri) {
+            this.jf = newJarFile(path);
+            this.uri = uri;
+        }
+
+        private JarEntry getEntry(String name) {
+            return jf.getJarEntry(Objects.requireNonNull(name));
+        }
+
+        @Override
+        Optional<URI> implFind(String name) throws IOException {
+            JarEntry je = getEntry(name);
+            if (je != null) {
+                if (jf.isMultiRelease())
+                    name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
+                String encodedPath = ParseUtil.encodePath(name, false);
+                String uris = "jar:" + uri + "!/" + encodedPath;
+                return Optional.of(URI.create(uris));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Optional<InputStream> implOpen(String name) throws IOException {
+            JarEntry je = getEntry(name);
+            if (je != null) {
+                return Optional.of(jf.getInputStream(je));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Stream<String> implList() throws IOException {
+            // take snapshot to avoid async close
+            List<String> names = VersionedStream.stream(jf)
+                    .filter(e -> !e.isDirectory())
+                    .map(JarEntry::getName)
+                    .collect(Collectors.toList());
+            return names.stream();
+        }
+
+        @Override
+        void implClose() throws IOException {
+            jf.close();
+        }
+    }
+
+
+    /**
+     * A ModuleReader for a JMOD file.
+     */
+    static class JModModuleReader extends SafeCloseModuleReader {
+        private final JmodFile jf;
+        private final URI uri;
+
+        static JmodFile newJmodFile(Path path) {
+            try {
+                return new JmodFile(path);
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
+
+        JModModuleReader(Path path, URI uri) {
+            this.jf = newJmodFile(path);
+            this.uri = uri;
+        }
+
+        private JmodFile.Entry getEntry(String name) {
+            Objects.requireNonNull(name);
+            return jf.getEntry(JmodFile.Section.CLASSES, name);
+        }
+
+        @Override
+        Optional<URI> implFind(String name) {
+            JmodFile.Entry je = getEntry(name);
+            if (je != null) {
+                String encodedPath = ParseUtil.encodePath(name, false);
+                String uris = "jmod:" + uri + "!/" + encodedPath;
+                return Optional.of(URI.create(uris));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Optional<InputStream> implOpen(String name) throws IOException {
+            JmodFile.Entry je = getEntry(name);
+            if (je != null) {
+                return Optional.of(jf.getInputStream(je));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        Stream<String> implList() throws IOException {
+            // take snapshot to avoid async close
+            List<String> names = jf.stream()
+                    .filter(e -> e.section() == JmodFile.Section.CLASSES)
+                    .map(JmodFile.Entry::name)
+                    .collect(Collectors.toList());
+            return names.stream();
+        }
+
+        @Override
+        void implClose() throws IOException {
+            jf.close();
+        }
+    }
+
+
+    /**
+     * A ModuleReader for an exploded module.
+     */
+    static class ExplodedModuleReader implements ModuleReader {
+        private final Path dir;
+        private volatile boolean closed;
+
+        ExplodedModuleReader(Path dir) {
+            this.dir = dir;
+
+            // when running with a security manager then check that the caller
+            // has access to the directory.
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                boolean unused = Files.isDirectory(dir);
+            }
+        }
+
+        /**
+         * Returns a Path to access to the given resource.
+         */
+        private Path toPath(String name) {
+            Path path = Paths.get(name.replace('/', File.separatorChar));
+            if (path.getRoot() == null) {
+                return dir.resolve(path);
+            } else {
+                // drop the root component so that the resource is
+                // located relative to the module directory
+                int n = path.getNameCount();
+                return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
+            }
+        }
+
+        /**
+         * Throws IOException if the module reader is closed;
+         */
+        private void ensureOpen() throws IOException {
+            if (closed) throw new IOException("ModuleReader is closed");
+        }
+
+        @Override
+        public Optional<URI> find(String name) throws IOException {
+            ensureOpen();
+            Path path = toPath(name);
+            if (path != null && Files.isRegularFile(path)) {
+                try {
+                    return Optional.of(path.toUri());
+                } catch (IOError e) {
+                    throw (IOException) e.getCause();
+                }
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<InputStream> open(String name) throws IOException {
+            ensureOpen();
+            Path path = toPath(name);
+            if (path != null && Files.isRegularFile(path)) {
+                return Optional.of(Files.newInputStream(path));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<ByteBuffer> read(String name) throws IOException {
+            ensureOpen();
+            Path path = toPath(name);
+            if (path != null && Files.isRegularFile(path)) {
+                return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Stream<String> list() throws IOException {
+            ensureOpen();
+            // sym links not followed
+            return Files.find(dir, Integer.MAX_VALUE,
+                              (path, attrs) -> attrs.isRegularFile())
+                    .map(f -> dir.relativize(f)
+                                 .toString()
+                                 .replace(File.separatorChar, '/'));
+        }
+
+        @Override
+        public void close() {
+            closed = true;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleResolution.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,114 @@
+/*
+ * 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.module;
+
+import java.lang.module.ModuleReference;
+import static jdk.internal.module.ClassFileConstants.*;
+
+/**
+ * Represents the Module Resolution flags.
+ */
+public final class ModuleResolution {
+
+    final int value;
+
+    ModuleResolution(int value) {
+        this.value = value;
+    }
+
+    public static ModuleResolution empty() {
+        return new ModuleResolution(0);
+    }
+
+    public boolean doNotResolveByDefault() {
+        return (value & DO_NOT_RESOLVE_BY_DEFAULT) != 0;
+    }
+
+    public boolean hasDeprecatedWarning() {
+        return (value & WARN_DEPRECATED) != 0;
+    }
+
+    public boolean hasDeprecatedForRemovalWarning() {
+        return (value & WARN_DEPRECATED_FOR_REMOVAL) != 0;
+    }
+
+    public boolean hasIncubatingWarning() {
+        return (value & WARN_INCUBATING) != 0;
+    }
+
+    public ModuleResolution withDoNotResolveByDefault() {
+        return new ModuleResolution(value | DO_NOT_RESOLVE_BY_DEFAULT);
+    }
+
+    public ModuleResolution withDeprecated() {
+        if ((value & (WARN_DEPRECATED_FOR_REMOVAL | WARN_INCUBATING)) != 0)
+            throw new InternalError("cannot add deprecated to " + value);
+        return new ModuleResolution(value | WARN_DEPRECATED);
+    }
+
+    public ModuleResolution withDeprecatedForRemoval() {
+        if ((value & (WARN_DEPRECATED | WARN_INCUBATING)) != 0)
+            throw new InternalError("cannot add deprecated for removal to " + value);
+        return new ModuleResolution(value | WARN_DEPRECATED_FOR_REMOVAL);
+    }
+    public ModuleResolution withIncubating() {
+        if ((value & (WARN_DEPRECATED | WARN_DEPRECATED_FOR_REMOVAL)) != 0)
+            throw new InternalError("cannot add incubating to " + value);
+        return new ModuleResolution(value | WARN_INCUBATING);
+    }
+
+    public int value() {
+        return value;
+    }
+
+    public static boolean doNotResolveByDefault(ModuleReference mref) {
+        // get the DO_NOT_RESOLVE_BY_DEFAULT flag, if any
+        if (!(mref instanceof ModuleReferenceImpl))
+            return false;
+
+        ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
+        if (mres != null)
+            return mres.doNotResolveByDefault();
+
+        return false;
+    }
+
+    public static boolean hasIncubatingWarning(ModuleReference mref) {
+        if (!(mref instanceof ModuleReferenceImpl))
+            return false;
+
+        ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
+        if (mres != null)
+            return mres.hasIncubatingWarning();
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + "[value=" + value + "]";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,443 @@
+/*
+ * 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 jdk.internal.module;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import jdk.internal.jimage.ImageLocation;
+import jdk.internal.jimage.ImageReader;
+import jdk.internal.jimage.ImageReaderFactory;
+import jdk.internal.misc.JavaNetUriAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleHashes.HashSupplier;
+import jdk.internal.perf.PerfCounter;
+
+/**
+ * A {@code ModuleFinder} that finds modules that are linked into the
+ * run-time image.
+ *
+ * The modules linked into the run-time image are assumed to have the
+ * Packages attribute.
+ */
+
+public class SystemModuleFinder implements ModuleFinder {
+
+    private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
+
+    private static final PerfCounter initTime
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
+    private static final PerfCounter moduleCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
+    private static final PerfCounter packageCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
+    private static final PerfCounter exportsCount
+        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
+    // ImageReader used to access all modules in the image
+    private static final ImageReader imageReader;
+
+    // singleton finder to find modules in the run-time images
+    private static final SystemModuleFinder INSTANCE;
+
+    public static SystemModuleFinder getInstance() {
+        return INSTANCE;
+    }
+
+    /**
+     * For now, the module references are created eagerly on the assumption
+     * that service binding will require all modules to be located.
+     */
+    static {
+        long t0 = System.nanoTime();
+        imageReader = ImageReaderFactory.getImageReader();
+
+        INSTANCE = new SystemModuleFinder();
+
+        initTime.addElapsedTimeFrom(t0);
+    }
+
+    private static boolean isFastPathSupported() {
+       return SystemModules.MODULE_NAMES.length > 0;
+    }
+
+    private static String[] moduleNames() {
+        if (isFastPathSupported())
+            // module names recorded at link time
+            return SystemModules.MODULE_NAMES;
+
+        // this happens when java.base is patched with java.base
+        // from an exploded image
+        return imageReader.getModuleNames();
+    }
+
+    // the set of modules in the run-time image
+    private final Set<ModuleReference> modules;
+
+    // maps module name to module reference
+    private final Map<String, ModuleReference> nameToModule;
+
+    // module name to hashes
+    private final Map<String, byte[]> hashes;
+
+    private SystemModuleFinder() {
+        String[] names = moduleNames();
+        int n = names.length;
+        moduleCount.add(n);
+
+        // fastpath is enabled by default.
+        // It can be disabled for troubleshooting purpose.
+        boolean disabled =
+            System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
+
+        ModuleDescriptor[] descriptors;
+        ModuleHashes[] recordedHashes;
+        ModuleResolution[] moduleResolutions;
+
+        // fast loading of ModuleDescriptor of system modules
+        if (isFastPathSupported() && !disabled) {
+            descriptors = SystemModules.descriptors();
+            recordedHashes = SystemModules.hashes();
+            moduleResolutions = SystemModules.moduleResolutions();
+        } else {
+            // if fast loading of ModuleDescriptors is disabled
+            // fallback to read module-info.class
+            descriptors = new ModuleDescriptor[n];
+            recordedHashes = new ModuleHashes[n];
+            moduleResolutions = new ModuleResolution[n];
+            for (int i = 0; i < names.length; i++) {
+                String mn = names[i];
+                ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
+                ModuleInfo.Attributes attrs =
+                    ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
+                descriptors[i] = attrs.descriptor();
+                recordedHashes[i] = attrs.recordedHashes();
+                moduleResolutions[i] = attrs.moduleResolution();
+            }
+        }
+
+        Map<String, byte[]> hashes = null;
+        boolean secondSeen = false;
+        // record the hashes to build HashSupplier
+        for (ModuleHashes mh : recordedHashes) {
+            if (mh != null) {
+                // if only one module contain ModuleHashes, use it
+                if (hashes == null) {
+                    hashes = mh.hashes();
+                } else {
+                    if (!secondSeen) {
+                        hashes = new HashMap<>(hashes);
+                        secondSeen = true;
+                    }
+                    hashes.putAll(mh.hashes());
+                }
+            }
+        }
+        this.hashes = (hashes == null) ? Map.of() : hashes;
+
+        ModuleReference[] mods = new ModuleReference[n];
+
+        @SuppressWarnings(value = {"rawtypes", "unchecked"})
+        Entry<String, ModuleReference>[] map
+            = (Entry<String, ModuleReference>[])new Entry[n];
+
+        for (int i = 0; i < n; i++) {
+            ModuleDescriptor md = descriptors[i];
+
+            // create the ModuleReference
+            ModuleReference mref = toModuleReference(md,
+                                                     recordedHashes[i],
+                                                     hashSupplier(names[i]),
+                                                     moduleResolutions[i]);
+            mods[i] = mref;
+            map[i] = Map.entry(names[i], mref);
+
+            // counters
+            packageCount.add(md.packages().size());
+            exportsCount.add(md.exports().size());
+        }
+
+        modules = Set.of(mods);
+        nameToModule = Map.ofEntries(map);
+    }
+
+    @Override
+    public Optional<ModuleReference> find(String name) {
+        Objects.requireNonNull(name);
+        return Optional.ofNullable(nameToModule.get(name));
+    }
+
+    @Override
+    public Set<ModuleReference> findAll() {
+        return modules;
+    }
+
+    private ModuleReference toModuleReference(ModuleDescriptor md,
+                                              ModuleHashes recordedHashes,
+                                              HashSupplier hasher,
+                                              ModuleResolution mres) {
+        String mn = md.name();
+        URI uri = JNUA.create("jrt", "/".concat(mn));
+
+        Supplier<ModuleReader> readerSupplier = new Supplier<>() {
+            @Override
+            public ModuleReader get() {
+                return new ImageModuleReader(mn, uri);
+            }
+        };
+
+        ModuleReference mref =
+            new ModuleReferenceImpl(md, uri, readerSupplier, null,
+                                    recordedHashes, hasher, mres);
+
+        // may need a reference to a patched module if --patch-module specified
+        mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
+
+        return mref;
+    }
+
+    private HashSupplier hashSupplier(String name) {
+        if (!hashes.containsKey(name))
+            return null;
+
+        return new HashSupplier() {
+            @Override
+            public byte[] generate(String algorithm) {
+                return hashes.get(name);
+            }
+        };
+    }
+
+    /**
+     * A ModuleReader for reading resources from a module linked into the
+     * run-time image.
+     */
+    static class ImageModuleReader implements ModuleReader {
+        private final String module;
+        private volatile boolean closed;
+
+        /**
+         * If there is a security manager set then check permission to
+         * connect to the run-time image.
+         */
+        private static void checkPermissionToConnect(URI uri) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                try {
+                    URLConnection uc = uri.toURL().openConnection();
+                    sm.checkPermission(uc.getPermission());
+                } catch (IOException ioe) {
+                    throw new UncheckedIOException(ioe);
+                }
+            }
+        }
+
+        ImageModuleReader(String module, URI uri) {
+            checkPermissionToConnect(uri);
+            this.module = module;
+        }
+
+        /**
+         * Returns the ImageLocation for the given resource, {@code null}
+         * if not found.
+         */
+        private ImageLocation findImageLocation(String name) throws IOException {
+            Objects.requireNonNull(name);
+            if (closed)
+                throw new IOException("ModuleReader is closed");
+            if (imageReader != null) {
+                return imageReader.findLocation(module, name);
+            } else {
+                // not an images build
+                return null;
+            }
+        }
+
+        @Override
+        public Optional<URI> find(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                URI u = URI.create("jrt:/" + module + "/" + name);
+                return Optional.of(u);
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<InputStream> open(String name) throws IOException {
+            return read(name).map(this::toInputStream);
+        }
+
+        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
+            try {
+                int rem = bb.remaining();
+                byte[] bytes = new byte[rem];
+                bb.get(bytes);
+                return new ByteArrayInputStream(bytes);
+            } finally {
+                release(bb);
+            }
+        }
+
+        @Override
+        public Optional<ByteBuffer> read(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                return Optional.of(imageReader.getResourceBuffer(location));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public void release(ByteBuffer bb) {
+            Objects.requireNonNull(bb);
+            ImageReader.releaseByteBuffer(bb);
+        }
+
+        @Override
+        public Stream<String> list() throws IOException {
+            if (closed)
+                throw new IOException("ModuleReader is closed");
+
+            Spliterator<String> s = new ModuleContentSpliterator(module);
+            return StreamSupport.stream(s, false);
+        }
+
+        @Override
+        public void close() {
+            // nothing else to do
+            closed = true;
+        }
+    }
+
+    /**
+     * A Spliterator for traversing the resources of a module linked into the
+     * run-time image.
+     */
+    static class ModuleContentSpliterator implements Spliterator<String> {
+        final String moduleRoot;
+        final Deque<ImageReader.Node> stack;
+        Iterator<ImageReader.Node> iterator;
+
+        ModuleContentSpliterator(String module) throws IOException {
+            moduleRoot = "/modules/" + module;
+            stack = new ArrayDeque<>();
+
+            // push the root node to the stack to get started
+            ImageReader.Node dir = imageReader.findNode(moduleRoot);
+            if (dir == null || !dir.isDirectory())
+                throw new IOException(moduleRoot + " not a directory");
+            stack.push(dir);
+            iterator = Collections.emptyIterator();
+        }
+
+        /**
+         * Returns the name of the next non-directory node or {@code null} if
+         * there are no remaining nodes to visit.
+         */
+        private String next() throws IOException {
+            for (;;) {
+                while (iterator.hasNext()) {
+                    ImageReader.Node node = iterator.next();
+                    String name = node.getName();
+                    if (node.isDirectory()) {
+                        // build node
+                        ImageReader.Node dir = imageReader.findNode(name);
+                        assert dir.isDirectory();
+                        stack.push(dir);
+                    } else {
+                        // strip /modules/$MODULE/ prefix
+                        return name.substring(moduleRoot.length() + 1);
+                    }
+                }
+
+                if (stack.isEmpty()) {
+                    return null;
+                } else {
+                    ImageReader.Node dir = stack.poll();
+                    assert dir.isDirectory();
+                    iterator = dir.getChildren().iterator();
+                }
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super String> action) {
+            String next;
+            try {
+                next = next();
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+            if (next != null) {
+                action.accept(next);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public Spliterator<String> trySplit() {
+            return null;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
+        }
+
+        @Override
+        public long estimateSize() {
+            return Long.MAX_VALUE;
+        }
+    }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Mon Dec 19 16:05:38 2016 +0000
@@ -29,14 +29,14 @@
 
 /*
  * SystemModules class will be generated at link time to create
- * ModuleDescriptor for the installed modules directly to improve
+ * ModuleDescriptor for the system modules directly to improve
  * the module descriptor reconstitution time.
  *
  * This will skip parsing of module-info.class file and validating
  * names such as module name, package name, service and provider type names.
  * It also avoids taking a defensive copy of any collection.
  *
- * @see jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin
+ * @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
  */
 public final class SystemModules {
     /**
@@ -49,11 +49,6 @@
     public static final String[] MODULE_NAMES = new String[0];
 
     /**
-     * Hash of system modules.
-     */
-    public static byte[][] MODULES_TO_HASH = new byte[0][];
-
-    /**
      * Number of packages in the boot layer from the installed modules.
      *
      * Don't make it final to avoid inlining during compile time as
@@ -66,8 +61,24 @@
      *
      * When running an exploded image it returns an empty array.
      */
-    public static ModuleDescriptor[] modules() {
-        throw new InternalError("should not reach here");
+    public static ModuleDescriptor[] descriptors() {
+        throw new InternalError("expected to be overridden at link time");
     }
 
+    /**
+     * Returns a non-empty array of ModuleHashes recorded in each module
+     * in the run-time image.
+     *
+     * When running an exploded image it returns an empty array.
+     */
+    public static ModuleHashes[] hashes() {
+        throw new InternalError("expected to be overridden at link time");
+    }
+
+    /**
+     * Returns a non-empty array of ModuleResolutions in the run-time image.
+     */
+    public static ModuleResolution[] moduleResolutions() {
+        throw new InternalError("expected to be overridden at link time");
+    }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java	Mon Dec 19 16:05:38 2016 +0000
@@ -2491,6 +2491,40 @@
     }
 
     /**
+     * Reads a CONSTANT_Module_info item in {@code b}. This method is intended
+     * for {@link Attribute} sub classes, and is normally not needed by class
+     * generators or adapters.</i>
+     *
+     * @param  index
+     *         the start index of an unsigned short value in {@link #b b},
+     *         whose value is the index of a module constant pool item.
+     * @param  buf
+     *         buffer to be used to read the item. This buffer must be
+     *         sufficiently large. It is not automatically resized.
+     * @return the String corresponding to the specified module item.
+     */
+    public String readModule(int index, char[] buf) {
+        return readUTF8(items[readUnsignedShort(index)], buf);
+    }
+
+    /**
+     * Reads a CONSTANT_Pakcage_info item in {@code b}.  This method is
+     * intended for {@link Attribute} sub slasses, and is normally not needed
+     * by class generators or adapters.</i>
+     *
+     * @param  index
+     *         the start index of an unsigned short value in {@link #b b},
+     *         whose value is the index of a package constant pool item.
+     * @param  buf
+     *         buffer to be used to read the item. This buffer must be
+     *         sufficiently large. It is not automatically resized.
+     * @return the String corresponding to the specified package item.
+     */
+    public String readPackage(int index, char[] buf) {
+        return readUTF8(items[readUnsignedShort(index)], buf);
+    }
+
+    /**
      * Reads a numeric or string constant pool item in {@link #b b}. <i>This
      * method is intended for {@link Attribute} sub classes, and is normally not
      * needed by class generators or adapters.</i>
@@ -2516,6 +2550,8 @@
         case ClassWriter.DOUBLE:
             return Double.longBitsToDouble(readLong(index));
         case ClassWriter.CLASS:
+        case ClassWriter.MODULE:
+        case ClassWriter.PACKAGE:
             return Type.getObjectType(readUTF8(index, buf));
         case ClassWriter.STR:
             return readUTF8(index, buf);
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java	Mon Dec 19 16:05:38 2016 +0000
@@ -272,6 +272,16 @@
     static final int INDY = 18;
 
     /**
+     * The type of CONSTANT_Module constant pool items.
+     */
+    static final int MODULE = 19;
+
+    /**
+     * The type of CONSTANT_Package constant pool items.
+     */
+    static final int PACKAGE = 20;
+
+    /**
      * The base value for all CONSTANT_MethodHandle constant pool items.
      * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9
      * different items.
@@ -1161,6 +1171,50 @@
     }
 
     /**
+     * Adds a module name to the constant pool.
+     *
+     * Does nothing if the constant pool already contains a similar item.
+     * <i>This method is intended for {@link Attribute} sub classes, and is
+     * normally not needed by class generators or adapters.</i>
+     *
+     * @param  value
+     *         the module name
+     * @return the index of a new or already existing module reference item.
+     */
+    public int newModule(String value) {
+        key2.set(MODULE, value, null, null);
+        Item result = get(key2);
+        if (result == null) {
+            pool.put12(MODULE, newUTF8(value));
+            result = new Item(index++, key2);
+            put(result);
+        }
+        return result.index;
+    }
+
+    /**
+     * Adds a package name to the constant pool.
+     *
+     * Does nothing if the constant pool already contains a similar item.
+     * <i>This method is intended for {@link Attribute} sub classes, and is
+     * normally not needed by class generators or adapters.</i>
+     *
+     * @param  value
+     *         the internal name of the package.
+     * @return the index of a new or already existing package reference item.
+     */
+    public int newPackage(String value) {
+        key2.set(PACKAGE, value, null, null);
+        Item result = get(key2);
+        if (result == null) {
+            pool.put12(PACKAGE, newUTF8(value));
+            result = new Item(index++, key2);
+            put(result);
+        }
+        return result.index;
+    }
+
+    /**
      * Adds a method type reference to the constant pool of the class being
      * build. Does nothing if the constant pool already contains a similar item.
      * <i>This method is intended for {@link Attribute} sub classes, and is
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Item.java	Mon Dec 19 16:05:38 2016 +0000
@@ -239,6 +239,8 @@
         this.strVal3 = strVal3;
         switch (type) {
         case ClassWriter.CLASS:
+        case ClassWriter.MODULE:
+        case ClassWriter.PACKAGE:
             this.intVal = 0;     // intVal of a class must be zero, see visitInnerClass
         case ClassWriter.UTF8:
         case ClassWriter.STR:
@@ -311,6 +313,8 @@
         case ClassWriter.UTF8:
         case ClassWriter.STR:
         case ClassWriter.CLASS:
+        case ClassWriter.MODULE:
+        case ClassWriter.PACKAGE:
         case ClassWriter.MTYPE:
         case ClassWriter.TYPE_NORMAL:
             return i.strVal1.equals(strVal1);
--- a/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/ref/Cleaner.java	Mon Dec 19 16:05:38 2016 +0000
@@ -58,7 +58,6 @@
 
 public class Cleaner
     extends PhantomReference<Object>
-    implements Runnable
 {
 
     // Dummy reference queue, needed because the PhantomReference constructor
@@ -153,12 +152,4 @@
                     }});
         }
     }
-
-    @Override public void run() {
-        SecurityManager security = System.getSecurityManager();
-        if (security != null)
-            security.checkPackageAccess("jdk.internal.ref");
-        this.clean();
-    }
-
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Mon Dec 19 16:05:38 2016 +0000
@@ -31,6 +31,7 @@
 import java.util.Map;
 import java.util.Objects;
 import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
 import sun.security.action.GetPropertyAction;
 
@@ -218,8 +219,16 @@
         if (c.isPrimitive())
             return true;
 
-        // check that memberModule exports the package to currentModule
-        return memberModule.isExported(c.getPackageName(), currentModule);
+        String pkg = c.getPackageName();
+        boolean allowed = memberModule.isExported(pkg, currentModule);
+        if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) {
+            if (!SharedSecrets.getJavaLangReflectModuleAccess()
+                    .isStaticallyExported(memberModule, pkg, currentModule)) {
+                String msg = currentModule + " allowed access to member of " + memberClass;
+                new Exception(msg).printStackTrace(System.err);
+            }
+        }
+        return allowed;
     }
 
     /**
@@ -348,23 +357,41 @@
     }
 
 
-    // true to print a stack trace when IAE is thrown
+    // true to print a stack trace when access fails
     private static volatile boolean printStackWhenAccessFails;
 
-    // true if printStackWhenAccessFails has been initialized
-    private static volatile boolean printStackWhenAccessFailsSet;
+    // true to print a stack trace when access succeeds
+    private static volatile boolean printStackWhenAccessSucceeds;
 
-    private static void printStackTraceIfNeeded(Throwable e) {
-        if (!printStackWhenAccessFailsSet && VM.initLevel() >= 1) {
+    // true if printStack* values are initialized
+    private static volatile boolean printStackPropertiesSet;
+
+    private static void ensurePrintStackPropertiesSet() {
+        if (!printStackPropertiesSet && VM.initLevel() >= 1) {
             String s = GetPropertyAction.privilegedGetProperty(
                     "sun.reflect.debugModuleAccessChecks");
-            printStackWhenAccessFails =
-                    (s != null && !s.equalsIgnoreCase("false"));
-            printStackWhenAccessFailsSet = true;
+            if (s != null) {
+                printStackWhenAccessFails = !s.equalsIgnoreCase("false");
+                printStackWhenAccessSucceeds = s.equalsIgnoreCase("access");
+            }
+            printStackPropertiesSet = true;
         }
-        if (printStackWhenAccessFails) {
-            e.printStackTrace();
-        }
+    }
+
+    public static void enableStackTraces() {
+        printStackWhenAccessFails = true;
+        printStackWhenAccessSucceeds = true;
+        printStackPropertiesSet = true;
+    }
+
+    public static boolean printStackTraceWhenAccessFails() {
+        ensurePrintStackPropertiesSet();
+        return printStackWhenAccessFails;
+    }
+
+    public static boolean printStackTraceWhenAccessSucceeds() {
+        ensurePrintStackPropertiesSet();
+        return printStackWhenAccessSucceeds;
     }
 
     /**
@@ -416,17 +443,10 @@
         throws IllegalAccessException
     {
         IllegalAccessException e = new IllegalAccessException(msg);
-        printStackTraceIfNeeded(e);
+        ensurePrintStackPropertiesSet();
+        if (printStackWhenAccessFails) {
+            e.printStackTrace(System.err);
+        }
         throw e;
     }
-
-    /**
-     * Throws InaccessibleObjectException with the given exception message.
-     */
-    public static void throwInaccessibleObjectException(String msg) {
-        InaccessibleObjectException e = new InaccessibleObjectException(msg);
-        printStackTraceIfNeeded(e);
-        throw e;
-    }
-
 }
--- a/jdk/src/java.base/share/classes/module-info.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/module-info.java	Mon Dec 19 16:05:38 2016 +0000
@@ -180,7 +180,8 @@
         java.management,
         jdk.jvmstat;
     exports jdk.internal.ref to
-        java.desktop;
+        java.desktop,
+        jdk.unsupported;
     exports jdk.internal.reflect to
         java.corba,
         java.logging,
@@ -219,7 +220,8 @@
     exports sun.nio.ch to
         java.management,
         jdk.crypto.token,
-        jdk.sctp;
+        jdk.sctp,
+        jdk.unsupported;
     exports sun.nio.cs to
         java.desktop,
         jdk.charsets;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Mon Dec 19 16:05:38 2016 +0000
@@ -36,6 +36,7 @@
 import java.security.AccessControlContext;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedActionException;
+import java.util.function.BiFunction;
 
 import javax.crypto.*;
 import javax.crypto.spec.*;
@@ -122,6 +123,14 @@
     // Negotiated ALPN value
     String applicationProtocol = null;
 
+    // Application protocol callback function (for SSLEngine)
+    BiFunction<SSLEngine,List<String>,String>
+        appProtocolSelectorSSLEngine = null;
+
+    // Application protocol callback function (for SSLSocket)
+    BiFunction<SSLSocket,List<String>,String>
+        appProtocolSelectorSSLSocket = null;
+
     // The maximum expected network packet size for SSL/TLS/DTLS records.
     int                         maximumPacketSize = 0;
 
@@ -501,6 +510,22 @@
     }
 
     /**
+     * Sets the Application Protocol selector function for SSLEngine.
+     */
+    void setApplicationProtocolSelectorSSLEngine(
+        BiFunction<SSLEngine,List<String>,String> selector) {
+        this.appProtocolSelectorSSLEngine = selector;
+    }
+
+    /**
+     * Sets the Application Protocol selector function for SSLSocket.
+     */
+    void setApplicationProtocolSelectorSSLSocket(
+        BiFunction<SSLSocket,List<String>,String> selector) {
+        this.appProtocolSelectorSSLSocket = selector;
+    }
+
+    /**
      * Sets the cipher suites preference.
      */
     void setUseCipherSuitesOrder(boolean on) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java	Mon Dec 19 16:05:38 2016 +0000
@@ -27,8 +27,9 @@
 
 import java.io.*;
 import java.nio.*;
+import java.security.*;
 import java.util.*;
-import java.security.*;
+import java.util.function.BiFunction;
 
 import javax.crypto.BadPaddingException;
 
@@ -206,6 +207,10 @@
     // The value under negotiation will be obtained from handshaker.
     String applicationProtocol = null;
 
+    // Callback function that selects the application protocol value during
+    // the SSL/TLS handshake.
+    BiFunction<SSLEngine, List<String>, String> applicationProtocolSelector;
+
     // Have we been told whether we're client or server?
     private boolean                     serverModeSet = false;
     private boolean                     roleIsServer;
@@ -442,6 +447,8 @@
         handshaker.setEnabledCipherSuites(enabledCipherSuites);
         handshaker.setEnableSessionCreation(enableSessionCreation);
         handshaker.setApplicationProtocols(applicationProtocols);
+        handshaker.setApplicationProtocolSelectorSSLEngine(
+            applicationProtocolSelector);
 
         outputRecord.initHandshaker();
     }
@@ -2264,6 +2271,21 @@
         return null;
     }
 
+    @Override
+    public synchronized void setHandshakeApplicationProtocolSelector(
+        BiFunction<SSLEngine, List<String>, String> selector) {
+        applicationProtocolSelector = selector;
+        if ((handshaker != null) && !handshaker.activated()) {
+            handshaker.setApplicationProtocolSelectorSSLEngine(selector);
+        }
+    }
+
+    @Override
+    public synchronized BiFunction<SSLEngine, List<String>, String>
+        getHandshakeApplicationProtocolSelector() {
+        return this.applicationProtocolSelector;
+    }
+
     /**
      * Returns a printable representation of this end of the connection.
      */
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Mon Dec 19 16:05:38 2016 +0000
@@ -37,6 +37,7 @@
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiFunction;
 
 import javax.crypto.BadPaddingException;
 import javax.net.ssl.*;
@@ -223,6 +224,10 @@
     // The value under negotiation will be obtained from handshaker.
     String applicationProtocol = null;
 
+    // Callback function that selects the application protocol value during
+    // the SSL/TLS handshake.
+    BiFunction<SSLSocket, List<String>, String> applicationProtocolSelector;
+
     /*
      * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
      * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES.
@@ -1370,6 +1375,8 @@
         handshaker.setEnabledCipherSuites(enabledCipherSuites);
         handshaker.setEnableSessionCreation(enableSessionCreation);
         handshaker.setApplicationProtocols(applicationProtocols);
+        handshaker.setApplicationProtocolSelectorSSLSocket(
+            applicationProtocolSelector);
     }
 
     /**
@@ -2658,6 +2665,21 @@
         return null;
     }
 
+    @Override
+    public synchronized void setHandshakeApplicationProtocolSelector(
+        BiFunction<SSLSocket, List<String>, String> selector) {
+        applicationProtocolSelector = selector;
+        if ((handshaker != null) && !handshaker.activated()) {
+            handshaker.setApplicationProtocolSelectorSSLSocket(selector);
+        }
+    }
+
+    @Override
+    public synchronized BiFunction<SSLSocket, List<String>, String>
+        getHandshakeApplicationProtocolSelector() {
+        return this.applicationProtocolSelector;
+    }
+
     //
     // We allocate a separate thread to deliver handshake completion
     // events.  This ensures that the notifications don't block the
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Mon Dec 19 16:05:38 2016 +0000
@@ -34,6 +34,7 @@
 import java.security.interfaces.*;
 import java.security.spec.ECParameterSpec;
 import java.math.BigInteger;
+import java.util.function.BiFunction;
 
 import javax.crypto.SecretKey;
 import javax.net.ssl.*;
@@ -532,31 +533,39 @@
         ALPNExtension clientHelloALPN = (ALPNExtension)
             mesg.extensions.get(ExtensionType.EXT_ALPN);
 
-        if ((clientHelloALPN != null) && (localApl.length > 0)) {
+        // Use the application protocol callback when provided.
+        // Otherwise use the local list of application protocols.
+        boolean hasAPCallback =
+            ((engine != null && appProtocolSelectorSSLEngine != null) ||
+                (conn != null && appProtocolSelectorSSLSocket != null));
+
+        if (!hasAPCallback) {
+            if ((clientHelloALPN != null) && (localApl.length > 0)) {
 
-            // Intersect the requested and the locally supported,
-            // and save for later.
-            String negotiatedValue = null;
-            List<String> protocols = clientHelloALPN.getPeerAPs();
+                // Intersect the requested and the locally supported,
+                // and save for later.
+                String negotiatedValue = null;
+                List<String> protocols = clientHelloALPN.getPeerAPs();
 
-            // Use server preference order
-            for (String ap : localApl) {
-                if (protocols.contains(ap)) {
-                    negotiatedValue = ap;
-                    break;
+                // Use server preference order
+                for (String ap : localApl) {
+                    if (protocols.contains(ap)) {
+                        negotiatedValue = ap;
+                        break;
+                    }
                 }
-            }
 
-            if (negotiatedValue == null) {
-                fatalSE(Alerts.alert_no_application_protocol,
-                    new SSLHandshakeException(
-                        "No matching ALPN values"));
+                if (negotiatedValue == null) {
+                    fatalSE(Alerts.alert_no_application_protocol,
+                        new SSLHandshakeException(
+                            "No matching ALPN values"));
+                }
+                applicationProtocol = negotiatedValue;
+
+            } else {
+                applicationProtocol = "";
             }
-            applicationProtocol = negotiatedValue;
-
-        } else {
-            applicationProtocol = "";
-        }
+        }  // Otherwise, applicationProtocol will be set by the callback.
 
         session = null; // forget about the current session
         //
@@ -892,8 +901,36 @@
         }
 
         // Prepare the ALPN response
-        if (applicationProtocol != null && !applicationProtocol.isEmpty()) {
-            m1.extensions.add(new ALPNExtension(applicationProtocol));
+        if (clientHelloALPN != null) {
+            List<String> peerAPs = clientHelloALPN.getPeerAPs();
+
+            // check for a callback function
+            if (hasAPCallback) {
+                if (conn != null) {
+                    applicationProtocol =
+                        appProtocolSelectorSSLSocket.apply(conn, peerAPs);
+                } else {
+                    applicationProtocol =
+                        appProtocolSelectorSSLEngine.apply(engine, peerAPs);
+                }
+            }
+
+            // check for no-match and that the selected name was also proposed
+            // by the TLS peer
+            if (applicationProtocol == null ||
+                   (!applicationProtocol.isEmpty() &&
+                        !peerAPs.contains(applicationProtocol))) {
+
+                fatalSE(Alerts.alert_no_application_protocol,
+                    new SSLHandshakeException(
+                        "No matching ALPN values"));
+
+            } else if (!applicationProtocol.isEmpty()) {
+                m1.extensions.add(new ALPNExtension(applicationProtocol));
+            }
+        } else {
+            // Nothing was negotiated, returned at end of the handshake
+            applicationProtocol = "";
         }
 
         if (debug != null && Debug.isOn("handshake")) {
--- a/jdk/src/java.base/share/native/libjava/StrictMath.c	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/share/native/libjava/StrictMath.c	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -65,12 +65,6 @@
 }
 
 JNIEXPORT jdouble JNICALL
-Java_java_lang_StrictMath_exp(JNIEnv *env, jclass unused, jdouble d)
-{
-    return (jdouble) jexp((double)d);
-}
-
-JNIEXPORT jdouble JNICALL
 Java_java_lang_StrictMath_log(JNIEnv *env, jclass unused, jdouble d)
 {
     return (jdouble) jlog((double)d);
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -109,13 +109,9 @@
         private String helperPath(String javahome, String osArch) {
             switch (this) {
                 case SOLARIS:
-                    if (osArch.equals("x86")) { osArch = "i386"; }
-                    else if (osArch.equals("x86_64")) { osArch = "amd64"; }
                     // fall through...
                 case LINUX:
                 case AIX:
-                    return javahome + "/lib/" + osArch + "/jspawnhelper";
-
                 case BSD:
                     return javahome + "/lib/jspawnhelper";
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/unix/classes/module-info.java.extra	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+// jdk.vm.compiler uses Unsafe and VM classes from jdk.internal.misc
+exports jdk.internal.misc to jdk.vm.compiler;
+opens   jdk.internal.misc to jdk.vm.compiler;
+
+// jdk.vm.compiler uses com.sun.crypto.provider to generate crypto intrinsics
+opens com.sun.crypto.provider to jdk.vm.compiler;
+
+exports jdk.internal.module to jdk.vm.compiler;
+
+// AOT uses jdk.internal.misc.Unsafe
+exports jdk.internal.misc to jdk.aot;
--- a/jdk/src/java.base/unix/native/libjli/java_md.h	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/unix/native/libjli/java_md.h	Mon Dec 19 16:05:38 2016 +0000
@@ -54,10 +54,8 @@
 const char *SetExecname(char **argv);
 const char *GetExecName();
 static jboolean GetJVMPath(const char *jrepath, const char *jvmtype,
-                           char *jvmpath, jint jvmpathsize, const char * arch,
-                           int bitsWanted);
-static jboolean GetJREPath(char *path, jint pathsize, const char * arch,
-                           jboolean speculative);
+                           char *jvmpath, jint jvmpathsize, int bitsWanted);
+static jboolean GetJREPath(char *path, jint pathsize, jboolean speculative);
 
 #if defined(_AIX)
 #include "java_md_aix.h"
--- a/jdk/src/java.base/unix/native/libjli/java_md_solinux.c	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/unix/native/libjli/java_md_solinux.c	Mon Dec 19 16:05:38 2016 +0000
@@ -52,9 +52,6 @@
 #endif
 
 #ifdef __solaris__
-#  ifndef LIBARCHNAME
-#    error "The macro LIBARCHNAME was not defined on the compile line"
-#  endif
 #  include <sys/systeminfo.h>
 #  include <sys/elf.h>
 #  include <stdio.h>
@@ -188,12 +185,13 @@
     return JNI_FALSE;
 }
 /*
- * contains a lib/$LIBARCHNAME/{server,client}/libjvm.so ?
+ * contains a lib/{server,client}/libjvm.so ?
  */
 static jboolean
 ContainsLibJVM(const char *env) {
-    char clientPattern[PATH_MAX + 1];
-    char serverPattern[PATH_MAX + 1];
+    /* the usual suspects */
+    char clientPattern[] = "lib/client";
+    char serverPattern[] = "lib/server";
     char *envpath;
     char *path;
     jboolean clientPatternFound;
@@ -204,10 +202,6 @@
         return JNI_FALSE;
     }
 
-    /* the usual suspects */
-    JLI_Snprintf(clientPattern, PATH_MAX, "lib/%s/client", LIBARCHNAME);
-    JLI_Snprintf(serverPattern, PATH_MAX, "lib/%s/server", LIBARCHNAME);
-
     /* to optimize for time, test if any of our usual suspects are present. */
     clientPatternFound = JLI_StrStr(env, clientPattern) != NULL;
     serverPatternFound = JLI_StrStr(env, serverPattern) != NULL;
@@ -322,7 +316,6 @@
 
     /* Check data model flags, and exec process, if needed */
     {
-      char *arch        = LIBARCHNAME; /* like sparc or sparcv9 */
       char * jvmtype    = NULL;
       int  argc         = *pargc;
       char **argv       = *pargv;
@@ -408,12 +401,12 @@
          jvmpath does not exist */
       if (wanted == running) {
         /* Find out where the JRE is that we will be using. */
-        if (!GetJREPath(jrepath, so_jrepath, arch, JNI_FALSE) ) {
+        if (!GetJREPath(jrepath, so_jrepath, JNI_FALSE) ) {
           JLI_ReportErrorMessage(JRE_ERROR1);
           exit(2);
         }
-        JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",
-                     jrepath, FILESEP, FILESEP,  arch, FILESEP);
+        JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%sjvm.cfg",
+                     jrepath, FILESEP, FILESEP, FILESEP);
         /* Find the specified JVM type */
         if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
           JLI_ReportErrorMessage(CFG_ERROR7);
@@ -427,7 +420,7 @@
             exit(4);
         }
 
-        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, arch, 0 )) {
+        if (!GetJVMPath(jrepath, jvmtype, jvmpath, so_jvmpath, 0 )) {
           JLI_ReportErrorMessage(CFG_ERROR8, jvmtype, jvmpath);
           exit(4);
         }
@@ -457,8 +450,8 @@
              * We will set the LD_LIBRARY_PATH as follows:
              *
              *     o          $JVMPATH (directory portion only)
-             *     o          $JRE/lib/$LIBARCHNAME
-             *     o          $JRE/../lib/$LIBARCHNAME
+             *     o          $JRE/lib
+             *     o          $JRE/../lib
              *
              * followed by the user's previous effective LD_LIBRARY_PATH, if
              * any.
@@ -518,10 +511,10 @@
             { /* New scope to declare local variable */
               char *new_jvmpath = JLI_StringDup(jvmpath);
               new_runpath_size = ((runpath != NULL) ? JLI_StrLen(runpath) : 0) +
-                      2 * JLI_StrLen(jrepath) + 2 * JLI_StrLen(arch) +
+                      2 * JLI_StrLen(jrepath) +
 #ifdef AIX
                       /* On AIX we additionally need 'jli' in the path because ld doesn't support $ORIGIN. */
-                      JLI_StrLen(jrepath) + JLI_StrLen(arch) + JLI_StrLen("/lib//jli:") +
+                      JLI_StrLen(jrepath) + JLI_StrLen("/lib//jli:") +
 #endif
                       JLI_StrLen(new_jvmpath) + 52;
               new_runpath = JLI_MemAlloc(new_runpath_size);
@@ -539,17 +532,17 @@
 
                 sprintf(new_runpath, LD_LIBRARY_PATH "="
                         "%s:"
-                        "%s/lib/%s:"
+                        "%s/lib:"
 #ifdef AIX
-                        "%s/lib/%s/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */
+                        "%s/lib/jli:" /* Needed on AIX because ld doesn't support $ORIGIN. */
 #endif
-                        "%s/../lib/%s",
+                        "%s/../lib",
                         new_jvmpath,
-                        jrepath, arch,
+                        jrepath,
 #ifdef AIX
-                        jrepath, arch,
+                        jrepath,
 #endif
-                        jrepath, arch
+                        jrepath
                         );
 
                 JLI_MemFree(new_jvmpath);
@@ -640,14 +633,14 @@
  */
 static jboolean
 GetJVMPath(const char *jrepath, const char *jvmtype,
-           char *jvmpath, jint jvmpathsize, const char * arch, int bitsWanted)
+           char *jvmpath, jint jvmpathsize, int bitsWanted)
 {
     struct stat s;
 
     if (JLI_StrChr(jvmtype, '/')) {
         JLI_Snprintf(jvmpath, jvmpathsize, "%s/" JVM_DLL, jvmtype);
     } else {
-        JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/%s/" JVM_DLL, jrepath, arch, jvmtype);
+        JLI_Snprintf(jvmpath, jvmpathsize, "%s/lib/%s/" JVM_DLL, jrepath, jvmtype);
     }
 
     JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
@@ -665,14 +658,14 @@
  * Find path to JRE based on .exe's location or registry settings.
  */
 static jboolean
-GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
+GetJREPath(char *path, jint pathsize, jboolean speculative)
 {
     char libjava[MAXPATHLEN];
     struct stat s;
 
     if (GetApplicationHome(path, pathsize)) {
         /* Is JRE co-located with the application? */
-        JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);
+        JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
         if (access(libjava, F_OK) == 0) {
             JLI_TraceLauncher("JRE path is %s\n", path);
             return JNI_TRUE;
@@ -683,7 +676,7 @@
             return JNI_FALSE;
         }
         /* Does the app ship a private JRE in <apphome>/jre directory? */
-        JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/%s/" JAVA_DLL, path, arch);
+        JLI_Snprintf(libjava, sizeof(libjava), "%s/jre/lib/" JAVA_DLL, path);
         if (access(libjava, F_OK) == 0) {
             JLI_StrCat(path, "/jre");
             JLI_TraceLauncher("JRE path is %s\n", path);
@@ -692,7 +685,7 @@
     }
 
     if (GetApplicationHomeFromDll(path, pathsize)) {
-        JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/%s/" JAVA_DLL, path, arch);
+        JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
         if (stat(libjava, &s) == 0) {
             JLI_TraceLauncher("JRE path is %s\n", path);
             return JNI_TRUE;
@@ -858,12 +851,12 @@
         char jrePath[MAXPATHLEN];
         char splashPath[MAXPATHLEN];
 
-        if (!GetJREPath(jrePath, sizeof(jrePath), LIBARCHNAME, JNI_FALSE)) {
+        if (!GetJREPath(jrePath, sizeof(jrePath), JNI_FALSE)) {
             JLI_ReportErrorMessage(JRE_ERROR1);
             return NULL;
         }
-        ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s/%s",
-                     jrePath, LIBARCHNAME, SPLASHSCREEN_SO);
+        ret = JLI_Snprintf(splashPath, sizeof(splashPath), "%s/lib/%s",
+                     jrePath, SPLASHSCREEN_SO);
 
         if (ret >= (int) sizeof(splashPath)) {
             JLI_ReportErrorMessage(JRE_ERROR11);
--- a/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/unix/native/libnet/Inet4AddressImpl.c	Mon Dec 19 16:05:38 2016 +0000
@@ -37,273 +37,10 @@
 
 #include "java_net_Inet4AddressImpl.h"
 
-#if defined(__GLIBC__) || (defined(__FreeBSD__) && (__FreeBSD_version >= 601104))
-#define HAS_GLIBC_GETHOSTBY_R   1
-#endif
-
-
-#if defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R)
+#if defined(MACOSX)
 extern jobjectArray lookupIfLocalhost(JNIEnv *env, const char *hostname, jboolean includeV6);
-
-/* Use getaddrinfo(3), which is thread safe */
-/************************************************************************
- * Inet4AddressImpl
- */
-
-/*
- * Class:     java_net_Inet4AddressImpl
- * Method:    getLocalHostName
- * Signature: ()Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL
-Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
-    char hostname[NI_MAXHOST+1];
-
-    hostname[0] = '\0';
-    if (gethostname(hostname, NI_MAXHOST)) {
-        /* Something went wrong, maybe networking is not setup? */
-        strcpy(hostname, "localhost");
-    } else {
-         struct addrinfo  hints, *res;
-         int error;
-
-         memset(&hints, 0, sizeof(hints));
-         hints.ai_flags = AI_CANONNAME;
-         hints.ai_family = AF_UNSPEC;
-
-         error = getaddrinfo(hostname, NULL, &hints, &res);
-
-         if (error == 0) {
-             /* host is known to name service */
-             error = getnameinfo(res->ai_addr,
-                                 res->ai_addrlen,
-                                 hostname,
-                                 NI_MAXHOST,
-                                 NULL,
-                                 0,
-                                 NI_NAMEREQD);
-
-             /* if getnameinfo fails hostname is still the value
-                from gethostname */
-
-             freeaddrinfo(res);
-        }
-    }
-    return (*env)->NewStringUTF(env, hostname);
-}
-
-/*
- * Find an internet address for a given hostname.  Note that this
- * code only works for addresses of type INET. The translation
- * of %d.%d.%d.%d to an address (int) occurs in java now, so the
- * String "host" shouldn't *ever* be a %d.%d.%d.%d string
- *
- * Class:     java_net_Inet4AddressImpl
- * Method:    lookupAllHostAddr
- * Signature: (Ljava/lang/String;)[[B
- */
-
-JNIEXPORT jobjectArray JNICALL
-Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this,
-                                                jstring host) {
-    const char *hostname;
-    jobject name;
-    jobjectArray ret = 0;
-    int retLen = 0;
-
-    int getaddrinfo_error=0;
-    struct addrinfo hints, *res, *resNew = NULL;
-
-    initInetAddressIDs(env);
-    JNU_CHECK_EXCEPTION_RETURN(env, NULL);
-
-    if (IS_NULL(host)) {
-        JNU_ThrowNullPointerException(env, "host is null");
-        return 0;
-    }
-    hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
-    CHECK_NULL_RETURN(hostname, NULL);
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_flags = AI_CANONNAME;
-    hints.ai_family = AF_INET;
-
-    /*
-     * Workaround for Solaris bug 4160367 - if a hostname contains a
-     * white space then 0.0.0.0 is returned
-     */
-    if (isspace((unsigned char)hostname[0])) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
-                        (char *)hostname);
-        JNU_ReleaseStringPlatformChars(env, host, hostname);
-        return NULL;
-    }
-
-
-    getaddrinfo_error = getaddrinfo(hostname, NULL, &hints, &res);
-
-#ifdef MACOSX
-    if (getaddrinfo_error) {
-        // If getaddrinfo fails try getifaddrs.
-        ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
-        if (ret != NULL || (*env)->ExceptionCheck(env)) {
-            JNU_ReleaseStringPlatformChars(env, host, hostname);
-            return ret;
-        }
-    }
 #endif
 
-    if (getaddrinfo_error) {
-        /* report error */
-        NET_ThrowUnknownHostExceptionWithGaiError(
-            env, hostname, getaddrinfo_error);
-        JNU_ReleaseStringPlatformChars(env, host, hostname);
-        return NULL;
-    } else {
-        int i = 0;
-        struct addrinfo *itr, *last = NULL, *iterator = res;
-        while (iterator != NULL) {
-            int skip = 0;
-            itr = resNew;
-
-            while (itr != NULL) {
-                struct sockaddr_in *addr1, *addr2;
-
-                addr1 = (struct sockaddr_in *)iterator->ai_addr;
-                addr2 = (struct sockaddr_in *)itr->ai_addr;
-                if (addr1->sin_addr.s_addr ==
-                    addr2->sin_addr.s_addr) {
-                    skip = 1;
-                    break;
-                }
-
-                itr = itr->ai_next;
-            }
-
-            if (!skip) {
-                struct addrinfo *next
-                    = (struct addrinfo*) malloc(sizeof(struct addrinfo));
-                if (!next) {
-                    JNU_ThrowOutOfMemoryError(env, "Native heap allocation failed");
-                    ret = NULL;
-                    goto cleanupAndReturn;
-                }
-                memcpy(next, iterator, sizeof(struct addrinfo));
-                next->ai_next = NULL;
-                if (resNew == NULL) {
-                    resNew = next;
-                } else {
-                    last->ai_next = next;
-                }
-                last = next;
-                i++;
-            }
-            iterator = iterator->ai_next;
-        }
-
-        retLen = i;
-        iterator = resNew;
-        i = 0;
-
-        name = (*env)->NewStringUTF(env, hostname);
-        if (IS_NULL(name)) {
-          goto cleanupAndReturn;
-        }
-
-        ret = (*env)->NewObjectArray(env, retLen, ia_class, NULL);
-        if (IS_NULL(ret)) {
-            /* we may have memory to free at the end of this */
-            goto cleanupAndReturn;
-        }
-
-        while (iterator != NULL) {
-            /* We need 4 bytes to store ipv4 address; */
-            int len = 4;
-
-            jobject iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
-            if (IS_NULL(iaObj)) {
-                /* we may have memory to free at the end of this */
-                ret = NULL;
-                goto cleanupAndReturn;
-            }
-            setInetAddress_addr(env, iaObj, ntohl(((struct sockaddr_in*)(iterator->ai_addr))->sin_addr.s_addr));
-            setInetAddress_hostName(env, iaObj, name);
-            (*env)->SetObjectArrayElement(env, ret, retLen - i -1, iaObj);
-            i++;
-            iterator = iterator->ai_next;
-        }
-    }
-
-cleanupAndReturn:
-    {
-        struct addrinfo *iterator, *tmp;
-        iterator = resNew;
-        while (iterator != NULL) {
-            tmp = iterator;
-            iterator = iterator->ai_next;
-            free(tmp);
-        }
-        JNU_ReleaseStringPlatformChars(env, host, hostname);
-    }
-
-    freeaddrinfo(res);
-
-    return ret;
-
-}
-
-/*
- * Class:     java_net_Inet4AddressImpl
- * Method:    getHostByAddr
- * Signature: (I)Ljava/lang/String;
- */
-JNIEXPORT jstring JNICALL
-Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this,
-                                            jbyteArray addrArray) {
-    jstring ret = NULL;
-
-    char host[NI_MAXHOST+1];
-    jfieldID fid;
-    int error = 0;
-    jint family;
-    struct sockaddr *him ;
-    int len = 0;
-    jbyte caddr[4];
-    jint addr;
-
-    struct sockaddr_in him4;
-    struct sockaddr *sa;
-
-    /*
-         * For IPv4 addresses construct a sockaddr_in structure.
-         */
-    (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
-    addr = ((caddr[0]<<24) & 0xff000000);
-    addr |= ((caddr[1] <<16) & 0xff0000);
-    addr |= ((caddr[2] <<8) & 0xff00);
-    addr |= (caddr[3] & 0xff);
-    memset((char *) &him4, 0, sizeof(him4));
-    him4.sin_addr.s_addr = htonl(addr);
-    him4.sin_family = AF_INET;
-    sa = (struct sockaddr *) &him4;
-    len = sizeof(him4);
-
-    error = getnameinfo(sa, len, host, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
-
-    if (!error) {
-        ret = (*env)->NewStringUTF(env, host);
-    }
-
-    if (ret == NULL) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException", NULL);
-    }
-
-    return ret;
-
-}
-
-#else /* defined(_ALLBSD_SOURCE) && !defined(HAS_GLIBC_GETHOSTBY_R) */
-
 /* the initial size of our hostent buffers */
 #ifndef NI_MAXHOST
 #define NI_MAXHOST 1025
@@ -405,6 +142,17 @@
 
     error = getaddrinfo(hostname, NULL, &hints, &res);
 
+#ifdef MACOSX
+    if (error) {
+        // If getaddrinfo fails try getifaddrs, see bug 8170910.
+        ret = lookupIfLocalhost(env, hostname, JNI_FALSE);
+        if (ret != NULL || (*env)->ExceptionCheck(env)) {
+            JNU_ReleaseStringPlatformChars(env, host, hostname);
+            return ret;
+        }
+    }
+#endif
+
     if (error) {
         /* report error */
         NET_ThrowUnknownHostExceptionWithGaiError(env, hostname, error);
@@ -475,7 +223,7 @@
         }
     }
 
- cleanupAndReturn:
+cleanupAndReturn:
     {
         struct addrinfo *iterator, *tmp;
         iterator = resNew;
@@ -535,8 +283,6 @@
     return ret;
 }
 
-#endif /* _ALLBSD_SOURCE */
-
 #define SET_NONBLOCKING(fd) {           \
         int flags = fcntl(fd, F_GETFL); \
         flags |= O_NONBLOCK;            \
--- a/jdk/src/java.base/windows/native/libjli/java_md.c	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.base/windows/native/libjli/java_md.c	Mon Dec 19 16:05:38 2016 +0000
@@ -151,22 +151,6 @@
 }
 
 /*
- * Returns the arch path, to get the current arch use the
- * macro GetArch, nbits here is ignored for now.
- */
-const char *
-GetArchPath(int nbits)
-{
-#ifdef _M_AMD64
-    return "amd64";
-#elif defined(_M_IA64)
-    return "ia64";
-#else
-    return "i386";
-#endif
-}
-
-/*
  *
  */
 void
@@ -207,8 +191,8 @@
         exit(2);
     }
 
-    JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%s%s%sjvm.cfg",
-        jrepath, FILESEP, FILESEP, (char*)GetArch(), FILESEP);
+    JLI_Snprintf(jvmcfg, so_jvmcfg, "%s%slib%sjvm.cfg",
+        jrepath, FILESEP, FILESEP);
 
     /* Find the specified JVM type */
     if (ReadKnownVMs(jvmcfg, JNI_FALSE) < 1) {
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java	Mon Dec 19 16:05:38 2016 +0000
@@ -34,10 +34,18 @@
 
 import sun.lwawt.macosx.LWCToolkit;
 import sun.security.action.GetBooleanAction;
-import sun.security.action.GetPropertyAction;
 
 // MenuBar implementation for Mac L&F
 public class AquaMenuBarUI extends BasicMenuBarUI implements ScreenMenuBarProvider {
+
+    static {
+        java.security.AccessController.doPrivileged(
+                (java.security.PrivilegedAction<Void>) () -> {
+            System.loadLibrary("osxui");
+            return null;
+        });
+    }
+
     // Utilities
     public void uninstallUI(final JComponent c) {
         if (fScreenMenuBar != null) {
@@ -134,7 +142,7 @@
     ScreenMenuBar fScreenMenuBar;
     boolean useScreenMenuBar = getScreenMenuBarProperty();
 
-    static boolean getScreenMenuBarProperty() {
+    public static boolean getScreenMenuBarProperty() {
         // Do not allow AWT to set the screen menu bar if it's embedded in another UI toolkit
         if (LWCToolkit.isEmbedded()) return false;
         if (AccessController.doPrivileged(
--- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java	Mon Dec 19 16:05:38 2016 +0000
@@ -141,12 +141,24 @@
         }
     }
 
-    protected void registerFontsInDir(String dirName, boolean useJavaRasterizer, int fontRank, boolean defer, boolean resolveSymLinks) {
-        loadNativeDirFonts(dirName);
+    protected void registerFontsInDir(final String dirName, boolean useJavaRasterizer,
+                                      int fontRank, boolean defer, boolean resolveSymLinks) {
+
+        String[] files = AccessController.doPrivileged((PrivilegedAction<String[]>) () -> {
+            return new File(dirName).list(getTrueTypeFilter());
+        });
+
+        if (files == null) {
+           return;
+        } else {
+            for (String f : files) {
+                loadNativeDirFonts(dirName+File.separator+f);
+            }
+        }
         super.registerFontsInDir(dirName, useJavaRasterizer, fontRank, defer, resolveSymLinks);
     }
 
-    private native void loadNativeDirFonts(String dirName);
+    private native void loadNativeDirFonts(String fontPath);
     private native void loadNativeFonts();
 
     void registerFont(String fontName, String fontFamilyName) {
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Mon Dec 19 16:05:38 2016 +0000
@@ -33,11 +33,14 @@
 import java.awt.event.*;
 import java.beans.*;
 import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
 
 import javax.swing.*;
 
 import sun.awt.*;
 import sun.awt.AWTAccessor.ComponentAccessor;
+import sun.awt.AWTAccessor.WindowAccessor;
 import sun.java2d.SurfaceData;
 import sun.java2d.opengl.CGLSurfaceData;
 import sun.lwawt.*;
@@ -1031,6 +1034,11 @@
         return !peer.isSimpleWindow() && target.getFocusableWindowState();
     }
 
+    private boolean isBlocked() {
+        LWWindowPeer blocker = (peer != null) ? peer.getBlocker() : null;
+        return (blocker != null);
+    }
+
     /*
      * An utility method for the support of the auto request focus.
      * Updates the focusable state of the window under certain
@@ -1063,29 +1071,70 @@
         return true;
     }
 
+    private boolean isOneOfOwnersOrSelf(CPlatformWindow window) {
+        while (window != null) {
+            if (this == window) {
+                return true;
+            }
+            window = window.owner;
+        }
+        return false;
+    }
+
+    private CPlatformWindow getRootOwner() {
+        CPlatformWindow rootOwner = this;
+        while (rootOwner.owner != null) {
+            rootOwner = rootOwner.owner;
+        }
+        return rootOwner;
+    }
+
     private void orderAboveSiblings() {
-        if (owner == null) {
-            return;
+        // Recursively pop up the windows from the very bottom, (i.e. root owner) so that
+        // the windows are ordered above their nearest owner; ancestors of the window,
+        // which is going to become 'main window', are placed above their siblings.
+        CPlatformWindow rootOwner = getRootOwner();
+        if (rootOwner.isVisible()) {
+            CWrapper.NSWindow.orderFront(rootOwner.getNSWindowPtr());
         }
+        final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
+        orderAboveSiblingsImpl(windowAccessor.getOwnedWindows(rootOwner.target));
+    }
 
-        // NOTE: the logic will fail if we have a hierarchy like:
-        //       visible root owner
-        //          invisible owner
-        //              visible dialog
-        // However, this is an unlikely scenario for real life apps
-        if (owner.isVisible()) {
-            // Recursively pop up the windows from the very bottom so that only
-            // the very top-most one becomes the main window
-            owner.orderAboveSiblings();
+    private void orderAboveSiblingsImpl(Window[] windows) {
+        ArrayList<Window> childWindows = new ArrayList<Window>();
+
+        final ComponentAccessor componentAccessor = AWTAccessor.getComponentAccessor();
+        final WindowAccessor windowAccessor = AWTAccessor.getWindowAccessor();
 
-            // Order the window to front of the stack of child windows
-            final long nsWindowSelfPtr = getNSWindowPtr();
-            final long nsWindowOwnerPtr = owner.getNSWindowPtr();
-            CWrapper.NSWindow.orderFront(nsWindowOwnerPtr);
-            CWrapper.NSWindow.orderWindow(nsWindowSelfPtr, CWrapper.NSWindow.NSWindowAbove, nsWindowOwnerPtr);
+        // Go through the list of windows and perform ordering.
+        for (Window w : windows) {
+            final Object p = componentAccessor.getPeer(w);
+            if (p instanceof LWWindowPeer) {
+                CPlatformWindow pw = (CPlatformWindow)((LWWindowPeer)p).getPlatformWindow();
+                if (pw != null && pw.isVisible()) {
+                    // If the window is one of ancestors of 'main window' or is going to become main by itself,
+                    // the window should be ordered above its siblings; otherwise the window is just ordered
+                    // above its nearest parent.
+                    if (pw.isOneOfOwnersOrSelf(this)) {
+                        CWrapper.NSWindow.orderFront(pw.getNSWindowPtr());
+                    } else {
+                        CWrapper.NSWindow.orderWindow(pw.getNSWindowPtr(), CWrapper.NSWindow.NSWindowAbove,
+                                pw.owner.getNSWindowPtr());
+                    }
+                    pw.applyWindowLevel(w);
+                }
+            }
+            // Retrieve the child windows for each window from the list and store them for future use.
+            // Note: we collect data about child windows even for invisible owners, since they may have
+            // visible children.
+            childWindows.addAll(Arrays.asList(windowAccessor.getOwnedWindows(w)));
         }
-
-        applyWindowLevel(target);
+        // If some windows, which have just been ordered, have any child windows, let's start new iteration
+        // and order these child windows.
+        if (!childWindows.isEmpty()) {
+            orderAboveSiblingsImpl(childWindows.toArray(new Window[0]));
+        }
     }
 
     protected void applyWindowLevel(Window target) {
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Mon Dec 19 16:05:38 2016 +0000
@@ -25,6 +25,7 @@
 
 package sun.lwawt.macosx;
 
+import com.apple.laf.AquaMenuBarUI;
 import java.awt.peer.TaskbarPeer;
 import java.awt.*;
 import java.awt.datatransfer.Clipboard;
@@ -43,6 +44,7 @@
 import java.util.*;
 import java.util.concurrent.Callable;
 import java.net.MalformedURLException;
+import javax.swing.UIManager;
 
 import sun.awt.*;
 import sun.awt.datatransfer.DataTransferer;
@@ -935,4 +937,13 @@
     protected PlatformWindow getPlatformWindowUnderMouse() {
         return CPlatformWindow.nativeGetTopmostPlatformWindowUnderMouse();
     }
+
+    @Override
+    public void updateScreenMenuBarUI() {
+        if (AquaMenuBarUI.getScreenMenuBarProperty())  {
+            UIManager.put("MenuBarUI", "com.apple.laf.AquaMenuBarUI");
+        } else {
+            UIManager.put("MenuBarUI", null);
+        }
+    }
 }
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Mon Dec 19 16:05:38 2016 +0000
@@ -430,7 +430,22 @@
     [super dealloc];
 }
 
-// Tests wheather the corresponding Java paltform window is visible or not
+// Tests whether window is blocked by modal dialog/window
+- (BOOL) isBlocked {
+    BOOL isBlocked = NO;
+    
+    JNIEnv *env = [ThreadUtilities getJNIEnv];
+    jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
+    if (platformWindow != NULL) {
+        static JNF_MEMBER_CACHE(jm_isBlocked, jc_CPlatformWindow, "isBlocked", "()Z");
+        isBlocked = JNFCallBooleanMethod(env, platformWindow, jm_isBlocked) == JNI_TRUE ? YES : NO;
+        (*env)->DeleteLocalRef(env, platformWindow);
+    }
+    
+    return isBlocked;
+}
+
+// Tests whether the corresponding Java platform window is visible or not
 + (BOOL) isJavaPlatformWindowVisible:(NSWindow *)window {
     BOOL isVisible = NO;
 
@@ -454,8 +469,9 @@
 - (void) orderChildWindows:(BOOL)focus {
 AWT_ASSERT_APPKIT_THREAD;
 
-    if (self.isMinimizing) {
+    if (self.isMinimizing || [self isBlocked]) {
         // Do not perform any ordering, if iconify is in progress
+        // or the window is blocked by a modal window
         return;
     }
 
@@ -809,18 +825,20 @@
 
 - (void)sendEvent:(NSEvent *)event {
         if ([event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown) {
-            // Move parent windows to front and make sure that a child window is displayed
-            // in front of its nearest parent.
-            if (self.ownerWindow != nil) {
-                JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
-                jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
-                if (platformWindow != NULL) {
-                    static JNF_MEMBER_CACHE(jm_orderAboveSiblings, jc_CPlatformWindow, "orderAboveSiblings", "()V");
-                    JNFCallVoidMethod(env,platformWindow, jm_orderAboveSiblings);
-                    (*env)->DeleteLocalRef(env, platformWindow);
+            if ([self isBlocked]) {
+                // Move parent windows to front and make sure that a child window is displayed
+                // in front of its nearest parent.
+                if (self.ownerWindow != nil) {
+                    JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
+                    jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
+                    if (platformWindow != NULL) {
+                        static JNF_MEMBER_CACHE(jm_orderAboveSiblings, jc_CPlatformWindow, "orderAboveSiblings", "()V");
+                        JNFCallVoidMethod(env,platformWindow, jm_orderAboveSiblings);
+                        (*env)->DeleteLocalRef(env, platformWindow);
+                    }
                 }
+                [self orderChildWindows:YES];
             }
-            [self orderChildWindows:YES];
 
             NSPoint p = [NSEvent mouseLocation];
             NSRect frame = [self.nsWindow frame];
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m	Mon Dec 19 16:05:38 2016 +0000
@@ -115,19 +115,18 @@
             if (keyWindow != nil) {
                 return;
             }
-        }
-        else {
-            static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem");
-            static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event)
-            
-            NSUInteger modifiers = [currEvent modifierFlags];
-            jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO);
-            
-            JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event)
-        }
+		}
+		
+        static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem");
+        static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event)
+
+        NSUInteger modifiers = [currEvent modifierFlags];
+        jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO);
+
+        JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event)
     }
     JNF_COCOA_EXIT(env);
-    
+	
 }
 
 - (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers {
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m	Mon Dec 19 16:05:38 2016 +0000
@@ -404,19 +404,14 @@
 {
 JNF_COCOA_ENTER(env);
 
-    NSString *nsFilePath = JNFJavaToNSString(env, filename);
-
-    FSRef iFile;
-    OSStatus status = CreateFSRef(&iFile, nsFilePath);
-
-    if (status == noErr) {
-        ATSFontContainerRef oContainer;
-        status = ATSFontActivateFromFileReference(&iFile, kATSFontContextLocal,
-                                                  kATSFontFormatUnspecified,
-                                                  NULL, kNilOptions,
-                                                  &oContainer);
-    }
-
+    NSString *path = JNFJavaToNSString(env, filename);
+    NSURL *url = [NSURL fileURLWithPath:(NSString *)path];
+    bool res = CTFontManagerRegisterFontsForURL((CFURLRef)url, kCTFontManagerScopeProcess, nil);
+#ifdef DEBUG
+    NSLog(@"path is : %@", (NSString*)path);
+    NSLog(@"url is : %@", (NSString*)url);
+    printf("res is %d\n", res);
+#endif
 JNF_COCOA_EXIT(env);
 }
 
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CGGlyphImages.m	Mon Dec 19 16:05:38 2016 +0000
@@ -591,7 +591,7 @@
 static inline GlyphInfo *
 CGGI_CreateImageForUnicode
     (CGGI_GlyphCanvas *canvas, const AWTStrike *strike,
-     const CGGI_RenderingMode *mode, const UniChar uniChar)
+     const CGGI_RenderingMode *mode, const UnicodeScalarValue uniChar)
 {
     // save the state of the world
     CGContextSaveGState(canvas->context);
@@ -668,7 +668,7 @@
                                         const AWTStrike *strike,
                                         const CGGI_RenderingMode *mode,
                                         jlong glyphInfos[],
-                                        const UniChar uniChars[],
+                                        const UnicodeScalarValue uniChars[],
                                         const CGGlyph glyphs[],
                                         const CFIndex len)
 {
@@ -720,7 +720,7 @@
 static inline void
 CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
                          const CGGI_RenderingMode *mode,
-                         const UniChar uniChars[], const CGGlyph glyphs[],
+                         const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
                          const size_t maxWidth, const size_t maxHeight,
                          const CFIndex len)
 {
@@ -767,7 +767,7 @@
 static inline void
 CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
                       const CGGI_RenderingMode *mode,
-                      const UniChar uniChars[], const CGGlyph glyphs[],
+                      const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
                       CGSize advances[], CGRect bboxes[], const CFIndex len)
 {
     AWTFont *font = strike->fAWTFont;
@@ -817,7 +817,7 @@
                                         const AWTStrike *strike,
                                         const CGGI_RenderingMode *mode,
                                         jint rawGlyphCodes[],
-                                        UniChar uniChars[], CGGlyph glyphs[],
+                                        UnicodeScalarValue uniChars[], CGGlyph glyphs[],
                                         CGSize advances[], CGRect bboxes[],
                                         const CFIndex len)
 {
@@ -860,7 +860,7 @@
         CGRect bboxes[len];
         CGSize advances[len];
         CGGlyph glyphs[len];
-        UniChar uniChars[len];
+        UnicodeScalarValue uniChars[len];
 
         CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
                                                 rawGlyphCodes, uniChars, glyphs,
@@ -871,7 +871,7 @@
 
     // just do one malloc, and carve it up for all the buffers
     void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
-                          sizeof(CGGlyph) * sizeof(UniChar) * len);
+                          sizeof(CGGlyph) * sizeof(UnicodeScalarValue) * len);
     if (buffer == NULL) {
         [[NSException exceptionWithName:NSMallocException
             reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
@@ -880,7 +880,7 @@
     CGRect *bboxes = (CGRect *)(buffer);
     CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
     CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
-    UniChar *uniChars = (UniChar *)(glyphs + sizeof(UniChar) * len);
+    UnicodeScalarValue *uniChars = (UnicodeScalarValue *)(glyphs + sizeof(UnicodeScalarValue) * len);
 
     CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
                                             rawGlyphCodes, uniChars, glyphs,
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.h	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.h	Mon Dec 19 16:05:38 2016 +0000
@@ -32,7 +32,9 @@
 #pragma mark --- CoreText Support ---
 
 #define HI_SURROGATE_START 0xD800
+#define HI_SURROGATE_END   0xDBFF
 #define LO_SURROGATE_START 0xDC00
+#define LO_SURROGATE_END   0xDFFF
 
 /*
  *    Transform Unicode characters into glyphs.
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.m	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/CoreTextSupport.m	Mon Dec 19 16:05:38 2016 +0000
@@ -103,24 +103,34 @@
 
     size_t i;
     for (i = 0; i < count; i++) {
+        UniChar unicode = unicodes[i];
+        UniChar nextUnicode = (i+1) < count ? unicodes[i+1] : 0;
+        bool surrogatePair = unicode >= HI_SURROGATE_START && unicode <= HI_SURROGATE_END
+                             && nextUnicode >= LO_SURROGATE_START && nextUnicode <= LO_SURROGATE_END;
+
         CGGlyph glyph = glyphs[i];
         if (glyph > 0) {
             glyphsAsInts[i] = glyph;
+            if (surrogatePair) i++;
             continue;
         }
 
-        UniChar unicode = unicodes[i];
-        const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicode, 1);
+        const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicodes[i],
+                                                                          surrogatePair ? 2 : 1);
         if (fallback) {
-            CTFontGetGlyphsForCharacters(fallback, &unicode, &glyph, 1);
+            CTFontGetGlyphsForCharacters(fallback, &unicodes[i], &glyphs[i], surrogatePair ? 2 : 1);
+            glyph = glyphs[i];
             CFRelease(fallback);
         }
 
         if (glyph > 0) {
-            glyphsAsInts[i] = -unicode; // set the glyph code to the negative unicode value
+            int codePoint = surrogatePair ? (((int)(unicode - HI_SURROGATE_START)) << 10)
+                                            + nextUnicode - LO_SURROGATE_START + 0x10000 : unicode;
+            glyphsAsInts[i] = -codePoint; // set the glyph code to the negative unicode value
         } else {
             glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either
         }
+        if (surrogatePair) i++;
     }
 }
 
@@ -158,8 +168,18 @@
         return (CTFontRef)font->fFont;
     }
 
-    UTF16Char character = -glyphCode;
-    return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
+    int codePoint = -glyphCode;
+    if (codePoint >= 0x10000) {
+        UTF16Char chars[2];
+        CGGlyph glyphs[2];
+        CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, chars);
+        CTFontRef result = CTS_CopyCTFallbackFontAndGlyphForUnicode(font, chars, glyphs, 2);
+        *glyphRef = glyphs[0];
+        return result;
+    } else {
+        UTF16Char character = codePoint;
+        return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
+    }
 }
 
 // Breakup a 32 bit unicode value into the component surrogate pairs
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java	Mon Dec 19 16:05:38 2016 +0000
@@ -541,10 +541,10 @@
     }
 
     // Stream position initially at beginning, left at end
-    // if ignoreUnknownFields is true, do not load fields for which
+    // if readUnknownTags is false, do not load fields for which
     // a tag cannot be found in an allowed TagSet.
     public void initialize(ImageInputStream stream, boolean isPrimaryIFD,
-        boolean ignoreUnknownFields) throws IOException {
+        boolean ignoreMetadata, boolean readUnknownTags) throws IOException {
 
         removeTIFFFields();
 
@@ -553,10 +553,16 @@
 
         List<TIFFTagSet> tagSetList = getTagSetList();
 
+        // Configure essential tag variables if this is the primary IFD and
+        // either all metadata are being ignored, or metadata are not being
+        // ignored but both unknown tags are being ignored and the tag set
+        // list does not contain the baseline tags.
         boolean ensureEssentialTags = false;
         TIFFTagSet baselineTagSet = null;
-        if (isPrimaryIFD && ignoreUnknownFields
-            && !tagSetList.contains(BaselineTIFFTagSet.getInstance())) {
+        if (isPrimaryIFD &&
+            (ignoreMetadata ||
+             (!readUnknownTags &&
+              !tagSetList.contains(BaselineTIFFTagSet.getInstance())))) {
             ensureEssentialTags = true;
             initializeEssentialTags();
             baselineTagSet = BaselineTIFFTagSet.getInstance();
@@ -590,9 +596,12 @@
                 tag = baselineTagSet.getTag(tagNumber);
             }
 
-            // Ignore unknown fields, fields with unknown type, and fields
+            // Ignore non-essential fields, unknown fields unless forcibly
+            // being read, fields with unknown type, and fields
             // with count out of int range.
-            if((tag == null && ignoreUnknownFields)
+            if((ignoreMetadata &&
+                (!ensureEssentialTags || !essentialTags.contains(tagNumber)))
+                || (tag == null && !readUnknownTags)
                 || (tag != null && !tag.isDataTypeOK(type))
                 || longCount > Integer.MAX_VALUE) {
                 // Skip the value/offset so as to leave the stream
@@ -701,7 +710,8 @@
                     tagSets.add(tag.getTagSet());
                     TIFFIFD subIFD = new TIFFIFD(tagSets);
 
-                    subIFD.initialize(stream, false, ignoreUnknownFields);
+                    subIFD.initialize(stream, false, ignoreMetadata,
+                                      readUnknownTags);
                     TIFFField f = new TIFFField(tag, type, e.offset, subIFD);
                     addTIFFField(f);
                 } else {
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java	Mon Dec 19 16:05:38 2016 +0000
@@ -82,12 +82,13 @@
     }
 
     public void initializeFromStream(ImageInputStream stream,
-                                     boolean ignoreUnknownFields)
+                                     boolean ignoreMetadata,
+                                     boolean readUnknownTags)
         throws IOException {
-        rootIFD.initialize(stream, true, ignoreUnknownFields);
+        rootIFD.initialize(stream, true, ignoreMetadata, readUnknownTags);
     }
 
-    public void addShortOrLongField(int tagNumber, int value) {
+    public void addShortOrLongField(int tagNumber, long value) {
         TIFFField field = new TIFFField(rootIFD.getTag(tagNumber), value);
         rootIFD.addTIFFField(field);
     }
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java	Mon Dec 19 16:05:38 2016 +0000
@@ -305,16 +305,19 @@
         try {
             // Create an object to store the image metadata
             List<TIFFTagSet> tagSets;
+            boolean readUnknownTags = false;
             if (imageReadParam instanceof TIFFImageReadParam) {
-                tagSets
-                        = ((TIFFImageReadParam) imageReadParam).getAllowedTagSets();
+                TIFFImageReadParam tp = (TIFFImageReadParam)imageReadParam;
+                tagSets = tp.getAllowedTagSets();
+                readUnknownTags = tp.getReadUnknownTags();
             } else {
                 tagSets = new ArrayList<TIFFTagSet>(1);
                 tagSets.add(BaselineTIFFTagSet.getInstance());
             }
 
             this.imageMetadata = new TIFFImageMetadata(tagSets);
-            imageMetadata.initializeFromStream(stream, ignoreMetadata);
+            imageMetadata.initializeFromStream(stream, ignoreMetadata,
+                                               readUnknownTags);
         } catch (IIOException iioe) {
             throw iioe;
         } catch (IOException ioe) {
--- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java	Mon Dec 19 16:05:38 2016 +0000
@@ -3015,7 +3015,7 @@
         List<TIFFTagSet> tagSets = new ArrayList<TIFFTagSet>(1);
         tagSets.add(BaselineTIFFTagSet.getInstance());
         TIFFIFD rootIFD = new TIFFIFD(tagSets);
-        rootIFD.initialize(stream, true, true);
+        rootIFD.initialize(stream, true, false, false);
         stream.reset();
 
         return rootIFD;
--- a/jdk/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,18 +22,25 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
 import java.awt.peer.CheckboxMenuItemPeer;
-import java.awt.event.*;
-import java.util.EventListener;
-import java.io.ObjectOutputStream;
+import java.io.IOException;
 import java.io.ObjectInputStream;
-import java.io.IOException;
-import javax.accessibility.*;
+import java.io.ObjectOutputStream;
+import java.util.EventListener;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleAction;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleValue;
+
 import sun.awt.AWTAccessor;
 
-
 /**
  * This class represents a check box that can be included in a menu.
  * Selecting the check box in the menu changes its state from
@@ -43,7 +50,8 @@
  * of {@code CheckBoxMenuItem}:
  * <p>
  * <img src="doc-files/MenuBar-1.gif"
- * alt="Menu labeled Examples, containing items Basic, Simple, Check, and More Examples. The Check item is a CheckBoxMenuItem instance, in the off state."
+ * alt="Menu labeled Examples, containing items Basic, Simple, Check, and More
+ * Examples. The Check item is a CheckBoxMenuItem instance, in the off state."
  * style="float:center; margin: 7px 10px;">
  * <p>
  * The item labeled {@code Check} shows a check box menu item
@@ -84,9 +92,9 @@
     * @see #getState()
     * @see #setState(boolean)
     */
-    boolean state = false;
+    private volatile boolean state;
 
-    transient ItemListener itemListener;
+    private transient volatile ItemListener itemListener;
 
     private static final String base = "chkmenuitem";
     private static int nameCounter = 0;
--- a/jdk/src/java.desktop/share/classes/java/awt/Menu.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/Menu.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,15 +22,20 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
+import java.awt.event.KeyEvent;
+import java.awt.peer.MenuPeer;
 import java.io.IOException;
 import java.io.ObjectInputStream;
+import java.util.Enumeration;
 import java.util.Vector;
-import java.util.Enumeration;
-import java.awt.peer.MenuPeer;
-import java.awt.event.KeyEvent;
-import javax.accessibility.*;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+
 import sun.awt.AWTAccessor;
 
 /**
@@ -78,7 +83,7 @@
      * @serial
      * @see #countItems()
      */
-    Vector<MenuItem> items = new Vector<>();
+    private final Vector<MenuItem> items = new Vector<>();
 
     /**
      * This field indicates whether the menu has the
@@ -92,7 +97,7 @@
      * @serial
      * @see #isTearOff()
      */
-    boolean             tearOff;
+    private final boolean tearOff;
 
     /**
      * This field will be set to {@code true}
@@ -102,7 +107,7 @@
      *
      * @serial
      */
-    boolean             isHelpMenu;
+    volatile boolean isHelpMenu;
 
     private static final String base = "menu";
     private static int nameCounter = 0;
@@ -415,8 +420,8 @@
             if (peer != null) {
                 peer.delItem(index);
                 mi.removeNotify();
-                mi.parent = null;
             }
+            mi.parent = null;
         }
     }
 
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,16 +22,21 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
+import java.awt.event.KeyEvent;
+import java.awt.peer.MenuBarPeer;
 import java.io.IOException;
 import java.io.ObjectInputStream;
+import java.util.Enumeration;
 import java.util.Vector;
-import java.util.Enumeration;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+
 import sun.awt.AWTAccessor;
-import java.awt.peer.MenuBarPeer;
-import java.awt.event.KeyEvent;
-import javax.accessibility.*;
 
 /**
  * The {@code MenuBar} class encapsulates the platform's
@@ -94,7 +99,7 @@
      * @serial
      * @see #countMenus()
      */
-    Vector<Menu> menus = new Vector<>();
+    private final Vector<Menu> menus = new Vector<>();
 
     /**
      * This menu is a special menu dedicated to
@@ -106,7 +111,7 @@
      * @see #getHelpMenu()
      * @see #setHelpMenu(Menu)
      */
-    Menu helpMenu;
+    private volatile Menu helpMenu;
 
     private static final String base = "menubar";
     private static int nameCounter = 0;
@@ -252,8 +257,8 @@
             if (peer != null) {
                 peer.delMenu(index);
                 m.removeNotify();
-                m.parent = null;
             }
+            m.parent = null;
             if (helpMenu == m) {
                 helpMenu = null;
                 m.isHelpMenu = false;
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,21 +22,28 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
+import java.awt.event.ActionEvent;
 import java.awt.peer.MenuComponentPeer;
-import java.awt.event.ActionEvent;
 import java.io.IOException;
 import java.io.ObjectInputStream;
-import sun.awt.AppContext;
-import sun.awt.AWTAccessor;
-import sun.awt.ComponentFactory;
-
-import javax.accessibility.*;
-
 import java.security.AccessControlContext;
 import java.security.AccessController;
 
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleComponent;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleSelection;
+import javax.accessibility.AccessibleState;
+import javax.accessibility.AccessibleStateSet;
+
+import sun.awt.AWTAccessor;
+import sun.awt.AppContext;
+import sun.awt.ComponentFactory;
+
 /**
  * The abstract class {@code MenuComponent} is the superclass
  * of all menu-related components. In this respect, the class
@@ -60,13 +67,13 @@
     }
 
     transient volatile MenuComponentPeer peer;
-    transient MenuContainer parent;
+    transient volatile MenuContainer parent;
 
     /**
      * The {@code AppContext} of the {@code MenuComponent}.
      * This is set in the constructor and never changes.
      */
-    transient AppContext appContext;
+    private transient volatile AppContext appContext;
 
     /**
      * The menu component's font. This value can be
@@ -77,7 +84,7 @@
      * @see #setFont(Font)
      * @see #getFont()
      */
-    volatile Font font;
+    private volatile Font font;
 
     /**
      * The menu component's name, which defaults to {@code null}.
@@ -85,7 +92,7 @@
      * @see #getName()
      * @see #setName(String)
      */
-    private String name;
+    private volatile String name;
 
     /**
      * A variable to indicate whether a name is explicitly set.
@@ -94,14 +101,14 @@
      * @serial
      * @see #setName(String)
      */
-    private boolean nameExplicitlySet = false;
+    private volatile boolean nameExplicitlySet;
 
     /**
      * Defaults to {@code false}.
      * @serial
      * @see #dispatchEvent(AWTEvent)
      */
-    boolean newEventsOnly = false;
+    volatile boolean newEventsOnly;
 
     /*
      * The menu's AccessControlContext.
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -22,15 +22,25 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
+
 package java.awt;
 
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
 import java.awt.peer.MenuItemPeer;
-import java.awt.event.*;
-import java.util.EventListener;
+import java.io.IOException;
+import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
-import java.io.ObjectInputStream;
-import java.io.IOException;
-import javax.accessibility.*;
+import java.util.EventListener;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleAction;
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
+import javax.accessibility.AccessibleValue;
+
 import sun.awt.AWTAccessor;
 
 /**
@@ -111,7 +121,7 @@
      * @see #isEnabled()
      * @see #setEnabled(boolean)
      */
-    boolean enabled = true;
+    private volatile boolean enabled = true;
 
     /**
      * {@code label} is the label of a menu item.
@@ -121,7 +131,7 @@
      * @see #getLabel()
      * @see #setLabel(String)
      */
-    String label;
+    volatile String label;
 
     /**
      * This field indicates the command that has been issued
@@ -134,7 +144,7 @@
      * @see #setActionCommand(String)
      * @see #getActionCommand()
      */
-    String actionCommand;
+    private volatile String actionCommand;
 
     /**
      * The eventMask is ONLY set by subclasses via enableEvents.
@@ -144,9 +154,9 @@
      *
      * @serial
      */
-    long eventMask;
+    volatile long eventMask;
 
-    transient ActionListener actionListener;
+    private transient volatile ActionListener actionListener;
 
     /**
      * A sequence of key stokes that ia associated with
@@ -160,7 +170,7 @@
      * @see #setShortcut(MenuShortcut)
      * @see #deleteShortcut()
      */
-    private MenuShortcut shortcut = null;
+    private volatile MenuShortcut shortcut;
 
     private static final String base = "menuitem";
     private static int nameCounter = 0;
--- a/jdk/src/java.desktop/share/classes/java/awt/PopupMenu.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/PopupMenu.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -26,8 +26,9 @@
 package java.awt;
 
 import java.awt.peer.PopupMenuPeer;
-import javax.accessibility.*;
 
+import javax.accessibility.AccessibleContext;
+import javax.accessibility.AccessibleRole;
 
 import sun.awt.AWTAccessor;
 
@@ -48,7 +49,7 @@
     private static final String base = "popup";
     static int nameCounter = 0;
 
-    transient boolean isTrayIconPopup = false;
+    transient volatile boolean isTrayIconPopup;
 
     static {
         AWTAccessor.setPopupMenuAccessor(
--- a/jdk/src/java.desktop/share/classes/java/awt/Window.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/Window.java	Mon Dec 19 16:05:38 2016 +0000
@@ -4122,6 +4122,10 @@
             public void setTrayIconWindow(Window w, boolean isTrayIconWindow) {
                 w.isTrayIconWindow = isTrayIconWindow;
             }
+
+            public Window[] getOwnedWindows(Window w) {
+                return w.getOwnedWindows_NoClientCode();
+            }
         }); // WindowAccessor
     } // static
 
--- a/jdk/src/java.desktop/share/classes/java/awt/dnd/DragSourceContext.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/dnd/DragSourceContext.java	Mon Dec 19 16:05:38 2016 +0000
@@ -279,7 +279,7 @@
     }
 
     /**
-     * Sets the cursor for this drag operation to the specified
+     * Sets the custom cursor for this drag operation to the specified
      * {@code Cursor}.  If the specified {@code Cursor}
      * is {@code null}, the default drag cursor behavior is
      * activated for this drag operation, otherwise it is deactivated.
@@ -298,9 +298,11 @@
     }
 
     /**
-     * Returns the current drag {@code Cursor}.
+     * Returns the current custom drag {@code Cursor}.
      *
-     * @return the current drag {@code Cursor}
+     * @return the current custom drag {@code Cursor}, if it was set
+     *         otherwise returns {@code null}.
+     * @see #setCursor
      */
 
     public Cursor getCursor() { return cursor; }
--- a/jdk/src/java.desktop/share/classes/java/awt/image/AbstractMultiResolutionImage.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/java/awt/image/AbstractMultiResolutionImage.java	Mon Dec 19 16:05:38 2016 +0000
@@ -64,27 +64,71 @@
 public abstract class AbstractMultiResolutionImage extends java.awt.Image
         implements MultiResolutionImage {
 
+    /**
+     * This method simply delegates to the same method on the base image and
+     * it is equivalent to: {@code getBaseImage().getWidth(observer)}.
+     *
+     * @return the width of the base image, or -1 if the width is not yet known
+     * @see #getBaseImage()
+     *
+     * @since 9
+     */
     @Override
     public int getWidth(ImageObserver observer) {
         return getBaseImage().getWidth(observer);
     }
 
+    /**
+     * This method simply delegates to the same method on the base image and
+     * it is equivalent to: {@code getBaseImage().getHeight(observer)}.
+     *
+     * @return the height of the base image, or -1 if the height is not yet known
+     * @see #getBaseImage()
+     *
+     * @since 9
+     */
     @Override
     public int getHeight(ImageObserver observer) {
         return getBaseImage().getHeight(observer);
     }
 
+    /**
+     * This method simply delegates to the same method on the base image and
+     * it is equivalent to: {@code getBaseImage().getSource()}.
+     *
+     * @return the image producer that produces the pixels for the base image
+     * @see #getBaseImage()
+     *
+     * @since 9
+     */
     @Override
     public ImageProducer getSource() {
         return getBaseImage().getSource();
     }
 
+    /**
+     * As per the contract of the base {@code Image#getGraphics()} method,
+     * this implementation will always throw {@code UnsupportedOperationException}
+     * since only off-screen images can return a {@code Graphics} object.
+     *
+     * @return throws {@code UnsupportedOperationException}
+     * @throws UnsupportedOperationException this method is not supported
+     */
     @Override
     public Graphics getGraphics() {
         throw new UnsupportedOperationException("getGraphics() not supported"
                 + " on Multi-Resolution Images");
     }
 
+    /**
+     * This method simply delegates to the same method on the base image and
+     * it is equivalent to: {@code getBaseImage().getProperty(name, observer)}.
+     *
+     * @return the value of the named property in the base image
+     * @see #getBaseImage()
+     *
+     * @since 9
+     */
     @Override
     public Object getProperty(String name, ImageObserver observer) {
         return getBaseImage().getProperty(name, observer);
--- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html	Mon Dec 19 16:05:38 2016 +0000
@@ -216,22 +216,27 @@
 
 <h4><a name="MetadataIssuesRead"/>Metadata Issues</h4>
 
-By default all fields in the TIFF image file directory (IFD) are loaded into
-the native image metadata object. In cases where the IFD includes fields which
-contain large amounts of data this could be very inefficient. Which fields
-are loaded may be controlled by setting which TIFF tags the reader is allowed
-to recognize and whether it is ignoring metadata. The reader is informed to
-disregard metadata as usual via the <code>ignoreMetadata</code> parameter of
+By default all recognized fields in the TIFF image file directory (IFD) are
+loaded into the native image metadata object. Which fields are loaded may be
+controlled by setting which TIFF tags the reader is allowed to recognize,
+whether to read fields with unrecognized tags, and whether to ignore all
+metadata. The reader is informed to disregard all metadata as usual via the
+<code>ignoreMetadata</code> parameter of
 <code>ImageReader.setInput(Object,boolean,boolean)</code>. It is
 informed of which <a href="../../plugins/tiff/TIFFTag.html">TIFFTag</a>s to
 recognize or not to recognize via
-<code>TIFFImageReadParam.addAllowedTagSet(TIFFTagSet)</code>
-and
+<code>TIFFImageReadParam.addAllowedTagSet(TIFFTagSet)</code> and
 <code>TIFFImageReadParam.removeAllowedTagSet(TIFFTagSet)</code>.
-If <code>ignoreMetadata</code> is <code>true</code>, then the reader will
-load into the native image metadata object only those fields which have a
-<code>TIFFTag</code> contained in the one of the allowed
-<code>TIFFTagSet</code>s.
+If <code>ignoreMetadata</code> is <code>true</code>, then only metadata
+essential to reading the image will be loaded into the native image metadata
+object. If <code>ignoreMetadata</code> is <code>false</code>, then the reader
+will by default load into the native image metadata object only those fields
+which are either essential to reading the image or have a <code>TIFFTag</code>
+contained in the one of the allowed <code>TIFFTagSet</code>s. Reading of
+fields with tags not in the allowed <code>TIFFTagSet</code>s may be forced
+by passing in a <code>TIFFImageReadParam</code> on which
+<code>TIFFImageReadParam.setReadUnknownTags(boolean)</code> has been
+invoked with parameter <code>true</code>.
 
 <p>Use of a <a href="../../plugins/tiff/TIFFDirectory.html">TIFFDirectory</a>
 object may simplify gaining access to metadata values. An instance of
@@ -534,7 +539,7 @@
 <tr>
 <td>ZLib</td>
 <td>"Deflate/Inflate" compression (see note following this table)</td>
-<td><a href="http://partners.adobe.com/asn/developer/pdfs/tn/TIFFphotoshop.pdf">
+<td><a href="http://partners.adobe.com/public/developer/en/tiff/TIFFphotoshop.pdf">
 Adobe Photoshop&#174; TIFF Technical Notes</a> (PDF)</td>
 </tr>
 <tr>
@@ -545,9 +550,9 @@
 <tr>
 <td>Deflate</td>
 <td>"Zip-in-TIFF" compression (see note following this table)</td>
-<td><a href="http://www.isi.edu/in-notes/rfc1950.txt">
+<td><a href="https://tools.ietf.org/html/rfc1950">
 ZLIB Compressed Data Format Specification</a>,
-<a href="http://www.isi.edu/in-notes/rfc1951.txt">
+<a href="https://tools.ietf.org/html/rfc1951">
 DEFLATE Compressed Data Format Specification</a></td>
 </tr>
 <tr>
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java	Mon Dec 19 16:05:38 2016 +0000
@@ -224,7 +224,7 @@
      * A value to be used with the "Compression" tag.
      *
      * @see #TAG_COMPRESSION
-     * @see <a href="http://www.isi.edu/in-notes/rfc1951.txt">DEFLATE specification</a>
+     * @see <a href="https://tools.ietf.org/html/rfc1951">DEFLATE specification</a>
      * @see <a href="http://partners.adobe.com/public/developer/en/tiff/TIFFphotoshop.pdf"> TIFF Specification Supplement 2</a>
      */
     public static final int COMPRESSION_DEFLATE = 32946;
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java	Mon Dec 19 16:05:38 2016 +0000
@@ -29,7 +29,7 @@
 
 /**
  * A class representing the extra tags found in a
- * <a href="http://tools.ietf.org/html/rfc2306"> TIFF-F</a> (RFC 2036) file.
+ * <a href="http://tools.ietf.org/html/rfc2306.html">TIFF-F</a> (RFC 2036) file.
  *
  * @since 9
  */
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java	Mon Dec 19 16:05:38 2016 +0000
@@ -30,10 +30,7 @@
 /**
  * A class representing the tags found in a GeoTIFF IFD.  GeoTIFF is a
  * standard for annotating georeferenced or geocoded raster imagery.
- * The GeoTIFF specification may be found at <a
- * href="http://www.remotesensing.org/geotiff/spec/geotiffhome.html">
- * {@code http://www.remotesensing.org/geotiff/spec/geotiffhome.html}
- * </a>. This class does <i>not</i> handle the <i>GeoKey</i>s referenced
+ * This class does <i>not</i> handle the <i>GeoKey</i>s referenced
  * from a <i>GeoKeyDirectoryTag</i> as those are not TIFF tags per se.
  *
  * <p>The definitions of the data types referenced by the field
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java	Mon Dec 19 16:05:38 2016 +0000
@@ -263,14 +263,16 @@
  */
 public final class TIFFField implements Cloneable {
 
-    private static final String[] typeNames = {
+    private static final long MAX_UINT32 = 0xffffffffL;
+
+    private static final String[] TYPE_NAMES = {
         null,
         "Byte", "Ascii", "Short", "Long", "Rational",
         "SByte", "Undefined", "SShort", "SLong", "SRational",
         "Float", "Double", "IFDPointer"
     };
 
-    private static final boolean[] isIntegral = {
+    private static final boolean[] IS_INTEGRAL = {
         false,
         true, false, true, true, false,
         true, true, true, true, false,
@@ -544,6 +546,9 @@
      * @throws IllegalArgumentException if {@code data} is an instance of
      * a class incompatible with the specified type.
      * @throws IllegalArgumentException if the size of the data array is wrong.
+     * @throws IllegalArgumentException if the type of the data array is
+     * {@code TIFF_LONG}, {@code TIFF_RATIONAL}, or {@code TIFF_IFD_POINTER}
+     * and any of the elements is negative or greater than {@code 0xffffffff}.
      */
     public TIFFField(TIFFTag tag, int type, int count, Object data) {
         if(tag == null) {
@@ -587,15 +592,50 @@
         case TIFFTag.TIFF_LONG:
             isDataArrayCorrect = data instanceof long[]
                 && ((long[])data).length == count;
+            if (isDataArrayCorrect) {
+                for (long datum : (long[])data) {
+                    if (datum < 0) {
+                        throw new IllegalArgumentException
+                            ("Negative value supplied for TIFF_LONG");
+                    }
+                    if (datum > MAX_UINT32) {
+                        throw new IllegalArgumentException
+                            ("Too large value supplied for TIFF_LONG");
+                    }
+                }
+            }
             break;
         case TIFFTag.TIFF_IFD_POINTER:
             isDataArrayCorrect = data instanceof long[]
                 && ((long[])data).length == 1;
+            if (((long[])data)[0] < 0) {
+                throw new IllegalArgumentException
+                    ("Negative value supplied for TIFF_IFD_POINTER");
+            }
+            if (((long[])data)[0] > MAX_UINT32) {
+                throw new IllegalArgumentException
+                    ("Too large value supplied for TIFF_IFD_POINTER");
+            }
             break;
         case TIFFTag.TIFF_RATIONAL:
             isDataArrayCorrect = data instanceof long[][]
-                && ((long[][])data).length == count
-                && ((long[][])data)[0].length == 2;
+                && ((long[][])data).length == count;
+            if (isDataArrayCorrect) {
+                for (long[] datum : (long[][])data) {
+                    if (datum.length != 2) {
+                        isDataArrayCorrect = false;
+                        break;
+                    }
+                    if (datum[0] < 0 || datum[1] < 0) {
+                        throw new IllegalArgumentException
+                            ("Negative value supplied for TIFF_RATIONAL");
+                    }
+                    if (datum[0] > MAX_UINT32 || datum[1] > MAX_UINT32) {
+                        throw new IllegalArgumentException
+                            ("Too large value supplied for TIFF_RATIONAL");
+                    }
+                }
+            }
             break;
         case TIFFTag.TIFF_SSHORT:
             isDataArrayCorrect = data instanceof short[]
@@ -607,8 +647,15 @@
             break;
         case TIFFTag.TIFF_SRATIONAL:
             isDataArrayCorrect = data instanceof int[][]
-                && ((int[][])data).length == count
-                && ((int[][])data)[0].length == 2;
+                && ((int[][])data).length == count;
+            if (isDataArrayCorrect) {
+                for (int[] datum : (int[][])data) {
+                    if (datum.length != 2) {
+                        isDataArrayCorrect = false;
+                        break;
+                    }
+                }
+            }
             break;
         case TIFFTag.TIFF_FLOAT:
             isDataArrayCorrect = data instanceof float[]
@@ -658,27 +705,32 @@
 
     /**
      * Constructs a {@code TIFFField} with a single non-negative integral
-     * value.
-     * The field will have type
-     * {@link TIFFTag#TIFF_SHORT  TIFF_SHORT} if
-     * {@code val < 65536} and type
-     * {@link TIFFTag#TIFF_LONG TIFF_LONG} otherwise.  The count
-     * of the field will be unity.
+     * value. The field will have type {@link TIFFTag#TIFF_SHORT TIFF_SHORT}
+     * if {@code value} is in {@code [0,0xffff]}, and type
+     * {@link TIFFTag#TIFF_LONG TIFF_LONG} if {@code value} is in
+     * {@code [0x10000,0xffffffff]}. The count of the field will be unity.
      *
      * @param tag The tag to associate with this field.
      * @param value The value to associate with this field.
      * @throws NullPointerException if {@code tag == null}.
-     * @throws IllegalArgumentException if the derived type is unacceptable
-     * for the supplied {@code TIFFTag}.
-     * @throws IllegalArgumentException if {@code value < 0}.
+     * @throws IllegalArgumentException if {@code value} is not in
+     * {@code [0,0xffffffff]}.
+     * @throws IllegalArgumentException if {@code value} is in
+     * {@code [0,0xffff]} and {@code TIFF_SHORT} is an unacceptable type
+     * for the {@code TIFFTag}, or if {@code value} is in
+     * {@code [0x10000,0xffffffff]} and {@code TIFF_LONG} is an unacceptable
+     * type for the {@code TIFFTag}.
      */
-    public TIFFField(TIFFTag tag, int value) {
+    public TIFFField(TIFFTag tag, long value) {
         if(tag == null) {
             throw new NullPointerException("tag == null!");
         }
         if (value < 0) {
             throw new IllegalArgumentException("value < 0!");
         }
+        if (value > MAX_UINT32) {
+            throw new IllegalArgumentException("value > 0xffffffff!");
+        }
 
         this.tag = tag;
         this.tagNumber = tag.getNumber();
@@ -687,7 +739,8 @@
         if (value < 65536) {
             if (!tag.isDataTypeOK(TIFFTag.TIFF_SHORT)) {
                 throw new IllegalArgumentException("Illegal data type "
-                    + TIFFTag.TIFF_SHORT + " for " + tag.getName() + " tag");
+                    + getTypeName(TIFFTag.TIFF_SHORT) + " for tag "
+                    + "\"" + tag.getName() + "\"");
             }
             this.type = TIFFTag.TIFF_SHORT;
             char[] cdata = new char[1];
@@ -696,7 +749,8 @@
         } else {
             if (!tag.isDataTypeOK(TIFFTag.TIFF_LONG)) {
                 throw new IllegalArgumentException("Illegal data type "
-                    + TIFFTag.TIFF_LONG + " for " + tag.getName() + " tag");
+                    + getTypeName(TIFFTag.TIFF_LONG) + " for tag "
+                    + "\"" + tag.getName() + "\"");
             }
             this.type = TIFFTag.TIFF_LONG;
             long[] ldata = new long[1];
@@ -799,7 +853,7 @@
             throw new IllegalArgumentException("Unknown data type "+dataType);
         }
 
-        return typeNames[dataType];
+        return TYPE_NAMES[dataType];
     }
 
     /**
@@ -812,7 +866,7 @@
      */
     public static int getTypeByName(String typeName) {
         for (int i = TIFFTag.MIN_DATATYPE; i <= TIFFTag.MAX_DATATYPE; i++) {
-            if (typeName.equals(typeNames[i])) {
+            if (typeName.equals(TYPE_NAMES[i])) {
                 return i;
             }
         }
@@ -887,7 +941,7 @@
      * @return Whether the field type is integral.
      */
     public boolean isIntegral() {
-        return isIntegral[type];
+        return IS_INTEGRAL[type];
     }
 
     /**
--- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java	Mon Dec 19 16:05:38 2016 +0000
@@ -46,11 +46,18 @@
  * {@code ExifParentTIFFTagSet}, and {@code GeoTIFFTagSet}
  * are included.
  *
+ * <p> Forcing reading of fields corresponding to {@code TIFFTag}s
+ * not in any of the allowed {@code TIFFTagSet}s may be effected via
+ * {@link #setReadUnknownTags setReadUnknownTags}.
+ *
  * @since 9
  */
 public final class TIFFImageReadParam extends ImageReadParam {
 
-    private List<TIFFTagSet> allowedTagSets = new ArrayList<TIFFTagSet>(4);
+    private final List<TIFFTagSet> allowedTagSets =
+        new ArrayList<TIFFTagSet>(4);
+
+    private boolean readUnknownTags = false;
 
     /**
      * Constructs a {@code TIFFImageReadParam}.  Tags defined by
@@ -72,7 +79,8 @@
 
     /**
      * Adds a {@code TIFFTagSet} object to the list of allowed
-     * tag sets.
+     * tag sets.  Attempting to add a duplicate object to the list
+     * has no effect.
      *
      * @param tagSet a {@code TIFFTagSet}.
      *
@@ -83,7 +91,9 @@
         if (tagSet == null) {
             throw new IllegalArgumentException("tagSet == null!");
         }
-        allowedTagSets.add(tagSet);
+        if (!allowedTagSets.contains(tagSet)) {
+            allowedTagSets.add(tagSet);
+        }
     }
 
     /**
@@ -113,4 +123,27 @@
     public List<TIFFTagSet> getAllowedTagSets() {
         return allowedTagSets;
     }
+
+    /**
+     * Set whether to read fields corresponding to {@code TIFFTag}s not in
+     * the allowed {@code TIFFTagSet}s. The default setting is {@code false}.
+     * If the TIFF {@code ImageReader} is ignoring metadata, then a setting
+     * of {@code true} is overridden as all metadata are ignored except those
+     * essential to reading the image itself.
+     *
+     * @param readUnknownTags Whether to read fields of unrecognized tags
+     */
+    public void setReadUnknownTags(boolean readUnknownTags) {
+        this.readUnknownTags = readUnknownTags;
+    }
+
+    /**
+     * Retrieve the setting of whether to read fields corresponding to unknown
+     * {@code TIFFTag}s.
+     *
+     * @return Whether to read fields of unrecognized tags
+     */
+    public boolean getReadUnknownTags() {
+        return readUnknownTags;
+    }
 }
--- a/jdk/src/java.desktop/share/classes/javax/swing/DefaultRowSorter.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/DefaultRowSorter.java	Mon Dec 19 16:05:38 2016 +0000
@@ -182,6 +182,8 @@
      */
     private int modelRowCount;
 
+    // Whether to print warning about JDK-8160087
+    private static boolean warning8160087 = true;
 
     /**
      * Creates an empty <code>DefaultRowSorter</code>.
@@ -489,10 +491,7 @@
      */
     public int convertRowIndexToView(int index) {
         if (modelToView == null) {
-            if (index < 0 || index >= modelRowCount) {
-                throw new IndexOutOfBoundsException("Invalid index");
-            }
-            return index;
+            return convertUnsortedUnfiltered(index);
         }
         return modelToView[index];
     }
@@ -504,14 +503,30 @@
      */
     public int convertRowIndexToModel(int index) {
         if (viewToModel == null) {
-            if (index < 0 || index >= modelRowCount) {
-                throw new IndexOutOfBoundsException("Invalid index");
-            }
-            return index;
+            return convertUnsortedUnfiltered(index);
         }
         return viewToModel[index].modelIndex;
     }
 
+    private int convertUnsortedUnfiltered(int index) {
+        if (index < 0 || index >= modelRowCount) {
+            if(index >= modelRowCount &&
+                                      index < getModelWrapper().getRowCount()) {
+                // 8160087
+                if(warning8160087) {
+                    warning8160087 = false;
+                    System.err.println("WARNING: row index is bigger than " +
+                            "sorter's row count. Most likely this is a wrong " +
+                            "sorter usage.");
+                }
+            } else {
+                throw new IndexOutOfBoundsException("Invalid index");
+            }
+        }
+        return index;
+    }
+
+
     private boolean isUnsorted() {
         List<? extends SortKey> keys = getSortKeys();
         int keySize = keys.size();
--- a/jdk/src/java.desktop/share/classes/javax/swing/JMenuBar.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JMenuBar.java	Mon Dec 19 16:05:38 2016 +0000
@@ -27,6 +27,7 @@
 import java.awt.Component;
 import java.awt.Graphics;
 import java.awt.Insets;
+import java.awt.Toolkit;
 import java.awt.event.*;
 import java.beans.JavaBean;
 import java.beans.BeanProperty;
@@ -41,6 +42,8 @@
 import javax.swing.plaf.*;
 import javax.accessibility.*;
 
+import sun.awt.SunToolkit;
+
 /**
  * An implementation of a menu bar. You add <code>JMenu</code> objects to the
  * menu bar to construct a menu. When the user selects a <code>JMenu</code>
@@ -144,6 +147,10 @@
      * @see JComponent#updateUI
      */
     public void updateUI() {
+        Toolkit tk = Toolkit.getDefaultToolkit();
+        if (tk instanceof SunToolkit) {
+            ((SunToolkit)tk).updateScreenMenuBarUI();
+        }
         setUI((MenuBarUI)UIManager.getUI(this));
     }
 
--- a/jdk/src/java.desktop/share/classes/javax/swing/JViewport.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JViewport.java	Mon Dec 19 16:05:38 2016 +0000
@@ -47,6 +47,7 @@
 import java.util.Collections;
 
 import sun.awt.AWTAccessor;
+import sun.swing.SwingUtilities2;
 
 /**
  * The "viewport" or "porthole" through which you see the underlying
@@ -1034,9 +1035,16 @@
     private boolean isBlitting() {
         Component view = getView();
         return (scrollMode == BLIT_SCROLL_MODE) &&
-               (view instanceof JComponent) && view.isOpaque();
+               (view instanceof JComponent) && view.isOpaque() && !isFPScale();
     }
 
+    private boolean isFPScale() {
+        GraphicsConfiguration gc = getGraphicsConfiguration();
+        if (gc != null) {
+            return SwingUtilities2.isFloatingPointScale(gc.getDefaultTransform());
+        }
+        return false;
+    }
 
     /**
      * Returns the <code>JViewport</code>'s one child or <code>null</code>.
--- a/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java	Mon Dec 19 16:05:38 2016 +0000
@@ -45,7 +45,11 @@
 import sun.security.action.GetPropertyAction;
 
 import com.sun.java.swing.SwingUtilities3;
+import java.awt.geom.AffineTransform;
+import sun.java2d.SunGraphics2D;
+import sun.java2d.pipe.Region;
 import sun.swing.SwingAccessor;
+import sun.swing.SwingUtilities2;
 import sun.swing.SwingUtilities2.RepaintListener;
 
 /**
@@ -1517,9 +1521,12 @@
             // standard Image buffer.
             boolean paintCompleted = false;
             Image offscreen;
+            int sw = w + 1;
+            int sh = h + 1;
+
             if (repaintManager.useVolatileDoubleBuffer() &&
                 (offscreen = getValidImage(repaintManager.
-                getVolatileOffscreenBuffer(bufferComponent, w, h))) != null) {
+                getVolatileOffscreenBuffer(bufferComponent, sw, sh))) != null) {
                 VolatileImage vImage = (java.awt.image.VolatileImage)offscreen;
                 GraphicsConfiguration gc = bufferComponent.
                                             getGraphicsConfiguration();
@@ -1529,7 +1536,7 @@
                                    VolatileImage.IMAGE_INCOMPATIBLE) {
                         repaintManager.resetVolatileDoubleBuffer(gc);
                         offscreen = repaintManager.getVolatileOffscreenBuffer(
-                            bufferComponent,w, h);
+                            bufferComponent, sw, sh);
                         vImage = (java.awt.image.VolatileImage)offscreen;
                     }
                     paintDoubleBuffered(paintingComponent, vImage, g, x, y,
@@ -1589,8 +1596,18 @@
          * Paints a portion of a component to an offscreen buffer.
          */
         protected void paintDoubleBuffered(JComponent c, Image image,
-                            Graphics g, int clipX, int clipY,
-                            int clipW, int clipH) {
+                Graphics g, int clipX, int clipY,
+                int clipW, int clipH) {
+            if (image instanceof VolatileImage && isPixelsCopying(c, g)) {
+                paintDoubleBufferedFPScales(c, image, g, clipX, clipY, clipW, clipH);
+            } else {
+                paintDoubleBufferedImpl(c, image, g, clipX, clipY, clipW, clipH);
+            }
+        }
+
+        private void paintDoubleBufferedImpl(JComponent c, Image image,
+                                             Graphics g, int clipX, int clipY,
+                                             int clipW, int clipH) {
             Graphics osg = image.getGraphics();
             int bw = Math.min(clipW, image.getWidth(null));
             int bh = Math.min(clipH, image.getHeight(null));
@@ -1629,6 +1646,76 @@
             }
         }
 
+        private void paintDoubleBufferedFPScales(JComponent c, Image image,
+                                                 Graphics g, int clipX, int clipY,
+                                                 int clipW, int clipH) {
+            Graphics osg = image.getGraphics();
+            Graphics2D g2d = (Graphics2D) g;
+            Graphics2D osg2d = (Graphics2D) osg;
+
+            AffineTransform identity = new AffineTransform();
+            int bw = Math.min(clipW, image.getWidth(null));
+            int bh = Math.min(clipH, image.getHeight(null));
+            int x, y, maxx, maxy;
+
+            AffineTransform tx = g2d.getTransform();
+            double scaleX = tx.getScaleX();
+            double scaleY = tx.getScaleY();
+            double trX = tx.getTranslateX();
+            double trY = tx.getTranslateY();
+
+            boolean translucent = volatileBufferType != Transparency.OPAQUE;
+            Composite oldComposite = g2d.getComposite();
+
+            try {
+                for (x = clipX, maxx = clipX + clipW; x < maxx; x += bw) {
+                    for (y = clipY, maxy = clipY + clipH; y < maxy; y += bh) {
+
+                        // draw x, y, bw, bh
+                        int pixelx1 = Region.clipRound(x * scaleX + trX);
+                        int pixely1 = Region.clipRound(y * scaleY + trY);
+                        int pixelx2 = Region.clipRound((x + bw) * scaleX + trX);
+                        int pixely2 = Region.clipRound((y + bh) * scaleY + trY);
+                        int pixelw = pixelx2 - pixelx1;
+                        int pixelh = pixely2 - pixely1;
+
+                        osg2d.setTransform(identity);
+                        if (translucent) {
+                            final Color oldBg = g2d.getBackground();
+                            g2d.setBackground(c.getBackground());
+                            g2d.clearRect(pixelx1, pixely1, pixelw, pixelh);
+                            g2d.setBackground(oldBg);
+                        }
+
+                        osg2d.setClip(0, 0, pixelw, pixelh);
+                        osg2d.translate(trX - pixelx1, trY - pixely1);
+                        osg2d.scale(scaleX, scaleY);
+                        c.paintToOffscreen(osg, x, y, bw, bh, maxx, maxy);
+
+                        g2d.setTransform(identity);
+                        g2d.setClip(pixelx1, pixely1, pixelw, pixelh);
+                        AffineTransform stx = new AffineTransform();
+                        stx.translate(pixelx1, pixely1);
+                        stx.scale(scaleX, scaleY);
+                        g2d.setTransform(stx);
+
+                        if (translucent) {
+                            g2d.setComposite(AlphaComposite.Src);
+                        }
+
+                        g2d.drawImage(image, 0, 0, c);
+
+                        if (translucent) {
+                            g2d.setComposite(oldComposite);
+                        }
+                        g2d.setTransform(tx);
+                    }
+                }
+            } finally {
+                osg.dispose();
+            }
+        }
+
         /**
          * If <code>image</code> is non-null with a positive size it
          * is returned, otherwise null is returned.
@@ -1671,9 +1758,33 @@
          */
         protected void dispose() {
         }
+
+        private boolean isPixelsCopying(JComponent c, Graphics g) {
+
+            AffineTransform tx = getTransform(g);
+            GraphicsConfiguration gc = c.getGraphicsConfiguration();
+
+            if (tx == null || gc == null
+                    || !SwingUtilities2.isFloatingPointScale(tx)) {
+                return false;
+            }
+
+            AffineTransform gcTx = gc.getDefaultTransform();
+
+            return gcTx.getScaleX() == tx.getScaleX()
+                    && gcTx.getScaleY() == tx.getScaleY();
+        }
+
+        private static AffineTransform getTransform(Graphics g) {
+            if (g instanceof SunGraphics2D) {
+                return ((SunGraphics2D) g).transform;
+            } else if (g instanceof Graphics2D) {
+                return ((Graphics2D) g).getTransform();
+            }
+            return null;
+        }
     }
 
-
     private class DoubleBufferInfo {
         public Image image;
         public Dimension size;
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java	Mon Dec 19 16:05:38 2016 +0000
@@ -571,7 +571,9 @@
 
     /**
      * Obsolete class, not used in this version.
+     * @deprecated As of JDK version 9. Obsolete class.
      */
+    @Deprecated(since = "9")
     protected class SingleClickListener extends MouseAdapter {
         /**
          * Constructs an instance of {@code SingleClickListener}.
@@ -584,7 +586,9 @@
 
     /**
      * Obsolete class, not used in this version.
+     * @deprecated As of JDK version 9. Obsolete class.
      */
+    @Deprecated(since = "9")
     @SuppressWarnings("serial") // Superclass is not serializable across versions
     protected class FileRenderer extends DefaultListCellRenderer  {
     }
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java	Mon Dec 19 16:05:38 2016 +0000
@@ -26,6 +26,7 @@
 
 import java.awt.*;
 import java.awt.font.FontRenderContext;
+import java.awt.geom.Rectangle2D;
 import java.lang.ref.SoftReference;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -750,7 +751,6 @@
          *   valid location in the associated document
          * @see View#modelToView
          */
-        @SuppressWarnings("deprecation")
         public Shape modelToView(int pos, Shape a, Position.Bias b)
                 throws BadLocationException {
             Rectangle alloc = a.getBounds();
@@ -777,9 +777,11 @@
             if (pos > p0) {
                 Segment segment = SegmentCache.getSharedSegment();
                 loadText(segment, p0, pos);
-                alloc.x += Utilities.getTabbedTextWidth(segment, metrics,
-                        alloc.x, WrappedPlainView.this, p0);
+                float x = alloc.x;
+                x += Utilities.getTabbedTextWidth(segment, metrics, x,
+                                                  WrappedPlainView.this, p0);
                 SegmentCache.releaseSharedSegment(segment);
+                return new Rectangle2D.Float(x, alloc.y, alloc.width, alloc.height);
             }
             return alloc;
         }
--- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java	Mon Dec 19 16:05:38 2016 +0000
@@ -360,6 +360,12 @@
          * Marks the specified window as an utility window for TrayIcon.
          */
         void setTrayIconWindow(Window w, boolean isTrayIconWindow);
+
+        /**
+         * Return an array containing all the windows this
+         * window currently owns.
+         */
+        Window[] getOwnedWindows(Window w);
     }
 
     /**
--- a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1857,6 +1857,9 @@
         return time == null ? -1 : time;
     }
 
+    public void updateScreenMenuBarUI() {
+    }
+
     // Cosntant alpha
     public boolean isWindowOpacitySupported() {
         return false;
--- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java	Mon Dec 19 16:05:38 2016 +0000
@@ -3101,10 +3101,10 @@
             if (scaleX == 1 && scaleY == 1) {
                 return null;
             }
-            sx1 = Region.clipScale(sx1, scaleX);
-            sx2 = Region.clipScale(sx2, scaleX);
-            sy1 = Region.clipScale(sy1, scaleY);
-            sy2 = Region.clipScale(sy2, scaleY);
+            sx1 = Region.clipRound(sx1 * scaleX);
+            sx2 = Region.clipRound(sx2 * scaleX);
+            sy1 = Region.clipRound(sy1 * scaleY);
+            sy2 = Region.clipRound(sy2 * scaleY);
 
             AffineTransform tx = null;
             if (xform != null) {
--- a/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java	Mon Dec 19 16:05:38 2016 +0000
@@ -305,6 +305,12 @@
             int startY = (int)Math.floor(y * scaleY);
             int width  = (int)Math.ceil((x + w) * scaleX) - startX;
             int height = (int)Math.ceil((y + h) * scaleY) - startY;
+            if (startX + width > linestride) {
+                width = linestride - startX;
+            }
+            if (startY + height > bbImage.getHeight()) {
+                height = bbImage.getHeight() - startY;
+            }
 
             for (int i = 0; i < height; i++) {
                 int from = (startY + i) * linestride + startX;
--- a/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java	Mon Dec 19 16:05:38 2016 +0000
@@ -33,6 +33,7 @@
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.AffineTransform;
 import static java.awt.geom.AffineTransform.TYPE_FLIP;
+import static java.awt.geom.AffineTransform.TYPE_MASK_SCALE;
 import static java.awt.geom.AffineTransform.TYPE_TRANSLATION;
 import java.awt.print.PrinterGraphics;
 import java.text.BreakIterator;
@@ -2162,6 +2163,19 @@
         return false;
     }
 
+    public static boolean isFloatingPointScale(AffineTransform tx) {
+        int type = tx.getType() & ~(TYPE_FLIP | TYPE_TRANSLATION);
+        if (type == 0) {
+            return false;
+        } else if ((type & ~TYPE_MASK_SCALE) == 0) {
+            double scaleX = tx.getScaleX();
+            double scaleY = tx.getScaleY();
+            return (scaleX != (int) scaleX) || (scaleY != (int) scaleY);
+        } else {
+            return false;
+        }
+    }
+
     /**
      * Returns the client property for the given key if it is set; otherwise
      * returns the {@L&F} property.
--- a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c	Mon Dec 19 16:05:38 2016 +0000
@@ -140,7 +140,7 @@
         indices[storei] = baseIndex + cluster;
         glyphs[storei] = (unsigned int)(glyphInfo[i].codepoint | slot);
         positions[storei*2] = startX + x + glyphPos[i].x_offset * scale;
-        positions[(storei*2)+1] = startY + y + glyphPos[i].y_offset * scale;
+        positions[(storei*2)+1] = startY + y - glyphPos[i].y_offset * scale;
         x += glyphPos[i].x_advance * scale;
         y += glyphPos[i].y_advance * scale;
         storei++;
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XContentWindow.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XContentWindow.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -123,15 +123,26 @@
             // Change in the size of the content window means, well, change of the size
             // Change in the location of the content window means change in insets
             boolean needHandleResize = !(newBounds.equals(getBounds()));
+            boolean needPaint = width <= 0 || height <= 0;
             reshape(newBounds);
             if (needHandleResize) {
                 insLog.fine("Sending RESIZED");
                 handleResize(newBounds);
             }
+            if (needPaint) {
+                postPaintEvent(target, 0, 0, newBounds.width, newBounds.height);
+            }
         } finally {
             XToolkit.awtUnlock();
         }
-        validateSurface();
+    }
+
+    @Override
+    public void handleExposeEvent(XEvent xev) {
+        if (width <= 0 || height <= 0) {
+            return;
+        }
+        super.handleExposeEvent(xev);
     }
 
     // NOTE: This method may be called by privileged threads.
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp	Mon Dec 19 16:05:38 2016 +0000
@@ -251,7 +251,8 @@
     m_bPauseDestroy = FALSE;
 
     m_MessagesProcessing = 0;
-    m_wheelRotationAmount = 0;
+    m_wheelRotationAmountX = 0;
+    m_wheelRotationAmountY = 0;
     if (!sm_PrimaryDynamicTableBuilt) {
         // do it once.
         AwtComponent::BuildPrimaryDynamicTable();
@@ -1208,6 +1209,7 @@
         WIN_MSG(WM_XBUTTONDOWN)
         WIN_MSG(WM_XBUTTONUP)
         WIN_MSG(WM_MOUSEWHEEL)
+        WIN_MSG(WM_MOUSEHWHEEL)
         WIN_MSG(WM_PARENTNOTIFY)
         WIN_MSG(WM_ENTERMENULOOP)
         WIN_MSG(WM_EXITMENULOOP)
@@ -1639,6 +1641,7 @@
       case WM_XBUTTONUP:
       case WM_MOUSEMOVE:
       case WM_MOUSEWHEEL:
+      case WM_MOUSEHWHEEL:
       case WM_AWT_MOUSEENTER:
       case WM_AWT_MOUSEEXIT:
           curPos = ::GetMessagePos();
@@ -1708,10 +1711,12 @@
           case WM_AWT_MOUSEEXIT:
               mr = WmMouseExit(static_cast<UINT>(wParam), myPos.x, myPos.y);
               break;
-          case  WM_MOUSEWHEEL:
+          case WM_MOUSEWHEEL:
+          case WM_MOUSEHWHEEL:
               mr = WmMouseWheel(GET_KEYSTATE_WPARAM(wParam),
                                 GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
-                                GET_WHEEL_DELTA_WPARAM(wParam));
+                                GET_WHEEL_DELTA_WPARAM(wParam),
+                                switchMessage == WM_MOUSEHWHEEL);
               break;
           }
           break;
@@ -2078,13 +2083,15 @@
 
 MsgRouting AwtComponent::WmSetFocus(HWND hWndLostFocus)
 {
-    m_wheelRotationAmount = 0;
+    m_wheelRotationAmountX = 0;
+    m_wheelRotationAmountY = 0;
     return mrDoDefault;
 }
 
 MsgRouting AwtComponent::WmKillFocus(HWND hWndGotFocus)
 {
-    m_wheelRotationAmount = 0;
+    m_wheelRotationAmountX = 0;
+    m_wheelRotationAmountY = 0;
     return mrDoDefault;
 }
 
@@ -2461,7 +2468,7 @@
 }
 
 MsgRouting AwtComponent::WmMouseWheel(UINT flags, int x, int y,
-                                      int wheelRotation)
+                                      int wheelRotation, BOOL isHorizontal)
 {
     // convert coordinates to be Component-relative, not screen relative
     // for wheeling when outside the window, this works similar to
@@ -2475,42 +2482,54 @@
 
     // set some defaults
     jint scrollType = java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL;
-    jint scrollLines = 3;
+    jint scrollUnits = 3;
 
     BOOL result;
-    UINT platformLines;
-
-    m_wheelRotationAmount += wheelRotation;
+    UINT platformUnits;
+    jint roundedWheelRotation;
+    jdouble preciseWheelRotation;
 
     // AWT interprets wheel rotation differently than win32, so we need to
     // decode wheel amount.
-    jint roundedWheelRotation = m_wheelRotationAmount / (-1 * WHEEL_DELTA);
-    jdouble preciseWheelRotation = (jdouble) wheelRotation / (-1 * WHEEL_DELTA);
+    jint modifiers = GetJavaModifiers();
+    if (isHorizontal) {
+        modifiers |= java_awt_event_InputEvent_SHIFT_DOWN_MASK;
+        m_wheelRotationAmountX += wheelRotation;
+        roundedWheelRotation = m_wheelRotationAmountX / (WHEEL_DELTA);
+        preciseWheelRotation = (jdouble) wheelRotation / (WHEEL_DELTA);
+        result = ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
+                                        &platformUnits, 0);
+    } else {
+        m_wheelRotationAmountY += wheelRotation;
+        roundedWheelRotation = m_wheelRotationAmountY / (-1 * WHEEL_DELTA);
+        preciseWheelRotation = (jdouble) wheelRotation / (-1 * WHEEL_DELTA);
+        result = ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
+                                        &platformUnits, 0);
+    }
 
     MSG msg;
-    result = ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
-                                    &platformLines, 0);
     InitMessage(&msg, lastMessage, MAKEWPARAM(flags, wheelRotation),
                 MAKELPARAM(x, y));
 
     if (result) {
-        if (platformLines == WHEEL_PAGESCROLL) {
+        if (platformUnits == WHEEL_PAGESCROLL) {
             scrollType = java_awt_event_MouseWheelEvent_WHEEL_BLOCK_SCROLL;
-            scrollLines = 1;
+            scrollUnits = 1;
         }
         else {
             scrollType = java_awt_event_MouseWheelEvent_WHEEL_UNIT_SCROLL;
-            scrollLines = platformLines;
+            scrollUnits = platformUnits;
         }
     }
 
     DTRACE_PRINTLN("calling SendMouseWheelEvent");
 
     SendMouseWheelEvent(java_awt_event_MouseEvent_MOUSE_WHEEL, ::JVM_CurrentTimeMillis(NULL, 0),
-                        eventPt.x, eventPt.y, GetJavaModifiers(), 0, 0, scrollType,
-                        scrollLines, roundedWheelRotation, preciseWheelRotation, &msg);
-
-    m_wheelRotationAmount %= WHEEL_DELTA;
+                        eventPt.x, eventPt.y, modifiers, 0, 0, scrollType,
+                        scrollUnits, roundedWheelRotation, preciseWheelRotation, &msg);
+
+    m_wheelRotationAmountX %= WHEEL_DELTA;
+    m_wheelRotationAmountY %= WHEEL_DELTA;
     // this message could be propagated up to the parent chain
     // by the mouse message post processors
     return mrConsume;
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h	Mon Dec 19 16:05:38 2016 +0000
@@ -522,7 +522,7 @@
     virtual MsgRouting WmMouseMove(UINT flags, int x, int y);
     virtual MsgRouting WmMouseExit(UINT flags, int x, int y);
     virtual MsgRouting WmMouseWheel(UINT flags, int x, int y,
-                                    int wheelRotation);
+                                    int wheelRotation, BOOL isHorizontal);
     virtual MsgRouting WmNcMouseDown(WPARAM hitTest, int x, int y, int button);
     virtual MsgRouting WmNcMouseUp(WPARAM hitTest, int x, int y, int button);
     virtual MsgRouting WmWindowPosChanging(LPARAM windowPos);
@@ -824,7 +824,8 @@
     int windowMoveLockPosCY;
 
     // 6524352: support finer-resolution
-    int m_wheelRotationAmount;
+    int m_wheelRotationAmountX;
+    int m_wheelRotationAmountY;
 
     BOOL deadKeyActive;
 
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Dialog.cpp	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Dialog.cpp	Mon Dec 19 16:05:38 2016 +0000
@@ -240,6 +240,7 @@
             (wParam == WM_RBUTTONDOWN) ||
             (wParam == WM_MOUSEACTIVATE) ||
             (wParam == WM_MOUSEWHEEL) ||
+            (wParam == WM_MOUSEHWHEEL) ||
             (wParam == WM_NCLBUTTONDOWN) ||
             (wParam == WM_NCMBUTTONDOWN) ||
             (wParam == WM_NCRBUTTONDOWN))
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp	Mon Dec 19 16:05:38 2016 +0000
@@ -484,7 +484,10 @@
             if (fgProcessID != ::GetCurrentProcessId()) {
                 AwtWindow* window = (AwtWindow*)GetComponent(GetHWnd());
 
-                if (window != NULL && window->IsFocusableWindow() && window->IsAutoRequestFocus() &&
+                if (window != NULL &&
+                    window->IsFocusableWindow() &&
+                    window->IsAutoRequestFocus() &&
+                    !::IsWindowVisible(GetHWnd()) && // the window is really showing
                     !::IsWindow(GetModalBlocker(GetHWnd())))
                 {
                     // When the Java process is not allowed to set the foreground window
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp	Mon Dec 19 16:05:38 2016 +0000
@@ -1590,7 +1590,7 @@
      * the mouse, not the Component with the input focus.
      */
 
-    if (msg.message == WM_MOUSEWHEEL) {
+    if (msg.message == WM_MOUSEWHEEL || msg.message == WM_MOUSEHWHEEL) {
             //i.e. mouse is over client area for this window
             DWORD hWndForWheelProcess;
             DWORD hWndForWheelThread = ::GetWindowThreadProcessId(hWndForWheel, &hWndForWheelProcess);
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awtmsg.h	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awtmsg.h	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -45,6 +45,10 @@
 #define WM_MOUSEWHEEL                   0x020A
 #endif //WM_MOUSEWHEEL
 
+#ifndef WM_MOUSEHWHEEL
+#define WM_MOUSEHWHEEL                  0x020E
+#endif //WM_MOUSEHWHEEL
+
 #ifndef WHEEL_DELTA
 #define WHEEL_DELTA                     120
 #endif //WHEEL_DELTA
@@ -54,12 +58,16 @@
 #endif //WHEEL_PAGESCROLL
 
 #ifndef SPI_GETWHEELSCROLLLINES
-#define SPI_GETWHEELSCROLLLINES         104
+#define SPI_GETWHEELSCROLLLINES         0x0068
 #endif //SPI_GETWHEELSCROLLLINES
 
+#ifndef SPI_GETWHEELSCROLLCHARS
+#define SPI_GETWHEELSCROLLCHARS         0x006C
+#endif //SPI_GETWHEELSCROLLCHARS
+
 #ifndef SM_MOUSEWHEELPRESENT
 #define SM_MOUSEWHEELPRESENT            75
-#endif //SPI_GETWHEELSCROLLLINES
+#endif //SM_MOUSEWHEELPRESENT
 
 #ifndef COLOR_HOTLIGHT
 #define COLOR_HOTLIGHT                  26
--- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Connections.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Connections.java	Mon Dec 19 16:05:38 2016 +0000
@@ -27,7 +27,6 @@
 
 import java.util.ArrayList; // JDK 1.2
 import java.util.List;
-import java.util.Iterator;
 
 import java.lang.ref.Reference;
 import java.lang.ref.SoftReference;
@@ -290,23 +289,28 @@
      * @param threshold an entry idle since this time has expired.
      * @return true if no more connections in list
      */
-    synchronized boolean expire(long threshold) {
-        Iterator<ConnectionDesc> iter = conns.iterator();
-        ConnectionDesc entry;
-        while (iter.hasNext()) {
-            entry = iter.next();
+    boolean expire(long threshold) {
+        List<ConnectionDesc> clonedConns;
+        synchronized(this) {
+            clonedConns = new ArrayList<>(conns);
+        }
+        List<ConnectionDesc> expired = new ArrayList<>();
+
+        for (ConnectionDesc entry : clonedConns) {
+            d("expire(): ", entry);
             if (entry.expire(threshold)) {
-                d("expire(): removing ", entry);
-                td("Expired ", entry);
-
-                iter.remove();  // remove from pool
-
-                // Don't need to call notify() because we're
-                // removing only idle connections. If there were
-                // idle connections, then there should be no waiters.
+                expired.add(entry);
+                td("expire(): Expired ", entry);
             }
         }
-        return conns.isEmpty();  // whether whole list has 'expired'
+
+        synchronized (this) {
+            conns.removeAll(expired);
+            // Don't need to call notify() because we're
+            // removing only idle connections. If there were
+            // idle connections, then there should be no waiters.
+            return conns.isEmpty();  // whether whole list has 'expired'
+        }
     }
 
     /**
--- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Pool.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool/Pool.java	Mon Dec 19 16:05:38 2016 +0000
@@ -25,11 +25,11 @@
 
 package com.sun.jndi.ldap.pool;
 
+import java.util.ArrayList;
 import java.util.Map;
 import java.util.WeakHashMap;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.LinkedList;
 
 import java.io.PrintStream;
@@ -166,17 +166,25 @@
      *          and removed.
      */
     public void expire(long threshold) {
+        Collection<ConnectionsRef> copy;
         synchronized (map) {
-            Iterator<ConnectionsRef> iter = map.values().iterator();
-            Connections conns;
-            while (iter.hasNext()) {
-                conns = iter.next().getConnections();
-                if (conns.expire(threshold)) {
-                    d("expire(): removing ", conns);
-                    iter.remove();
-                }
+            copy = new ArrayList<>(map.values());
+        }
+
+        ArrayList<ConnectionsRef> removed = new ArrayList<>();
+        Connections conns;
+        for (ConnectionsRef ref : copy) {
+            conns = ref.getConnections();
+            if (conns.expire(threshold)) {
+                d("expire(): removing ", conns);
+                removed.add(ref);
             }
         }
+
+        synchronized (map) {
+            map.values().removeAll(removed);
+        }
+
         expungeStaleConnections();
     }
 
--- a/jdk/src/java.sql/share/classes/java/sql/DriverManager.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/java.sql/share/classes/java/sql/DriverManager.java	Mon Dec 19 16:05:38 2016 +0000
@@ -41,46 +41,41 @@
 
 
 /**
- * <P>The basic service for managing a set of JDBC drivers.<br>
- * <B>NOTE:</B> The {@link javax.sql.DataSource} interface, new in the
- * JDBC 2.0 API, provides another way to connect to a data source.
- * The use of a <code>DataSource</code> object is the preferred means of
+ * The basic service for managing a set of JDBC drivers.
+ * <p>
+ * <strong>NOTE:</strong> The {@link javax.sql.DataSource} interface, provides
+ * another way to connect to a data source.
+ * The use of a {@code DataSource} object is the preferred means of
  * connecting to a data source.
+ * <P>
+ * As part of its initialization, the {@code DriverManager} class will
+ * attempt to load available JDBC drivers by using:
+ * <ul>
+ * <li>The {@code jdbc.drivers} system property which contains a
+ * colon separated list of fully qualified class names of JDBC drivers. Each
+ * driver is loaded using the {@linkplain ClassLoader#getSystemClassLoader
+ * system class loader}:
+ * <ul>
+ * <li>{@code jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver}
+ * </ul>
  *
- * <P>As part of its initialization, the <code>DriverManager</code> class will
- * attempt to load the driver classes referenced in the "jdbc.drivers"
- * system property. This allows a user to customize the JDBC Drivers
- * used by their applications. For example in your
- * ~/.hotjava/properties file you might specify:
- * <pre>
- * <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE>
- * </pre>
- *<P> The <code>DriverManager</code> methods <code>getConnection</code> and
- * <code>getDrivers</code> have been enhanced to support the Java Standard Edition
- * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
- * include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers
- * implementation of <code>java.sql.Driver</code>.  For example, to load the <code>my.sql.Driver</code> class,
- * the <code>META-INF/services/java.sql.Driver</code> file would contain the entry:
- * <pre>
- * <code>my.sql.Driver</code>
- * </pre>
+ * <li>Service providers of the {@code java.sql.Driver} class, that are loaded
+ * via the {@linkplain ServiceLoader#load service-provider loading} mechanism.
+ *</ul>
  *
- * <P>Applications no longer need to explicitly load JDBC drivers using <code>Class.forName()</code>. Existing programs
- * which currently load JDBC drivers using <code>Class.forName()</code> will continue to work without
- * modification.
+ *<P>
+ * @ImplNote
+ * {@code DriverManager} initialization is done lazily and looks up service
+ * providers using the thread context class loader.  The drivers loaded and
+ * available to an application will depend on the thread context class loader of
+ * the thread that triggers driver initialization by {@code DriverManager}.
  *
- * <P>When the method <code>getConnection</code> is called,
- * the <code>DriverManager</code> will attempt to
+ * <P>When the method {@code getConnection} is called,
+ * the {@code DriverManager} will attempt to
  * locate a suitable driver from amongst those loaded at
- * initialization and those loaded explicitly using the same classloader
- * as the current applet or application.
+ * initialization and those loaded explicitly using the same class loader
+ * as the current application.
  *
- * <P>
- * Starting with the Java 2 SDK, Standard Edition, version 1.3, a
- * logging stream can be set only if the proper
- * permission has been granted.  Normally this will be done with
- * the tool PolicyTool, which can be used to grant <code>permission
- * java.sql.SQLPermission "setLog"</code>.
  * @see Driver
  * @see Connection
  */
@@ -137,29 +132,15 @@
     /**
      * Sets the logging/tracing <code>PrintWriter</code> object
      * that is used by the <code>DriverManager</code> and all drivers.
-     * <P>
-     * There is a minor versioning problem created by the introduction
-     * of the method <code>setLogWriter</code>.  The
-     * method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object
-     * that will be returned by <code>getLogStream</code>---the Java platform does
-     * not provide a backward conversion.  As a result, a new application
-     * that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses
-     * <code>getLogStream</code> will likely not see debugging information written
-     * by that driver.
      *<P>
-     * Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
-     * to see that there is an <code>SQLPermission</code> object before setting
-     * the logging stream.  If a <code>SecurityManager</code> exists and its
-     * <code>checkPermission</code> method denies setting the log writer, this
-     * method throws a <code>java.lang.SecurityException</code>.
+     * If a security manager exists, its {@code checkPermission}
+     * method is first called with a {@code SQLPermission("setLog")}
+     * permission to check that the caller is allowed to call {@code setLogWriter}.
      *
      * @param out the new logging/tracing <code>PrintStream</code> object;
      *      <code>null</code> to disable logging and tracing
-     * @throws SecurityException
-     *    if a security manager exists and its
-     *    <code>checkPermission</code> method denies
-     *    setting the log writer
-     *
+     * @throws SecurityException if a security manager exists and its
+     * {@code checkPermission} method denies permission to set the log writer.
      * @see SecurityManager#checkPermission
      * @see #getLogWriter
      * @since 1.2
@@ -374,8 +355,9 @@
      * If a {@code null} value is specified for the driver to be removed, then no
      * action is taken.
      * <p>
-     * If a security manager exists and its {@code checkPermission} denies
-     * permission, then a {@code SecurityException} will be thrown.
+     * If a security manager exists, its {@code checkPermission}
+     * method is first called with a {@code SQLPermission("deregisterDriver")}
+     * permission to check that the caller is allowed to deregister a JDBC Driver.
      * <p>
      * If the specified driver is not found in the list of registered drivers,
      * then no action is taken.  If the driver was found, it will be removed
@@ -501,17 +483,14 @@
      * by the <code>DriverManager</code>
      * and all drivers.
      *<P>
-     * In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
-     * to see that there is an <code>SQLPermission</code> object before setting
-     * the logging stream.  If a <code>SecurityManager</code> exists and its
-     * <code>checkPermission</code> method denies setting the log writer, this
-     * method throws a <code>java.lang.SecurityException</code>.
+     * If a security manager exists, its {@code checkPermission}
+     * method is first called with a {@code SQLPermission("setLog")}
+     * permission to check that the caller is allowed to call {@code setLogStream}.
      *
      * @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>
      * @deprecated Use {@code setLogWriter}
      * @throws SecurityException if a security manager exists and its
-     *    <code>checkPermission</code> method denies setting the log stream
-     *
+     * {@code checkPermission} method denies permission to set the log stream.
      * @see SecurityManager#checkPermission
      * @see #getLogStream
      */
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,10 +25,8 @@
 
 package com.sun.java.accessibility.util;
 
-import java.util.*;
 import java.awt.*;
 import java.awt.event.*;
-import javax.accessibility.*;
 import javax.swing.*;
 import javax.swing.event.*;
 import sun.awt.AWTPermissions;
@@ -55,7 +53,7 @@
      * @deprecated This field is unused; to get the component with focus use the
      * getComponentWithFocus method.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected Component componentWithFocus = null;
 
     static private Component componentWithFocus_private = null;
@@ -69,7 +67,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected ComponentListener     componentListener     = null;
 
     static private ComponentListener componentListener_private = null;
@@ -82,7 +80,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected ContainerListener     containerListener     = null;
 
     static private ContainerListener containerListener_private = null;
@@ -95,7 +93,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected FocusListener         focusListener         = null;
 
     static private FocusListener focusListener_private = null;
@@ -108,7 +106,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected KeyListener           keyListener           = null;
 
     static private KeyListener keyListener_private = null;
@@ -121,7 +119,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected MouseListener         mouseListener         = null;
 
     static private MouseListener mouseListener_private = null;
@@ -134,7 +132,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected MouseMotionListener   mouseMotionListener   = null;
 
     static private MouseMotionListener mouseMotionListener_private = null;
@@ -147,7 +145,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected WindowListener        windowListener        = null;
 
     static private WindowListener windowListener_private = null;
@@ -162,7 +160,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected ActionListener        actionListener        = null;
 
     static private ActionListener actionListener_private = null;
@@ -175,7 +173,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected AdjustmentListener    adjustmentListener    = null;
 
     static private AdjustmentListener adjustmentListener_private = null;
@@ -188,7 +186,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected ItemListener          itemListener          = null;
 
     static private ItemListener itemListener_private = null;
@@ -201,7 +199,7 @@
      *
      * @deprecated This field is unused.
      */
-    @Deprecated
+    @Deprecated(since="8", forRemoval=true)
     static protected TextListener          textListener          = null;
 
     static private TextListener textListener_private = null;
@@ -212,13 +210,8 @@
      * This listener calls the other registered listeners when an event
      * occurs.  By doing things this way, the actual number of listeners
      * installed on a component instance is drastically reduced.
-     *
-     * @deprecated This field is unused.
      */
-    @Deprecated
-    static protected AWTEventsListener awtListener = new AWTEventsListener();
-
-    static private final AWTEventsListener awtListener_private = new AWTEventsListener();
+    static private final AWTEventsListener awtListener = new AWTEventsListener();
 
     /**
      * Returns the component that currently has keyboard focus.  The return
@@ -253,7 +246,7 @@
     static public void addComponentListener(ComponentListener l) {
         if (componentListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.COMPONENT);
+            awtListener.installListeners(EventID.COMPONENT);
         }
         componentListener_private = AWTEventMulticaster.add(componentListener_private, l);
     }
@@ -268,7 +261,7 @@
     static public void removeComponentListener(ComponentListener l) {
         componentListener_private = AWTEventMulticaster.remove(componentListener_private, l);
         if (componentListener_private == null) {
-            awtListener_private.removeListeners(EventID.COMPONENT);
+            awtListener.removeListeners(EventID.COMPONENT);
         }
     }
 
@@ -335,7 +328,7 @@
     static public void addKeyListener(KeyListener l) {
         if (keyListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.KEY);
+            awtListener.installListeners(EventID.KEY);
         }
         keyListener_private = AWTEventMulticaster.add(keyListener_private, l);
     }
@@ -350,7 +343,7 @@
     static public void removeKeyListener(KeyListener l) {
         keyListener_private = AWTEventMulticaster.remove(keyListener_private, l);
         if (keyListener_private == null)  {
-            awtListener_private.removeListeners(EventID.KEY);
+            awtListener.removeListeners(EventID.KEY);
         }
     }
 
@@ -367,7 +360,7 @@
     static public void addMouseListener(MouseListener l) {
         if (mouseListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.MOUSE);
+            awtListener.installListeners(EventID.MOUSE);
         }
         mouseListener_private = AWTEventMulticaster.add(mouseListener_private, l);
     }
@@ -382,7 +375,7 @@
     static public void removeMouseListener(MouseListener l) {
         mouseListener_private = AWTEventMulticaster.remove(mouseListener_private, l);
         if (mouseListener_private == null) {
-            awtListener_private.removeListeners(EventID.MOUSE);
+            awtListener.removeListeners(EventID.MOUSE);
         }
     }
 
@@ -399,7 +392,7 @@
     static public void addMouseMotionListener(MouseMotionListener l) {
         if (mouseMotionListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.MOTION);
+            awtListener.installListeners(EventID.MOTION);
         }
         mouseMotionListener_private = AWTEventMulticaster.add(mouseMotionListener_private, l);
     }
@@ -414,7 +407,7 @@
     static public void removeMouseMotionListener(MouseMotionListener l) {
         mouseMotionListener_private = AWTEventMulticaster.remove(mouseMotionListener_private, l);
         if (mouseMotionListener_private == null) {
-            awtListener_private.removeListeners(EventID.MOTION);
+            awtListener.removeListeners(EventID.MOTION);
         }
     }
 
@@ -431,7 +424,7 @@
     static public void addWindowListener(WindowListener l) {
         if (windowListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.WINDOW);
+            awtListener.installListeners(EventID.WINDOW);
         }
         windowListener_private = AWTEventMulticaster.add(windowListener_private, l);
     }
@@ -446,7 +439,7 @@
     static public void removeWindowListener(WindowListener l) {
         windowListener_private = AWTEventMulticaster.remove(windowListener_private, l);
         if (windowListener_private == null) {
-            awtListener_private.removeListeners(EventID.WINDOW);
+            awtListener.removeListeners(EventID.WINDOW);
         }
     }
 
@@ -463,7 +456,7 @@
     static public void addActionListener(ActionListener l) {
         if (actionListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.ACTION);
+            awtListener.installListeners(EventID.ACTION);
         }
         actionListener_private = AWTEventMulticaster.add(actionListener_private, l);
     }
@@ -478,7 +471,7 @@
     static public void removeActionListener(ActionListener l) {
         actionListener_private = AWTEventMulticaster.remove(actionListener_private, l);
         if (actionListener_private == null) {
-            awtListener_private.removeListeners(EventID.ACTION);
+            awtListener.removeListeners(EventID.ACTION);
         }
     }
 
@@ -496,7 +489,7 @@
     static public void addAdjustmentListener(AdjustmentListener l) {
         if (adjustmentListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.ADJUSTMENT);
+            awtListener.installListeners(EventID.ADJUSTMENT);
         }
         adjustmentListener_private = AWTEventMulticaster.add(adjustmentListener_private, l);
     }
@@ -511,7 +504,7 @@
     static public void removeAdjustmentListener(AdjustmentListener l) {
         adjustmentListener_private = AWTEventMulticaster.remove(adjustmentListener_private, l);
         if (adjustmentListener_private == null) {
-            awtListener_private.removeListeners(EventID.ADJUSTMENT);
+            awtListener.removeListeners(EventID.ADJUSTMENT);
         }
     }
 
@@ -528,7 +521,7 @@
     static public void addItemListener(ItemListener l) {
         if (itemListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.ITEM);
+            awtListener.installListeners(EventID.ITEM);
         }
         itemListener_private = AWTEventMulticaster.add(itemListener_private, l);
     }
@@ -543,7 +536,7 @@
     static public void removeItemListener(ItemListener l) {
         itemListener_private = AWTEventMulticaster.remove(itemListener_private, l);
         if (itemListener_private == null) {
-            awtListener_private.removeListeners(EventID.ITEM);
+            awtListener.removeListeners(EventID.ITEM);
         }
     }
 
@@ -560,7 +553,7 @@
     static public void addTextListener(TextListener l) {
         if (textListener_private == null) {
             checkInstallPermission();
-            awtListener_private.installListeners(EventID.TEXT);
+            awtListener.installListeners(EventID.TEXT);
         }
         textListener_private = AWTEventMulticaster.add(textListener_private, l);
     }
@@ -575,7 +568,7 @@
     static public void removeTextListener(TextListener l) {
         textListener_private = AWTEventMulticaster.remove(textListener_private, l);
         if (textListener_private == null) {
-            awtListener_private.removeListeners(EventID.TEXT);
+            awtListener.removeListeners(EventID.TEXT);
         }
     }
 
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -63,7 +63,7 @@
      * occurs.  By doing things this way, the actual number of listeners
      * installed on a component instance is drastically reduced.
      */
-    static protected final AccessibilityEventListener accessibilityListener =
+    static private final AccessibilityEventListener accessibilityListener =
         new AccessibilityEventListener();
 
     /**
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -71,7 +71,7 @@
      * occurs.  By doing things this way, the actual number of listeners
      * installed on a component instance is drastically reduced.
      */
-    static protected final SwingEventListener swingListener = new SwingEventListener();
+    static private final SwingEventListener swingListener = new SwingEventListener();
 
     /**
      * Adds the specified listener to receive all {@link EventID#ANCESTOR ANCESTOR}
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Mon Dec 19 16:05:38 2016 +0000
@@ -34,6 +34,7 @@
 import java.nio.file.Paths;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
+import jdk.internal.module.ModuleResolution;
 
 /**
  * Parser for GNU Style Options.
@@ -158,6 +159,31 @@
                                                                 ModuleFinder.of(paths));
                 }
             },
+            new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") {
+                void process(Main jartool, String opt, String arg) {
+                    ModuleResolution mres = jartool.moduleResolution;
+                    jartool.moduleResolution = mres.withDoNotResolveByDefault();
+                }
+                boolean isExtra() { return true; }
+            },
+            new Option(true, OptionType.CREATE_UPDATE, "--warn-if-resolved") {
+                void process(Main jartool, String opt, String arg) throws BadArgs {
+                    ModuleResolution mres = ModuleResolution.empty();
+                    if (jartool.moduleResolution.doNotResolveByDefault())
+                        mres.withDoNotResolveByDefault();
+
+                    if (arg.equals("deprecated")) {
+                        jartool.moduleResolution = mres.withDeprecated();
+                    } else if (arg.equals("deprecated-for-removal")) {
+                        jartool.moduleResolution = mres.withDeprecatedForRemoval();
+                    } else if (arg.equals("incubating")) {
+                        jartool.moduleResolution = mres.withIncubating();
+                    } else {
+                        throw new BadArgs("error.bad.reason", arg);
+                    }
+                }
+                boolean isExtra() { return true; }
+            },
             new Option(false, OptionType.CREATE_UPDATE_INDEX, "--no-compress", "-0") {
                 void process(Main jartool, String opt, String arg) {
                     jartool.flag0 = true;
@@ -175,17 +201,20 @@
             // Other options
             new Option(true, true, OptionType.OTHER, "--help", "-h") {
                 void process(Main jartool, String opt, String arg) throws BadArgs {
-                    if (jartool.info == null) {
-                        if (arg == null) {
-                            jartool.info = Main.Info.HELP;
-                            return;
-                        }
+                    if (arg == null) {
+                        jartool.info = Main.Info.HELP;
+                        return;
+                    }
 
-                        if (!arg.equals("compat"))
-                            throw new BadArgs("error.illegal.option", arg).showUsage(true);
+                    if (!arg.equals("compat"))
+                        throw new BadArgs("error.illegal.option", arg).showUsage(true);
 
-                        jartool.info = Main.Info.COMPAT_HELP;
-                    }
+                    jartool.info = Main.Info.COMPAT_HELP;
+                }
+            },
+            new Option(false, OptionType.OTHER, "--help-extra") {
+                void process(Main jartool, String opt, String arg) throws BadArgs {
+                    jartool.info = Main.Info.HELP_EXTRA;
                 }
             },
             new Option(false, OptionType.OTHER, "--version") {
@@ -229,6 +258,8 @@
 
         boolean isHidden() { return false; }
 
+        boolean isExtra() { return false; }
+
         boolean matches(String opt) {
             for (String a : aliases) {
                 if (a.equals(opt)) {
@@ -292,6 +323,14 @@
     }
 
     static void printHelp(PrintWriter out) {
+        printHelp(out, false);
+    }
+
+    static void printHelpExtra(PrintWriter out) {
+        printHelp(out, true);
+    }
+
+    private static void printHelp(PrintWriter out, boolean printExtra) {
         out.format("%s%n", Main.getMsg("main.help.preopt"));
         for (OptionType type : OptionType.values()) {
             boolean typeHeadingWritten = false;
@@ -304,6 +343,9 @@
                 if (o.isHidden() || name.equals("h")) {
                     continue;
                 }
+                if (o.isExtra() && !printExtra) {
+                    continue;
+                }
                 if (!typeHeadingWritten) {
                     out.format("%n%s%n", Main.getMsg("main.help.opt." + type.name));
                     typeHeadingWritten = true;
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Mon Dec 19 16:05:38 2016 +0000
@@ -47,7 +47,6 @@
 import java.util.*;
 import java.util.function.Consumer;
 import java.util.function.Function;
-import java.util.function.Supplier;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -57,11 +56,11 @@
 import java.util.jar.Manifest;
 import java.text.MessageFormat;
 
-import jdk.internal.misc.JavaLangModuleAccess;
-import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.Checks;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModuleResolution;
 import jdk.internal.util.jar.JarIndex;
 
 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
@@ -211,6 +210,7 @@
     /* To support additional GNU Style informational options */
     enum Info {
         HELP(GNUStyleOptions::printHelp),
+        HELP_EXTRA(GNUStyleOptions::printHelpExtra),
         COMPAT_HELP(GNUStyleOptions::printCompatHelp),
         USAGE_TRYHELP(GNUStyleOptions::printUsageTryHelp),
         VERSION(GNUStyleOptions::printVersion);
@@ -225,6 +225,7 @@
     /* Modular jar related options */
     Version moduleVersion;
     Pattern modulesToHash;
+    ModuleResolution moduleResolution = ModuleResolution.empty();
     ModuleFinder moduleFinder = ModuleFinder.of();
 
     private static final String MODULE_INFO = "module-info.class";
@@ -1991,12 +1992,13 @@
                   .collect(joining(" "));
     }
 
-    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
-
     private void printModuleDescriptor(InputStream entryInputStream)
         throws IOException
     {
-        ModuleDescriptor md = ModuleDescriptor.read(entryInputStream);
+        ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
+        ModuleDescriptor md = attrs.descriptor();
+        ModuleHashes hashes = attrs.recordedHashes();
+
         StringBuilder sb = new StringBuilder();
         sb.append("\n");
         if (md.isOpen())
@@ -2043,15 +2045,24 @@
 
         md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 
-        JLMA.hashes(md).ifPresent(hashes ->
-                hashes.names().stream().sorted().forEach(
+        if (hashes != null) {
+            hashes.names().stream().sorted().forEach(
                     mod -> sb.append("\n  hashes ").append(mod).append(" ")
                              .append(hashes.algorithm()).append(" ")
-                             .append(hashes.hashFor(mod))));
+                             .append(toHex(hashes.hashFor(mod))));
+        }
 
         output(sb.toString());
     }
 
+    private static String toHex(byte[] ba) {
+        StringBuilder sb = new StringBuilder(ba.length);
+        for (byte b: ba) {
+            sb.append(String.format("%02x", b & 0xff));
+        }
+        return sb.toString();
+    }
+
     private static String toBinaryName(String classname) {
         return (classname.replace('.', '/')) + ".class";
     }
@@ -2212,6 +2223,10 @@
             }
         }
 
+        if (moduleResolution.value() != 0) {
+            extender.moduleResolution(moduleResolution);
+        }
+
         extender.write(baos);
         return baos.toByteArray();
     }
@@ -2228,13 +2243,12 @@
             // Create a module finder that finds the modular JAR
             // being created/updated
             URI uri = Paths.get(fname).toUri();
-            ModuleReference mref = new ModuleReference(descriptor, uri,
-                new Supplier<>() {
-                    @Override
-                    public ModuleReader get() {
-                        throw new UnsupportedOperationException("should not reach here");
-                    }
-                });
+            ModuleReference mref = new ModuleReference(descriptor, uri) {
+                @Override
+                public ModuleReader open() {
+                    throw new UnsupportedOperationException("should not reach here");
+                }
+            };
 
             // Compose a module finder with the module path and
             // the modular JAR being created or updated
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Mon Dec 19 16:05:38 2016 +0000
@@ -46,6 +46,8 @@
 	 together!
 error.bad.dflag=\
         '-d, --print-module-descriptor' option requires no input file(s) to be specified: {0}
+error.bad.reason=\
+        bad reason: {0}, must be one of deprecated, deprecated-for-removal, or incubating
 error.nosuch.fileordir=\
         {0} : no such file or directory
 error.write.file=\
@@ -246,6 +248,12 @@
 main.help.opt.create.update.module-path=\
 \  -p, --module-path          Location of module dependence for generating\n\
 \                             the hash
+main.help.opt.create.update.do-not-resolve-by-default=\
+\      --do-not-resolve-by-default  Exclude from the default root set of modules
+main.help.opt.create.update.warn-if-resolved=\
+\      --warn-if-resolved     Hint for a tool to issue a warning if the module\n\
+\                             is resolved. One of deprecated, deprecated-for-removal,\n\
+\                             or incubating
 main.help.opt.create.update.index=\
 \ Operation modifiers valid only in create, update, and generate-index mode:\n
 main.help.opt.create.update.index.no-compress=\
@@ -254,6 +262,8 @@
 \ Other options:\n
 main.help.opt.other.help=\
 \  -?, --help[:compat]        Give this, or optionally the compatibility, help
+main.help.opt.other.help-extra=\
+\      --help-extra           Give help on extra options
 main.help.opt.other.version=\
 \      --version              Print program version
 main.help.postopt=\
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Mon Dec 19 16:05:38 2016 +0000
@@ -130,6 +130,7 @@
     }
 
     private final Path root;
+    private final Map<String, String> launchers;
     private final Path mdir;
     private final Set<String> modules = new HashSet<>();
     private String targetOsName;
@@ -140,10 +141,9 @@
      * @param root The image root directory.
      * @throws IOException
      */
-    public DefaultImageBuilder(Path root) throws IOException {
-        Objects.requireNonNull(root);
-
-        this.root = root;
+    public DefaultImageBuilder(Path root, Map<String, String> launchers) throws IOException {
+        this.root = Objects.requireNonNull(root);
+        this.launchers = Objects.requireNonNull(launchers);
         this.mdir = root.resolve("lib");
         Files.createDirectories(mdir);
     }
@@ -235,7 +235,7 @@
             // If native files are stripped completely, <root>/bin dir won't exist!
             // So, don't bother generating launcher scripts.
             if (Files.isDirectory(bin)) {
-                 prepareApplicationFiles(files, modules);
+                 prepareApplicationFiles(files);
             }
         } catch (IOException ex) {
             throw new PluginException(ex);
@@ -246,22 +246,44 @@
      * Generates launcher scripts.
      *
      * @param imageContent The image content.
-     * @param modules The set of modules that the runtime image contains.
      * @throws IOException
      */
-    protected void prepareApplicationFiles(ResourcePool imageContent, Set<String> modules) throws IOException {
+    protected void prepareApplicationFiles(ResourcePool imageContent) throws IOException {
         // generate launch scripts for the modules with a main class
-        for (String module : modules) {
+        for (Map.Entry<String, String> entry : launchers.entrySet()) {
+            String launcherEntry = entry.getValue();
+            int slashIdx = launcherEntry.indexOf("/");
+            String module, mainClassName;
+            if (slashIdx == -1) {
+                module = launcherEntry;
+                mainClassName = null;
+            } else {
+                module = launcherEntry.substring(0, slashIdx);
+                assert !module.isEmpty();
+                mainClassName = launcherEntry.substring(slashIdx + 1);
+                assert !mainClassName.isEmpty();
+            }
+
             String path = "/" + module + "/module-info.class";
             Optional<ResourcePoolEntry> res = imageContent.findEntry(path);
             if (!res.isPresent()) {
                 throw new IOException("module-info.class not found for " + module + " module");
             }
-            Optional<String> mainClass;
             ByteArrayInputStream stream = new ByteArrayInputStream(res.get().contentBytes());
-            mainClass = ModuleDescriptor.read(stream).mainClass();
-            if (mainClass.isPresent()) {
-                Path cmd = root.resolve("bin").resolve(module);
+            Optional<String> mainClass = ModuleDescriptor.read(stream).mainClass();
+            if (mainClassName == null && mainClass.isPresent()) {
+                mainClassName = mainClass.get();
+            }
+
+            if (mainClassName != null) {
+                // make sure main class exists!
+                if (!imageContent.findEntry("/" + module + "/" +
+                        mainClassName.replace('.', '/') + ".class").isPresent()) {
+                    throw new IllegalArgumentException(module + " does not have main class: " + mainClassName);
+                }
+
+                String launcherFile = entry.getKey();
+                Path cmd = root.resolve("bin").resolve(launcherFile);
                 // generate shell script for Unix platforms
                 StringBuilder sb = new StringBuilder();
                 sb.append("#!/bin/sh")
@@ -272,7 +294,7 @@
                         .append("\n");
                 sb.append("$DIR/java $JLINK_VM_OPTIONS -m ")
                         .append(module).append('/')
-                        .append(mainClass.get())
+                        .append(mainClassName)
                         .append(" $@\n");
 
                 try (BufferedWriter writer = Files.newBufferedWriter(cmd,
@@ -286,7 +308,7 @@
                 }
                 // generate .bat file for Windows
                 if (isWindows()) {
-                    Path bat = root.resolve(BIN_DIRNAME).resolve(module + ".bat");
+                    Path bat = root.resolve(BIN_DIRNAME).resolve(launcherFile + ".bat");
                     sb = new StringBuilder();
                     sb.append("@echo off")
                             .append("\r\n");
@@ -296,7 +318,7 @@
                             .append("\r\n");
                     sb.append("\"%DIR%\\java\" %JLINK_VM_OPTIONS% -m ")
                             .append(module).append('/')
-                            .append(mainClass.get())
+                            .append(mainClassName)
                             .append(" %*\r\n");
 
                     try (BufferedWriter writer = Files.newBufferedWriter(bat,
@@ -305,6 +327,8 @@
                         writer.write(sb.toString());
                     }
                 }
+            } else {
+                throw new IllegalArgumentException(module + " doesn't contain main class & main not specified in command line");
             }
         }
     }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Mon Dec 19 16:05:38 2016 +0000
@@ -53,7 +53,9 @@
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.builder.DefaultImageBuilder;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Checks;
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.ModuleResolution;
 
 /**
  * Implementation for the jlink tool.
@@ -109,6 +111,27 @@
             task.options.output = path;
         }, "--output"),
         new Option<JlinkTask>(true, (task, opt, arg) -> {
+            String[] values = arg.split("=");
+            // check values
+            if (values.length != 2 || values[0].isEmpty() || values[1].isEmpty()) {
+                throw taskHelper.newBadArgs("err.launcher.value.format", arg);
+            } else {
+                String commandName = values[0];
+                String moduleAndMain = values[1];
+                int idx = moduleAndMain.indexOf("/");
+                if (idx != -1) {
+                    if (moduleAndMain.substring(0, idx).isEmpty()) {
+                        throw taskHelper.newBadArgs("err.launcher.module.name.empty", arg);
+                    }
+
+                    if (moduleAndMain.substring(idx + 1).isEmpty()) {
+                        throw taskHelper.newBadArgs("err.launcher.main.class.empty", arg);
+                    }
+                }
+                task.options.launchers.put(commandName, moduleAndMain);
+            }
+        }, "--launcher"),
+        new Option<JlinkTask>(true, (task, opt, arg) -> {
             if ("little".equals(arg)) {
                 task.options.endian = ByteOrder.LITTLE_ENDIAN;
             } else if ("big".equals(arg)) {
@@ -168,6 +191,7 @@
         final Set<String> limitMods = new HashSet<>();
         final Set<String> addMods = new HashSet<>();
         Path output;
+        final Map<String, String> launchers = new HashMap<>();
         Path packagedModulesPath;
         ByteOrder endian = ByteOrder.nativeOrder();
         boolean ignoreSigning = false;
@@ -260,7 +284,8 @@
                                     config.getModules(),
                                     config.getByteOrder(),
                                     null,
-                                    IGNORE_SIGNING_DEFAULT);
+                                    IGNORE_SIGNING_DEFAULT,
+                                    null);
 
         // Then create the Plugin Stack
         ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins);
@@ -284,7 +309,7 @@
     }
 
     private void postProcessOnly(Path existingImage) throws Exception {
-        PluginsConfiguration config = taskHelper.getPluginsConfig(null);
+        PluginsConfiguration config = taskHelper.getPluginsConfig(null, null);
         ExecutableImage img = DefaultImageBuilder.getExecutableImage(existingImage);
         if (img == null) {
             throw taskHelper.newBadArgs("err.existing.image.invalid");
@@ -328,11 +353,12 @@
                                                           roots,
                                                           options.endian,
                                                           options.packagedModulesPath,
-                                                          options.ignoreSigning);
+                                                          options.ignoreSigning,
+                                                          log);
 
         // Then create the Plugin Stack
         ImagePluginStack stack = ImagePluginConfiguration.
-                parseConfiguration(taskHelper.getPluginsConfig(options.output));
+                parseConfiguration(taskHelper.getPluginsConfig(options.output, options.launchers));
 
         //Ask the stack to proceed
         stack.operate(imageProvider);
@@ -344,9 +370,7 @@
      */
     private ModuleFinder modulePathFinder() {
         Path[] entries = options.modulePath.toArray(new Path[0]);
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, entries);
-
+        ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
         if (!options.limitMods.isEmpty()) {
             finder = limitFinder(finder, options.limitMods, Collections.emptySet());
         }
@@ -364,8 +388,7 @@
                                                Set<String> roots)
     {
         Path[] entries = paths.toArray(new Path[0]);
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, entries);
+        ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
 
         // if limitmods is specified then limit the universe
         if (!limitMods.isEmpty()) {
@@ -386,7 +409,8 @@
                                                      Set<String> roots,
                                                      ByteOrder order,
                                                      Path retainModulesPath,
-                                                     boolean ignoreSigning)
+                                                     boolean ignoreSigning,
+                                                     PrintWriter log)
             throws IOException
     {
         if (roots.isEmpty()) {
@@ -398,6 +422,27 @@
                                  ModuleFinder.of(),
                                  roots);
 
+        // emit warning for modules that end with a digit
+        cf.modules().stream()
+            .map(ResolvedModule::name)
+            .filter(mn -> !Checks.hasLegalModuleNameLastCharacter(mn))
+            .forEach(mn -> System.err.println("WARNING: Module name \""
+                                              + mn + "\" may soon be illegal"));
+
+        // emit a warning for any incubating modules in the configuration
+        if (log != null) {
+            String im = cf.modules()
+                          .stream()
+                          .map(ResolvedModule::reference)
+                          .filter(ModuleResolution::hasIncubatingWarning)
+                          .map(ModuleReference::descriptor)
+                          .map(ModuleDescriptor::name)
+                          .collect(Collectors.joining(", "));
+
+            if (!"".equals(im))
+                log.println("WARNING: Using incubator modules: " + im);
+        }
+
         Map<String, Path> mods = cf.modules().stream()
             .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
         return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Mon Dec 19 16:05:38 2016 +0000
@@ -28,6 +28,7 @@
 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.io.IOException;
 import java.io.UncheckedIOException;
@@ -78,10 +79,12 @@
     }
 
     private static ModuleReference moduleReference(ModuleDescriptor desc) {
-        return new ModuleReference(desc, null, () -> {
-            IOException ioe = new IOException("<module reader unsupported>");
-            throw new UncheckedIOException(ioe);
-        });
+        return new ModuleReference(desc, null) {
+            @Override
+            public ModuleReader open() {
+                throw new UnsupportedOperationException();
+            }
+        };
     }
 
     private static Map<String, ModuleReference> allModRefs(ResourcePool pool) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Mon Dec 19 16:05:38 2016 +0000
@@ -58,7 +58,7 @@
 import jdk.tools.jlink.internal.plugins.PluginsResourceBundle;
 import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
 import jdk.tools.jlink.internal.plugins.StripDebugPlugin;
-import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModulePath;
 
 /**
  *
@@ -403,7 +403,7 @@
             return null;
         }
 
-        private PluginsConfiguration getPluginsConfig(Path output
+        private PluginsConfiguration getPluginsConfig(Path output, Map<String, String> launchers
                     ) throws IOException, BadArgs {
             if (output != null) {
                 if (Files.exists(output)) {
@@ -440,9 +440,9 @@
             // recreate or postprocessing don't require an output directory.
             ImageBuilder builder = null;
             if (output != null) {
-                builder = new DefaultImageBuilder(output);
+                builder = new DefaultImageBuilder(output, launchers);
+            }
 
-            }
             return new Jlink.PluginsConfiguration(pluginsList,
                     builder, lastSorter);
         }
@@ -745,9 +745,9 @@
                 + bundleHelper.getMessage(key, args));
     }
 
-    public PluginsConfiguration getPluginsConfig(Path output)
+    public PluginsConfiguration getPluginsConfig(Path output, Map<String, String> launchers)
             throws IOException, BadArgs {
-        return pluginOptions.getPluginsConfig(output);
+        return pluginOptions.getPluginsConfig(output, launchers);
     }
 
     public Path getExistingImage() {
@@ -765,9 +765,7 @@
     static Layer createPluginsLayer(List<Path> paths) {
 
         Path[] dirs = paths.toArray(new Path[0]);
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, dirs);
-
+        ModuleFinder finder = new ModulePath(Runtime.version(), true, dirs);
         Configuration bootConfiguration = Layer.boot().configuration();
         try {
             Configuration cf = bootConfiguration
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Mon Dec 19 16:05:38 2016 +0000
@@ -49,6 +49,7 @@
  */
 public final class AppRuntimeImageBuilder {
     private Path outputDir = null;
+    private Map<String, String> launchers = Collections.emptyMap();
     private List<Path> modulePath = null;
     private Set<String> addModules = null;
     private Set<String> limitModules = null;
@@ -62,6 +63,10 @@
         outputDir = value;
     }
 
+    public void setLaunchers(Map<String, String> value) {
+        launchers = value;
+    }
+
     public void setModulePath(List<Path> value) {
         modulePath = value;
     }
@@ -120,7 +125,7 @@
 
         // build the image
         Jlink.PluginsConfiguration pluginConfig = new Jlink.PluginsConfiguration(
-            plugins, new DefaultImageBuilder(outputDir), null);
+            plugins, new DefaultImageBuilder(outputDir, launchers), null);
         Jlink jlink = new Jlink();
         jlink.build(jlinkConfig, pluginConfig);
     }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Mon Dec 19 16:00:59 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1083 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.tools.jlink.internal.plugins;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.*;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.function.IntSupplier;
-
-import jdk.internal.misc.JavaLangModuleAccess;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.Checks;
-import jdk.internal.module.ModuleInfoExtender;
-import jdk.internal.module.SystemModules;
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.internal.org.objectweb.asm.Opcodes;
-
-import static jdk.internal.org.objectweb.asm.Opcodes.*;
-
-import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.plugin.ResourcePool;
-import jdk.tools.jlink.plugin.Plugin;
-import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.SystemModulesClassGenerator.*;
-import jdk.tools.jlink.plugin.ResourcePoolBuilder;
-import jdk.tools.jlink.plugin.ResourcePoolEntry;
-
-/**
- * Jlink plugin to reconstitute module descriptors for system modules.
- * It will extend module-info.class with Packages attribute,
- * if not present. It also determines the number of packages of
- * the boot layer at link time.
- *
- * This plugin will override jdk.internal.module.SystemModules class
- *
- * @see java.lang.module.SystemModuleFinder
- * @see SystemModules
- */
-public final class SystemModuleDescriptorPlugin implements Plugin {
-    private static final JavaLangModuleAccess JLMA =
-        SharedSecrets.getJavaLangModuleAccess();
-
-    private static final String NAME = "system-modules";
-    private static final String DESCRIPTION =
-        PluginsResourceBundle.getDescription(NAME);
-
-    private boolean enabled;
-    public SystemModuleDescriptorPlugin() {
-        this.enabled = true;
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
-    }
-
-    @Override
-    public String getDescription() {
-        return DESCRIPTION;
-    }
-
-    @Override
-    public Set<State> getState() {
-        return enabled ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL)
-                       : EnumSet.of(State.DISABLED);
-    }
-
-    @Override
-    public void configure(Map<String, String> config) {
-        if (config.containsKey(NAME)) {
-            enabled = false;
-        }
-    }
-
-    @Override
-    public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
-        if (!enabled) {
-            throw new PluginException(NAME + " was set");
-        }
-
-        SystemModulesClassGenerator generator = new SystemModulesClassGenerator();
-
-        // generate the byte code to create ModuleDescriptors
-        // skip parsing module-info.class and skip name check
-        in.moduleView().modules().forEach(module -> {
-
-            ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
-                // automatic module not supported yet
-                () ->  new PluginException("module-info.class not found for " +
-                    module.name() + " module")
-            );
-
-            assert module.name().equals(data.moduleName());
-            try {
-                ByteArrayInputStream bain = new ByteArrayInputStream(data.contentBytes());
-                ModuleDescriptor md = ModuleDescriptor.read(bain);
-                validateNames(md);
-
-                Set<String> packages = module.packages();
-                generator.addModule(md, module.packages());
-
-                // add Packages attribute if not exist
-                if (md.packages().isEmpty() && packages.size() > 0) {
-                    bain.reset();
-                    ModuleInfoRewriter minfoWriter =
-                        new ModuleInfoRewriter(bain, module.packages());
-                    // replace with the overridden version
-                    data = data.copyWithContent(minfoWriter.getBytes());
-                }
-                out.add(data);
-            } catch (IOException e) {
-                throw new PluginException(e);
-            }
-        });
-
-        // Generate the new class
-        ClassWriter cwriter = generator.getClassWriter();
-        in.entries().forEach(data -> {
-            if (data.path().endsWith("module-info.class"))
-                return;
-            if (generator.isOverriddenClass(data.path())) {
-                byte[] bytes = cwriter.toByteArray();
-                ResourcePoolEntry ndata = data.copyWithContent(bytes);
-                out.add(ndata);
-            } else {
-                out.add(data);
-            }
-        });
-
-        return out.build();
-    }
-
-    /*
-     * Add Packages attribute
-     */
-    class ModuleInfoRewriter extends ByteArrayOutputStream {
-        final ModuleInfoExtender extender;
-        ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
-            this.extender = ModuleInfoExtender.newExtender(in);
-            // Add Packages attribute
-            this.extender.packages(packages);
-            this.extender.write(this);
-        }
-
-        byte[] getBytes() {
-            return buf;
-        }
-    }
-
-    void validateNames(ModuleDescriptor md) {
-        Checks.requireModuleName(md.name());
-        for (Requires req : md.requires()) {
-            Checks.requireModuleName(req.name());
-        }
-        for (Exports e : md.exports()) {
-            Checks.requirePackageName(e.source());
-            if (e.isQualified())
-                e.targets().forEach(Checks::requireModuleName);
-        }
-        for (Opens opens : md.opens()) {
-            Checks.requirePackageName(opens.source());
-            if (opens.isQualified())
-                opens.targets().forEach(Checks::requireModuleName);
-        }
-        for (Provides provides : md.provides()) {
-            Checks.requireServiceTypeName(provides.service());
-            provides.providers().forEach(Checks::requireServiceProviderName);
-        }
-        for (String service : md.uses()) {
-            Checks.requireServiceTypeName(service);
-        }
-        for (String pn : md.packages()) {
-            Checks.requirePackageName(pn);
-        }
-    }
-
-    /*
-     * Returns the initial capacity for a new Set or Map of the given size
-     * to avoid resizing.
-     */
-    static final int initialCapacity(int size) {
-        if (size == 0) {
-            return 0;
-        } else {
-            // Adjust to try and get size/capacity as close to the
-            // HashSet/HashMap default load factor without going over.
-            return (int)(Math.ceil((double)size / 0.75));
-        }
-    }
-
-    /**
-     * ClassWriter of a new jdk.internal.module.SystemModules class
-     * to reconstitute ModuleDescriptor of the system modules.
-     */
-    static class SystemModulesClassGenerator {
-        private static final String CLASSNAME =
-            "jdk/internal/module/SystemModules";
-        private static final String MODULE_DESCRIPTOR_BUILDER =
-            "jdk/internal/module/Builder";
-        private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE =
-            "[Ljava/lang/module/ModuleDescriptor;";
-        private static final String REQUIRES_MODIFIER_CLASSNAME =
-            "java/lang/module/ModuleDescriptor$Requires$Modifier";
-        private static final String EXPORTS_MODIFIER_CLASSNAME =
-            "java/lang/module/ModuleDescriptor$Exports$Modifier";
-        private static final String OPENS_MODIFIER_CLASSNAME =
-            "java/lang/module/ModuleDescriptor$Opens$Modifier";
-
-        // static variables in SystemModules class
-        private static final String MODULE_NAMES = "MODULE_NAMES";
-        private static final String MODULES_TO_HASH = "MODULES_TO_HASH";
-        private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
-
-        private static final int MAX_LOCAL_VARS = 256;
-
-        private final int BUILDER_VAR    = 0;
-        private final int MD_VAR         = 1;  // variable for ModuleDescriptor
-        private int nextLocalVar         = 2;  // index to next local variable
-
-        private final ClassWriter cw;
-        private MethodVisitor mv;
-        private int nextModulesIndex = 0;
-
-        // list of all ModuleDescriptorBuilders, invoked in turn when building.
-        private final List<ModuleDescriptorBuilder> builders = new ArrayList<>();
-
-        // module name to hash
-        private final Map<String, byte[]> modulesToHash = new HashMap<>();
-
-        // module name to index in MODULES_TO_HASH
-        private final Map<String, Integer> modulesToHashIndex = new HashMap<>();
-
-        // A builder to create one single Set instance for a given set of
-        // names or modifiers to reduce the footprint
-        // e.g. target modules of qualified exports
-        private final DedupSetBuilder dedupSetBuilder
-            = new DedupSetBuilder(this::getNextLocalVar);
-
-        public SystemModulesClassGenerator() {
-            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
-                                      ClassWriter.COMPUTE_FRAMES);
-        }
-
-        private int getNextLocalVar() {
-            return nextLocalVar++;
-        }
-
-        /*
-         * static initializer initializing the static fields
-         *
-         * static Map<String, ModuleDescriptor> map = new HashMap<>();
-         */
-        private void clinit(int numModules, int numPackages) {
-            cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME,
-                     null, "java/lang/Object", null);
-
-            // public static String[] MODULE_NAMES = new String[] {....};
-            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES,
-                    "[Ljava/lang/String;", null, null)
-                    .visitEnd();
-
-            // public static byte[][] MODULES_TO_HASH
-            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULES_TO_HASH,
-                "[[B", null, null)
-                .visitEnd();
-
-            // public static int PACKAGES_IN_BOOT_LAYER;
-            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
-                    "I", null, numPackages)
-                    .visitEnd();
-
-            this.mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
-                    null, null);
-            mv.visitCode();
-
-            // create the MODULE_NAMES array
-            pushInt(numModules);
-            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
-
-            int index = 0;
-            for (ModuleDescriptorBuilder builder : builders) {
-                mv.visitInsn(DUP);                  // arrayref
-                pushInt(index++);
-                mv.visitLdcInsn(builder.md.name()); // value
-                mv.visitInsn(AASTORE);
-            }
-
-            mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
-                    "[Ljava/lang/String;");
-
-            // create the MODULES_TO_HASH array
-            pushInt(numModules);
-            mv.visitTypeInsn(ANEWARRAY, "[B");
-
-            index = 0;
-            for (ModuleDescriptorBuilder builder : builders) {
-                String mn = builder.md.name();
-                byte[] recordedHash = modulesToHash.get(mn);
-                if (recordedHash != null) {
-                    mv.visitInsn(DUP);              // arrayref
-                    pushInt(index);
-                    pushInt(recordedHash.length);
-                    mv.visitIntInsn(NEWARRAY, T_BYTE);
-                    for (int i = 0; i < recordedHash.length; i++) {
-                        mv.visitInsn(DUP);              // arrayref
-                        pushInt(i);
-                        mv.visitIntInsn(BIPUSH, recordedHash[i]);
-                        mv.visitInsn(BASTORE);
-                    }
-                    mv.visitInsn(AASTORE);
-                    modulesToHashIndex.put(mn, index);
-                }
-                index++;
-            }
-
-            mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
-
-            mv.visitInsn(RETURN);
-            mv.visitMaxs(0, 0);
-            mv.visitEnd();
-
-        }
-
-        /*
-         * Adds the given ModuleDescriptor to the system module list, and
-         * prepares mapping from various Sets to SetBuilders to emit an
-         * optimized number of sets during build.
-         */
-        public void addModule(ModuleDescriptor md, Set<String> packages) {
-            ModuleDescriptorBuilder builder = new ModuleDescriptorBuilder(md, packages);
-            builders.add(builder);
-
-            // exports
-            for (Exports e : md.exports()) {
-                dedupSetBuilder.stringSet(e.targets());
-                dedupSetBuilder.exportsModifiers(e.modifiers());
-            }
-
-            // opens
-            for (Opens opens : md.opens()) {
-                dedupSetBuilder.stringSet(opens.targets());
-                dedupSetBuilder.opensModifiers(opens.modifiers());
-            }
-
-            // requires
-            for (Requires r : md.requires()) {
-                dedupSetBuilder.requiresModifiers(r.modifiers());
-            }
-
-            // uses
-            dedupSetBuilder.stringSet(md.uses());
-
-            // hashes
-            JLMA.hashes(md).ifPresent(mh -> modulesToHash.putAll(mh.hashes()));
-        }
-
-        /*
-         * Generate bytecode for SystemModules
-         */
-        public ClassWriter getClassWriter() {
-            int numModules = builders.size();
-            int numPackages = 0;
-            for (ModuleDescriptorBuilder builder : builders) {
-                numPackages += builder.md.packages().size();
-            }
-
-            this.clinit(numModules, numPackages);
-            this.mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
-                                     "modules", "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
-                                     "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE, null);
-            mv.visitCode();
-            pushInt(numModules);
-            mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor");
-            mv.visitVarInsn(ASTORE, MD_VAR);
-
-            for (ModuleDescriptorBuilder builder : builders) {
-                builder.build();
-            }
-            mv.visitVarInsn(ALOAD, MD_VAR);
-            mv.visitInsn(ARETURN);
-            mv.visitMaxs(0, 0);
-            mv.visitEnd();
-            return cw;
-        }
-
-        public boolean isOverriddenClass(String path) {
-            return path.equals("/java.base/" + CLASSNAME + ".class");
-        }
-
-        void pushInt(int num) {
-            if (num <= 5) {
-                mv.visitInsn(ICONST_0 + num);
-            } else if (num < Byte.MAX_VALUE) {
-                mv.visitIntInsn(BIPUSH, num);
-            } else if (num < Short.MAX_VALUE) {
-                mv.visitIntInsn(SIPUSH, num);
-            } else {
-                throw new IllegalArgumentException("exceed limit: " + num);
-            }
-        }
-
-        class ModuleDescriptorBuilder {
-            static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;";
-            static final String EXPORTS_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Exports;";
-            static final String OPENS_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Opens;";
-            static final String PROVIDES_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Provides;";
-            static final String REQUIRES_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Requires;";
-
-            // method signature for static Builder::newExports, newOpens,
-            // newProvides, newRequires methods
-            static final String EXPORTS_MODIFIER_SET_STRING_SET_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
-                    + EXPORTS_TYPE;
-            static final String EXPORTS_MODIFIER_SET_STRING_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;)" + EXPORTS_TYPE;
-            static final String OPENS_MODIFIER_SET_STRING_SET_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
-                    + OPENS_TYPE;
-            static final String OPENS_MODIFIER_SET_STRING_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;)" + OPENS_TYPE;
-            static final String PROVIDES_STRING_LIST_SIG =
-                "(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE;
-            static final String REQUIRES_SET_STRING_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE;
-
-            // method signature for Builder instance methods that
-            // return this Builder instance
-            static final String EXPORTS_ARRAY_SIG =
-                "([" + EXPORTS_TYPE + ")" + BUILDER_TYPE;
-            static final String OPENS_ARRAY_SIG =
-                "([" + OPENS_TYPE + ")" + BUILDER_TYPE;
-            static final String PROVIDES_ARRAY_SIG =
-                "([" + PROVIDES_TYPE + ")" + BUILDER_TYPE;
-            static final String REQUIRES_ARRAY_SIG =
-                "([" + REQUIRES_TYPE + ")" + BUILDER_TYPE;
-            static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE;
-            static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE;
-            static final String STRING_BYTE_ARRAY_SIG =
-                "(Ljava/lang/String;[B)" + BUILDER_TYPE;
-            static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE;
-
-
-            final ModuleDescriptor md;
-            final Set<String> packages;
-
-            ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages) {
-                if (md.isAutomatic()) {
-                    throw new InternalError("linking automatic module is not supported");
-                }
-                this.md = md;
-                this.packages = packages;
-            }
-
-            void build() {
-                // new jdk.internal.module.Builder
-                newBuilder();
-
-                // requires
-                requires(md.requires());
-
-                // exports
-                exports(md.exports());
-
-                // opens
-                opens(md.opens());
-
-                // uses
-                uses(md.uses());
-
-                // provides
-                provides(md.provides());
-
-                // all packages
-                packages(packages);
-
-                // version
-                md.version().ifPresent(this::version);
-
-                // main class
-                md.mainClass().ifPresent(this::mainClass);
-
-                // hashes
-                JLMA.hashes(md).ifPresent(mh -> {
-                    algorithm(mh.algorithm());
-                    mh.names().forEach(mn -> moduleHash(mn, mh.hashFor(mn)));
-                });
-
-                putModuleDescriptor();
-            }
-
-            void newBuilder() {
-                mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
-                mv.visitInsn(DUP);
-                mv.visitLdcInsn(md.name());
-                mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
-                    "<init>", "(Ljava/lang/String;)V", false);
-                mv.visitVarInsn(ASTORE, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-
-                if (md.isOpen()) {
-                    setModuleBit("open", true);
-                }
-                if (md.isSynthetic()) {
-                    setModuleBit("synthetic", true);
-                }
-            }
-
-            /*
-             * Invoke Builder.<methodName>(boolean value)
-             */
-            void setModuleBit(String methodName, boolean value) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                if (value) {
-                    mv.visitInsn(ICONST_1);
-                } else {
-                    mv.visitInsn(ICONST_0);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   methodName, BOOLEAN_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Put ModuleDescriptor into the modules array
-             */
-            void putModuleDescriptor() {
-                mv.visitVarInsn(ALOAD, MD_VAR);
-                pushInt(nextModulesIndex++);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(md.hashCode());
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "build", "(I)Ljava/lang/module/ModuleDescriptor;",
-                                   false);
-                mv.visitInsn(AASTORE);
-            }
-
-            /*
-             * Call Builder::newRequires to create Requires instances and
-             * then pass it to the builder by calling:
-             *      Builder.requires(Requires[])
-             *
-             */
-            void requires(Set<Requires> requires) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                pushInt(requires.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires");
-                int arrayIndex = 0;
-                for (Requires require : requires) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    newRequires(require.modifiers(), require.name());
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "requires", REQUIRES_ARRAY_SIG, false);
-            }
-
-            /*
-             * Invoke Builder.newRequires(Set<Modifier> mods, String mn)
-             *
-             * Set<Modifier> mods = ...
-             * Builder.newRequires(mods, mn);
-             */
-            void newRequires(Set<Requires.Modifier> mods, String name) {
-                int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods);
-                mv.visitVarInsn(ALOAD, varIndex);
-                mv.visitLdcInsn(name);
-                mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                                   "newRequires", REQUIRES_SET_STRING_SIG, false);
-            }
-
-            /*
-             * Call Builder::newExports to create Exports instances and
-             * then pass it to the builder by calling:
-             *      Builder.exports(Exports[])
-             *
-             */
-            void exports(Set<Exports> exports) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                pushInt(exports.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports");
-                int arrayIndex = 0;
-                for (Exports export : exports) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    newExports(export.modifiers(), export.source(), export.targets());
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "exports", EXPORTS_ARRAY_SIG, false);
-            }
-
-            /*
-             * Invoke
-             *     Builder.newExports(Set<Exports.Modifier> ms, String pn,
-             *                        Set<String> targets)
-             * or
-             *     Builder.newExports(Set<Exports.Modifier> ms, String pn)
-             *
-             * Set<String> targets = new HashSet<>();
-             * targets.add(t);
-             * :
-             * :
-             *
-             * Set<Modifier> mods = ...
-             * Builder.newExports(mods, pn, targets);
-             */
-            void newExports(Set<Exports.Modifier> ms, String pn, Set<String> targets) {
-                int modifiersSetIndex = dedupSetBuilder.indexOfExportsModifiers(ms);
-                if (!targets.isEmpty()) {
-                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
-                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
-                    mv.visitLdcInsn(pn);
-                    mv.visitVarInsn(ALOAD, stringSetIndex);
-                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                        "newExports", EXPORTS_MODIFIER_SET_STRING_SET_SIG, false);
-                } else {
-                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
-                    mv.visitLdcInsn(pn);
-                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                        "newExports", EXPORTS_MODIFIER_SET_STRING_SIG, false);
-                }
-            }
-
-
-            /**
-             * Call Builder::newOpens to create Opens instances and
-             * then pass it to the builder by calling:
-             *      Builder.opens(Opens[])
-             *
-             */
-            void opens(Set<Opens> opens) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                pushInt(opens.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens");
-                int arrayIndex = 0;
-                for (Opens open : opens) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    newOpens(open.modifiers(), open.source(), open.targets());
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                        "opens", OPENS_ARRAY_SIG, false);
-            }
-
-            /*
-             * Invoke
-             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn,
-             *                        Set<String> targets)
-             * or
-             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn)
-             *
-             * Set<String> targets = new HashSet<>();
-             * targets.add(t);
-             * :
-             * :
-             *
-             * Set<Modifier> mods = ...
-             * Builder.newOpens(mods, pn, targets);
-             */
-            void newOpens(Set<Opens.Modifier> ms, String pn, Set<String> targets) {
-                int modifiersSetIndex = dedupSetBuilder.indexOfOpensModifiers(ms);
-                if (!targets.isEmpty()) {
-                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
-                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
-                    mv.visitLdcInsn(pn);
-                    mv.visitVarInsn(ALOAD, stringSetIndex);
-                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                            "newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false);
-                } else {
-                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
-                    mv.visitLdcInsn(pn);
-                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                            "newOpens", OPENS_MODIFIER_SET_STRING_SIG, false);
-                }
-            }
-
-            /*
-             * Invoke Builder.uses(Set<String> uses)
-             */
-            void uses(Set<String> uses) {
-                int varIndex = dedupSetBuilder.indexOfStringSet(uses);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, varIndex);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "uses", SET_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-            * Call Builder::newProvides to create Provides instances and
-            * then pass it to the builder by calling:
-            *      Builder.provides(Provides[] provides)
-            *
-            */
-            void provides(Collection<Provides> provides) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                pushInt(provides.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides");
-                int arrayIndex = 0;
-                for (Provides provide : provides) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    newProvides(provide.service(), provide.providers());
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "provides", PROVIDES_ARRAY_SIG, false);
-            }
-
-            /*
-             * Invoke Builder.newProvides(String service, Set<String> providers)
-             *
-             * Set<String> providers = new HashSet<>();
-             * providers.add(impl);
-             * :
-             * :
-             * Builder.newProvides(service, providers);
-             */
-            void newProvides(String service, List<String> providers) {
-                mv.visitLdcInsn(service);
-                pushInt(providers.size());
-                mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
-                int arrayIndex = 0;
-                for (String provider : providers) {
-                    mv.visitInsn(DUP);    // arrayref
-                    pushInt(arrayIndex++);
-                    mv.visitLdcInsn(provider);
-                    mv.visitInsn(AASTORE);
-                }
-                mv.visitMethodInsn(INVOKESTATIC, "java/util/List",
-                                   "of", "([Ljava/lang/Object;)Ljava/util/List;", true);
-                mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
-                                   "newProvides", PROVIDES_STRING_LIST_SIG, false);
-            }
-
-            /*
-             * Invoke Builder.packages(String pn)
-             */
-            void packages(Set<String> packages) {
-                int varIndex = dedupSetBuilder.newStringSet(packages);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, varIndex);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "packages", SET_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.mainClass(String cn)
-             */
-            void mainClass(String cn) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(cn);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "mainClass", STRING_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.version(Version v);
-             */
-            void version(Version v) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(v.toString());
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "version", STRING_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.algorithm(String a);
-             */
-            void algorithm(String alg) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(alg);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "algorithm", STRING_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.moduleHash(String name, byte[] hash);
-             */
-            void moduleHash(String name, byte[] hash) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(name);
-
-                // must exist
-                Integer index = modulesToHashIndex.get(name);
-                if (index != null) {
-                    mv.visitFieldInsn(GETSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
-                    pushInt(index);
-                    mv.visitInsn(AALOAD);
-                    assert(Objects.equals(hash, modulesToHash.get(name)));
-                } else {
-                    pushInt(hash.length);
-                    mv.visitIntInsn(NEWARRAY, T_BYTE);
-                    for (int i = 0; i < hash.length; i++) {
-                        mv.visitInsn(DUP);              // arrayref
-                        pushInt(i);
-                        mv.visitIntInsn(BIPUSH, hash[i]);
-                        mv.visitInsn(BASTORE);
-                    }
-                }
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "moduleHash", STRING_BYTE_ARRAY_SIG, false);
-                mv.visitInsn(POP);
-            }
-        }
-
-        /*
-         * Wraps set creation, ensuring identical sets are properly deduplicated.
-         */
-        class DedupSetBuilder {
-            // map Set<String> to a specialized builder to allow them to be
-            // deduplicated as they are requested
-            final Map<Set<String>, SetBuilder<String>> stringSets = new HashMap<>();
-
-            // map Set<Requires.Modifier> to a specialized builder to allow them to be
-            // deduplicated as they are requested
-            final Map<Set<Requires.Modifier>, EnumSetBuilder<Requires.Modifier>>
-                requiresModifiersSets = new HashMap<>();
-
-            // map Set<Exports.Modifier> to a specialized builder to allow them to be
-            // deduplicated as they are requested
-            final Map<Set<Exports.Modifier>, EnumSetBuilder<Exports.Modifier>>
-                exportsModifiersSets = new HashMap<>();
-
-            // map Set<Opens.Modifier> to a specialized builder to allow them to be
-            // deduplicated as they are requested
-            final Map<Set<Opens.Modifier>, EnumSetBuilder<Opens.Modifier>>
-                opensModifiersSets = new HashMap<>();
-
-            private final int stringSetVar;
-            private final int enumSetVar;
-            private final IntSupplier localVarSupplier;
-
-            DedupSetBuilder(IntSupplier localVarSupplier) {
-                this.stringSetVar = localVarSupplier.getAsInt();
-                this.enumSetVar = localVarSupplier.getAsInt();
-                this.localVarSupplier = localVarSupplier;
-            }
-
-            /*
-             * Add the given set of strings to this builder.
-             */
-            void stringSet(Set<String> strings) {
-                stringSets.computeIfAbsent(strings,
-                    s -> new SetBuilder<>(s, stringSetVar, localVarSupplier)
-                ).increment();
-            }
-
-            /*
-             * Add the given set of Exports.Modifiers
-             */
-            void exportsModifiers(Set<Exports.Modifier> mods) {
-                exportsModifiersSets.computeIfAbsent(mods, s ->
-                                new EnumSetBuilder<>(s, EXPORTS_MODIFIER_CLASSNAME,
-                                        enumSetVar, localVarSupplier)
-                ).increment();
-            }
-
-            /*
-             * Add the given set of Opens.Modifiers
-             */
-            void opensModifiers(Set<Opens.Modifier> mods) {
-                opensModifiersSets.computeIfAbsent(mods, s ->
-                                new EnumSetBuilder<>(s, OPENS_MODIFIER_CLASSNAME,
-                                        enumSetVar, localVarSupplier)
-                ).increment();
-            }
-
-            /*
-             * Add the given set of Requires.Modifiers
-             */
-            void requiresModifiers(Set<Requires.Modifier> mods) {
-                requiresModifiersSets.computeIfAbsent(mods, s ->
-                    new EnumSetBuilder<>(s, REQUIRES_MODIFIER_CLASSNAME,
-                                         enumSetVar, localVarSupplier)
-                ).increment();
-            }
-
-            /*
-             * Retrieve the index to the given set of Strings. Emit code to
-             * generate it when SetBuilder::build is called.
-             */
-            int indexOfStringSet(Set<String> names) {
-                return stringSets.get(names).build();
-            }
-
-            /*
-             * Retrieve the index to the given set of Exports.Modifier.
-             * Emit code to generate it when EnumSetBuilder::build is called.
-             */
-            int indexOfExportsModifiers(Set<Exports.Modifier> mods) {
-                return exportsModifiersSets.get(mods).build();
-            }
-
-            /**
-             * Retrieve the index to the given set of Opens.Modifier.
-             * Emit code to generate it when EnumSetBuilder::build is called.
-             */
-            int indexOfOpensModifiers(Set<Opens.Modifier> mods) {
-                return opensModifiersSets.get(mods).build();
-            }
-
-
-            /*
-             * Retrieve the index to the given set of Requires.Modifier.
-             * Emit code to generate it when EnumSetBuilder::build is called.
-             */
-            int indexOfRequiresModifiers(Set<Requires.Modifier> mods) {
-                return requiresModifiersSets.get(mods).build();
-            }
-
-            /*
-             * Build a new string set without any attempt to deduplicate it.
-             */
-            int newStringSet(Set<String> names) {
-                int index = new SetBuilder<>(names, stringSetVar, localVarSupplier).build();
-                assert index == stringSetVar;
-                return index;
-            }
-        }
-
-        /*
-         * SetBuilder generates bytecode to create one single instance of Set
-         * for a given set of elements and assign to a local variable slot.
-         * When there is only one single reference to a Set<T>,
-         * it will reuse defaultVarIndex.  For a Set with multiple references,
-         * it will use a new local variable retrieved from the nextLocalVar
-         */
-        class SetBuilder<T> {
-            private final Set<T> elements;
-            private final int defaultVarIndex;
-            private final IntSupplier nextLocalVar;
-            private int refCount;
-            private int localVarIndex;
-
-            SetBuilder(Set<T> elements,
-                       int defaultVarIndex,
-                       IntSupplier nextLocalVar) {
-                this.elements = elements;
-                this.defaultVarIndex = defaultVarIndex;
-                this.nextLocalVar = nextLocalVar;
-            }
-
-            /*
-             * Increments the number of references to this particular set.
-             */
-            final void increment() {
-                refCount++;
-            }
-
-            /**
-             * Generate the appropriate instructions to load an object reference
-             * to the element onto the stack.
-             */
-            void visitElement(T element, MethodVisitor mv) {
-                mv.visitLdcInsn(element);
-            }
-
-            /*
-             * Build bytecode for the Set represented by this builder,
-             * or get the local variable index of a previously generated set
-             * (in the local scope).
-             *
-             * @return local variable index of the generated set.
-             */
-            final int build() {
-                int index = localVarIndex;
-                if (localVarIndex == 0) {
-                    // if non-empty and more than one set reference this builder,
-                    // emit to a unique local
-                    index = refCount <= 1 ? defaultVarIndex
-                                          : nextLocalVar.getAsInt();
-                    if (index < MAX_LOCAL_VARS) {
-                        localVarIndex = index;
-                    } else {
-                        // overflow: disable optimization by using localVarIndex = 0
-                        index = defaultVarIndex;
-                    }
-
-                    generateSetOf(index);
-                }
-                return index;
-            }
-
-            private void generateSetOf(int index) {
-                if (elements.size() <= 10) {
-                    // call Set.of(e1, e2, ...)
-                    StringBuilder sb = new StringBuilder("(");
-                    for (T t : elements) {
-                        sb.append("Ljava/lang/Object;");
-                        visitElement(t, mv);
-                    }
-                    sb.append(")Ljava/util/Set;");
-                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
-                            "of", sb.toString(), true);
-                } else {
-                    // call Set.of(E... elements)
-                    pushInt(elements.size());
-                    mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
-                    int arrayIndex = 0;
-                    for (T t : elements) {
-                        mv.visitInsn(DUP);    // arrayref
-                        pushInt(arrayIndex);
-                        visitElement(t, mv);  // value
-                        mv.visitInsn(AASTORE);
-                        arrayIndex++;
-                    }
-                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
-                            "of", "([Ljava/lang/Object;)Ljava/util/Set;", true);
-                }
-                mv.visitVarInsn(ASTORE, index);
-            }
-        }
-
-        /*
-         * Generates bytecode to create one single instance of EnumSet
-         * for a given set of modifiers and assign to a local variable slot.
-         */
-        class EnumSetBuilder<T> extends SetBuilder<T> {
-
-            private final String className;
-
-            EnumSetBuilder(Set<T> modifiers, String className,
-                           int defaultVarIndex,
-                           IntSupplier nextLocalVar) {
-                super(modifiers, defaultVarIndex, nextLocalVar);
-                this.className = className;
-            }
-
-            /**
-             * Loads an Enum field.
-             */
-            void visitElement(T t, MethodVisitor mv) {
-                mv.visitFieldInsn(GETSTATIC, className, t.toString(),
-                                  "L" + className + ";");
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,1246 @@
+/*
+ * 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 jdk.tools.jlink.internal.plugins;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.IntSupplier;
+
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Checks;
+import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo.Attributes;
+import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModuleResolution;
+import jdk.internal.module.SystemModules;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.ResourcePool;
+import jdk.tools.jlink.plugin.Plugin;
+import jdk.tools.jlink.plugin.ResourcePoolBuilder;
+import jdk.tools.jlink.plugin.ResourcePoolEntry;
+
+/**
+ * Jlink plugin to reconstitute module descriptors for system modules.
+ * It will extend module-info.class with Packages attribute,
+ * if not present. It also determines the number of packages of
+ * the boot layer at link time.
+ *
+ * This plugin will override jdk.internal.module.SystemModules class
+ *
+ * @see jdk.internal.module.SystemModuleFinder
+ * @see SystemModules
+ */
+public final class SystemModulesPlugin implements Plugin {
+    private static final JavaLangModuleAccess JLMA =
+        SharedSecrets.getJavaLangModuleAccess();
+
+    private static final String NAME = "system-modules";
+    private static final String DESCRIPTION =
+        PluginsResourceBundle.getDescription(NAME);
+
+    private boolean enabled;
+    public SystemModulesPlugin() {
+        this.enabled = true;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public String getDescription() {
+        return DESCRIPTION;
+    }
+
+    @Override
+    public Set<State> getState() {
+        return enabled ? EnumSet.of(State.AUTO_ENABLED, State.FUNCTIONAL)
+                       : EnumSet.of(State.DISABLED);
+    }
+
+    @Override
+    public void configure(Map<String, String> config) {
+        if (config.containsKey(NAME)) {
+            enabled = false;
+        }
+    }
+
+    @Override
+    public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
+        if (!enabled) {
+            throw new PluginException(NAME + " was set");
+        }
+
+        SystemModulesClassGenerator generator = new SystemModulesClassGenerator();
+
+        // generate the byte code to create ModuleDescriptors
+        // skip parsing module-info.class and skip name check
+        in.moduleView().modules().forEach(module -> {
+
+            ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
+                // automatic module not supported yet
+                () ->  new PluginException("module-info.class not found for " +
+                    module.name() + " module")
+            );
+
+            assert module.name().equals(data.moduleName());
+            try {
+                ModuleInfo moduleInfo = new ModuleInfo(data.contentBytes(), module.packages());
+                generator.addModule(moduleInfo);
+
+                // link-time validation
+                moduleInfo.validateNames();
+                // check if any exported or open package is not present
+                moduleInfo.validatePackages();
+
+                // Packages attribute needs update
+                if (moduleInfo.shouldAddPackagesAttribute()) {
+                    // replace with the overridden version
+                    data = data.copyWithContent(moduleInfo.getBytes());
+                }
+                out.add(data);
+            } catch (IOException e) {
+                throw new PluginException(e);
+            }
+        });
+
+        // Generate the new class
+        ClassWriter cwriter = generator.getClassWriter();
+        in.entries().forEach(data -> {
+            if (data.path().endsWith("module-info.class"))
+                return;
+            if (generator.isOverriddenClass(data.path())) {
+                byte[] bytes = cwriter.toByteArray();
+                ResourcePoolEntry ndata = data.copyWithContent(bytes);
+                out.add(ndata);
+            } else {
+                out.add(data);
+            }
+        });
+
+        return out.build();
+    }
+
+    class ModuleInfo {
+        final ModuleDescriptor descriptor;
+        final ModuleHashes recordedHashes;
+        final ModuleResolution moduleResolution;
+        final Set<String> packages;
+        final ByteArrayInputStream bain;
+
+        ModuleInfo(byte[] bytes, Set<String> packages) throws IOException {
+            this.bain = new ByteArrayInputStream(bytes);
+            this.packages = packages;
+
+            Attributes attrs = jdk.internal.module.ModuleInfo.read(bain, null);
+            this.descriptor = attrs.descriptor();
+            this.recordedHashes = attrs.recordedHashes();
+            this.moduleResolution = attrs.moduleResolution();
+
+            if (descriptor.isAutomatic()) {
+                throw new InternalError("linking automatic module is not supported");
+            }
+        }
+
+        String moduleName() {
+            return descriptor.name();
+        }
+
+        /**
+         * Validates names in ModuleDescriptor
+         */
+        void validateNames() {
+            Checks.requireModuleName(descriptor.name());
+            for (Requires req : descriptor.requires()) {
+                Checks.requireModuleName(req.name());
+            }
+            for (Exports e : descriptor.exports()) {
+                Checks.requirePackageName(e.source());
+                if (e.isQualified())
+                    e.targets().forEach(Checks::requireModuleName);
+            }
+            for (Opens opens : descriptor.opens()) {
+                Checks.requirePackageName(opens.source());
+                if (opens.isQualified())
+                    opens.targets().forEach(Checks::requireModuleName);
+            }
+            for (Provides provides : descriptor.provides()) {
+                Checks.requireServiceTypeName(provides.service());
+                provides.providers().forEach(Checks::requireServiceProviderName);
+            }
+            for (String service : descriptor.uses()) {
+                Checks.requireServiceTypeName(service);
+            }
+            for (String pn : descriptor.packages()) {
+                Checks.requirePackageName(pn);
+            }
+        }
+
+
+        /**
+         * Validates if exported and open packages are present
+         */
+        void validatePackages() {
+            Set<String> nonExistPackages = new TreeSet<>();
+            descriptor.exports().stream()
+                .map(Exports::source)
+                .filter(pn -> !packages.contains(pn))
+                .forEach(nonExistPackages::add);
+
+            descriptor.opens().stream()
+                .map(Opens::source)
+                .filter(pn -> !packages.contains(pn))
+                .forEach(nonExistPackages::add);
+
+            if (!nonExistPackages.isEmpty()) {
+                throw new PluginException("Packages that are exported or open in "
+                    + descriptor.name() + " are not present: " + nonExistPackages);
+            }
+        }
+
+        /**
+         * Returns true if the PackagesAttribute should be written
+         */
+        boolean shouldAddPackagesAttribute() {
+            return descriptor.packages().isEmpty() && packages.size() > 0;
+        }
+
+        /**
+         * Returns the bytes for the module-info.class with PackagesAttribute
+         * if it contains at least one package
+         */
+        byte[] getBytes() throws IOException {
+            bain.reset();
+
+            // add Packages attribute if not exist
+            if (shouldAddPackagesAttribute()) {
+                return new ModuleInfoRewriter(bain, packages).getBytes();
+            } else {
+                return bain.readAllBytes();
+            }
+        }
+
+        class ModuleInfoRewriter extends ByteArrayOutputStream {
+            final ModuleInfoExtender extender;
+            ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
+                this.extender = ModuleInfoExtender.newExtender(in);
+                // Add Packages attribute
+                if (packages.size() > 0) {
+                    this.extender.packages(packages);
+                }
+                this.extender.write(this);
+            }
+
+            byte[] getBytes() {
+                return buf;
+            }
+        }
+    }
+
+    /**
+     * ClassWriter of a new jdk.internal.module.SystemModules class
+     * to reconstitute ModuleDescriptor of the system modules.
+     */
+    static class SystemModulesClassGenerator {
+        private static final String CLASSNAME =
+            "jdk/internal/module/SystemModules";
+        private static final String MODULE_DESCRIPTOR_BUILDER =
+            "jdk/internal/module/Builder";
+        private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE =
+            "[Ljava/lang/module/ModuleDescriptor;";
+        private static final String REQUIRES_MODIFIER_CLASSNAME =
+            "java/lang/module/ModuleDescriptor$Requires$Modifier";
+        private static final String EXPORTS_MODIFIER_CLASSNAME =
+            "java/lang/module/ModuleDescriptor$Exports$Modifier";
+        private static final String OPENS_MODIFIER_CLASSNAME =
+            "java/lang/module/ModuleDescriptor$Opens$Modifier";
+        private static final String MODULE_HASHES_ARRAY_SIGNATURE  =
+            "[Ljdk/internal/module/ModuleHashes;";
+        private static final String MODULE_RESOLUTION_CLASSNAME  =
+            "jdk/internal/module/ModuleResolution";
+        private static final String MODULE_RESOLUTIONS_ARRAY_SIGNATURE  =
+            "[Ljdk/internal/module/ModuleResolution;";
+
+        // static variables in SystemModules class
+        private static final String MODULE_NAMES = "MODULE_NAMES";
+        private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
+
+        private static final int MAX_LOCAL_VARS = 256;
+
+        private final int BUILDER_VAR    = 0;
+        private final int MD_VAR         = 1;  // variable for ModuleDescriptor
+        private final int MH_VAR         = 1;  // variable for ModuleHashes
+        private int nextLocalVar         = 2;  // index to next local variable
+
+        private final ClassWriter cw;
+
+        // Method visitor for generating the SystemModules::modules() method
+        private MethodVisitor mv;
+
+        // list of all ModuleDescriptorBuilders, invoked in turn when building.
+        private final List<ModuleInfo> moduleInfos = new ArrayList<>();
+
+        // A builder to create one single Set instance for a given set of
+        // names or modifiers to reduce the footprint
+        // e.g. target modules of qualified exports
+        private final DedupSetBuilder dedupSetBuilder
+            = new DedupSetBuilder(this::getNextLocalVar);
+
+        public SystemModulesClassGenerator() {
+            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
+                                      ClassWriter.COMPUTE_FRAMES);
+        }
+
+        private int getNextLocalVar() {
+            return nextLocalVar++;
+        }
+
+        /*
+         * static initializer initializing the static fields
+         *
+         * static Map<String, ModuleDescriptor> map = new HashMap<>();
+         */
+        private void clinit(int numModules, int numPackages) {
+            cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME,
+                     null, "java/lang/Object", null);
+
+            // public static String[] MODULE_NAMES = new String[] {....};
+            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES,
+                    "[Ljava/lang/String;", null, null)
+                    .visitEnd();
+
+            // public static int PACKAGES_IN_BOOT_LAYER;
+            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
+                    "I", null, numPackages)
+                    .visitEnd();
+
+            MethodVisitor clinit =
+                cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
+                               null, null);
+            clinit.visitCode();
+
+            // create the MODULE_NAMES array
+            pushInt(clinit, numModules);
+            clinit.visitTypeInsn(ANEWARRAY, "java/lang/String");
+
+            int index = 0;
+            for (ModuleInfo minfo : moduleInfos) {
+                clinit.visitInsn(DUP);                  // arrayref
+                pushInt(clinit, index++);
+                clinit.visitLdcInsn(minfo.moduleName()); // value
+                clinit.visitInsn(AASTORE);
+            }
+
+            clinit.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
+                    "[Ljava/lang/String;");
+
+            clinit.visitInsn(RETURN);
+            clinit.visitMaxs(0, 0);
+            clinit.visitEnd();
+        }
+
+        /*
+         * Adds the given ModuleDescriptor to the system module list, and
+         * prepares mapping from various Sets to SetBuilders to emit an
+         * optimized number of sets during build.
+         */
+        public void addModule(ModuleInfo moduleInfo) {
+            ModuleDescriptor md = moduleInfo.descriptor;
+            moduleInfos.add(moduleInfo);
+
+            // exports
+            for (Exports e : md.exports()) {
+                dedupSetBuilder.stringSet(e.targets());
+                dedupSetBuilder.exportsModifiers(e.modifiers());
+            }
+
+            // opens
+            for (Opens opens : md.opens()) {
+                dedupSetBuilder.stringSet(opens.targets());
+                dedupSetBuilder.opensModifiers(opens.modifiers());
+            }
+
+            // requires
+            for (Requires r : md.requires()) {
+                dedupSetBuilder.requiresModifiers(r.modifiers());
+            }
+
+            // uses
+            dedupSetBuilder.stringSet(md.uses());
+        }
+
+        /*
+         * Generate bytecode for SystemModules
+         */
+        public ClassWriter getClassWriter() {
+            int numModules = moduleInfos.size();
+            int numPackages = 0;
+            for (ModuleInfo minfo : moduleInfos) {
+                numPackages += minfo.packages.size();
+            }
+
+            clinit(numModules, numPackages);
+
+            // generate SystemModules::descriptors
+            genDescriptorsMethod();
+            // generate SystemModules::hashes
+            genHashesMethod();
+            // generate SystemModules::moduleResolutions
+            genModuleResolutionsMethod();
+
+            return cw;
+        }
+
+        /*
+         * Generate bytecode for SystemModules::descriptors method
+         */
+        private void genDescriptorsMethod() {
+            this.mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
+                                     "descriptors",
+                                     "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
+                                     "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
+                                     null);
+            mv.visitCode();
+            pushInt(mv, moduleInfos.size());
+            mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor");
+            mv.visitVarInsn(ASTORE, MD_VAR);
+
+            for (int index = 0; index < moduleInfos.size(); index++) {
+                ModuleInfo minfo = moduleInfos.get(index);
+                new ModuleDescriptorBuilder(minfo.descriptor,
+                                            minfo.packages,
+                                            index).build();
+            }
+            mv.visitVarInsn(ALOAD, MD_VAR);
+            mv.visitInsn(ARETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+
+        }
+
+        /*
+         * Generate bytecode for SystemModules::hashes method
+         */
+        private void genHashesMethod() {
+            MethodVisitor hmv =
+                cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
+                               "hashes",
+                               "()" + MODULE_HASHES_ARRAY_SIGNATURE,
+                               "()" + MODULE_HASHES_ARRAY_SIGNATURE,
+                               null);
+            hmv.visitCode();
+            pushInt(hmv, moduleInfos.size());
+            hmv.visitTypeInsn(ANEWARRAY, "jdk/internal/module/ModuleHashes");
+            hmv.visitVarInsn(ASTORE, MH_VAR);
+
+            for (int index = 0; index < moduleInfos.size(); index++) {
+                ModuleInfo minfo = moduleInfos.get(index);
+                if (minfo.recordedHashes != null) {
+                    new ModuleHashesBuilder(minfo.recordedHashes,
+                                            index,
+                                            hmv).build();
+                }
+            }
+
+            hmv.visitVarInsn(ALOAD, MH_VAR);
+            hmv.visitInsn(ARETURN);
+            hmv.visitMaxs(0, 0);
+            hmv.visitEnd();
+
+        }
+
+        /*
+         * Generate bytecode for SystemModules::methodResoultions method
+         */
+        private void genModuleResolutionsMethod() {
+            MethodVisitor mresmv =
+                cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+                               "moduleResolutions",
+                               "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
+                               "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
+                               null);
+            mresmv.visitCode();
+            pushInt(mresmv, moduleInfos.size());
+            mresmv.visitTypeInsn(ANEWARRAY, MODULE_RESOLUTION_CLASSNAME);
+            mresmv.visitVarInsn(ASTORE, 0);
+
+            for (int index=0; index < moduleInfos.size(); index++) {
+                ModuleInfo minfo = moduleInfos.get(index);
+                if (minfo.moduleResolution != null) {
+                    mresmv.visitVarInsn(ALOAD, 0);
+                    pushInt(mresmv, index);
+                    mresmv.visitTypeInsn(NEW, MODULE_RESOLUTION_CLASSNAME);
+                    mresmv.visitInsn(DUP);
+                    mresmv.visitLdcInsn(minfo.moduleResolution.value());
+                    mresmv.visitMethodInsn(INVOKESPECIAL,
+                                           MODULE_RESOLUTION_CLASSNAME,
+                                           "<init>",
+                                           "(I)V", false);
+                    mresmv.visitInsn(AASTORE);
+                }
+            }
+            mresmv.visitVarInsn(ALOAD, 0);
+            mresmv.visitInsn(ARETURN);
+            mresmv.visitMaxs(0, 0);
+            mresmv.visitEnd();
+        }
+
+        public boolean isOverriddenClass(String path) {
+            return path.equals("/java.base/" + CLASSNAME + ".class");
+        }
+
+        void pushInt(MethodVisitor mv, int num) {
+            if (num <= 5) {
+                mv.visitInsn(ICONST_0 + num);
+            } else if (num < Byte.MAX_VALUE) {
+                mv.visitIntInsn(BIPUSH, num);
+            } else if (num < Short.MAX_VALUE) {
+                mv.visitIntInsn(SIPUSH, num);
+            } else {
+                throw new IllegalArgumentException("exceed limit: " + num);
+            }
+        }
+
+        class ModuleDescriptorBuilder {
+            static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;";
+            static final String EXPORTS_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Exports;";
+            static final String OPENS_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Opens;";
+            static final String PROVIDES_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Provides;";
+            static final String REQUIRES_TYPE =
+                "Ljava/lang/module/ModuleDescriptor$Requires;";
+
+            // method signature for static Builder::newExports, newOpens,
+            // newProvides, newRequires methods
+            static final String EXPORTS_MODIFIER_SET_STRING_SET_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
+                    + EXPORTS_TYPE;
+            static final String EXPORTS_MODIFIER_SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + EXPORTS_TYPE;
+            static final String OPENS_MODIFIER_SET_STRING_SET_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;Ljava/util/Set;)"
+                    + OPENS_TYPE;
+            static final String OPENS_MODIFIER_SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + OPENS_TYPE;
+            static final String PROVIDES_STRING_LIST_SIG =
+                "(Ljava/lang/String;Ljava/util/List;)" + PROVIDES_TYPE;
+            static final String REQUIRES_SET_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;)" + REQUIRES_TYPE;
+            static final String REQUIRES_SET_STRING_STRING_SIG =
+                "(Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;)" + REQUIRES_TYPE;
+
+            // method signature for Builder instance methods that
+            // return this Builder instance
+            static final String EXPORTS_ARRAY_SIG =
+                "([" + EXPORTS_TYPE + ")" + BUILDER_TYPE;
+            static final String OPENS_ARRAY_SIG =
+                "([" + OPENS_TYPE + ")" + BUILDER_TYPE;
+            static final String PROVIDES_ARRAY_SIG =
+                "([" + PROVIDES_TYPE + ")" + BUILDER_TYPE;
+            static final String REQUIRES_ARRAY_SIG =
+                "([" + REQUIRES_TYPE + ")" + BUILDER_TYPE;
+            static final String SET_SIG = "(Ljava/util/Set;)" + BUILDER_TYPE;
+            static final String STRING_SIG = "(Ljava/lang/String;)" + BUILDER_TYPE;
+            static final String BOOLEAN_SIG = "(Z)" + BUILDER_TYPE;
+
+            final ModuleDescriptor md;
+            final Set<String> packages;
+            final int index;
+            ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages, int index) {
+                if (md.isAutomatic()) {
+                    throw new InternalError("linking automatic module is not supported");
+                }
+                this.md = md;
+                this.packages = packages;
+                this.index = index;
+            }
+
+            void build() {
+                // new jdk.internal.module.Builder
+                newBuilder();
+
+                // requires
+                requires(md.requires());
+
+                // exports
+                exports(md.exports());
+
+                // opens
+                opens(md.opens());
+
+                // uses
+                uses(md.uses());
+
+                // provides
+                provides(md.provides());
+
+                // all packages
+                packages(packages);
+
+                // version
+                md.version().ifPresent(this::version);
+
+                // main class
+                md.mainClass().ifPresent(this::mainClass);
+
+                putModuleDescriptor();
+            }
+
+            void newBuilder() {
+                mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
+                mv.visitInsn(DUP);
+                mv.visitLdcInsn(md.name());
+                mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
+                    "<init>", "(Ljava/lang/String;)V", false);
+                mv.visitVarInsn(ASTORE, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+
+                if (md.isOpen()) {
+                    setModuleBit("open", true);
+                }
+                if (md.isSynthetic()) {
+                    setModuleBit("synthetic", true);
+                }
+            }
+
+            /*
+             * Invoke Builder.<methodName>(boolean value)
+             */
+            void setModuleBit(String methodName, boolean value) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                if (value) {
+                    mv.visitInsn(ICONST_1);
+                } else {
+                    mv.visitInsn(ICONST_0);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    methodName, BOOLEAN_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Put ModuleDescriptor into the modules array
+             */
+            void putModuleDescriptor() {
+                mv.visitVarInsn(ALOAD, MD_VAR);
+                pushInt(mv, index);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(md.hashCode());
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "build", "(I)Ljava/lang/module/ModuleDescriptor;",
+                    false);
+                mv.visitInsn(AASTORE);
+            }
+
+            /*
+             * Call Builder::newRequires to create Requires instances and
+             * then pass it to the builder by calling:
+             *      Builder.requires(Requires[])
+             *
+             */
+            void requires(Set<Requires> requires) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                pushInt(mv, requires.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Requires");
+                int arrayIndex = 0;
+                for (Requires require : requires) {
+                    String compiledVersion = null;
+                    if (require.compiledVersion().isPresent()) {
+                        compiledVersion = require.compiledVersion().get().toString();
+                    }
+
+                    mv.visitInsn(DUP);               // arrayref
+                    pushInt(mv, arrayIndex++);
+                    newRequires(require.modifiers(), require.name(), compiledVersion);
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "requires", REQUIRES_ARRAY_SIG, false);
+            }
+
+            /*
+             * Invoke Builder.newRequires(Set<Modifier> mods, String mn, String compiledVersion)
+             *
+             * Set<Modifier> mods = ...
+             * Builder.newRequires(mods, mn, compiledVersion);
+             */
+            void newRequires(Set<Requires.Modifier> mods, String name, String compiledVersion) {
+                int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods);
+                mv.visitVarInsn(ALOAD, varIndex);
+                mv.visitLdcInsn(name);
+                if (compiledVersion != null) {
+                    mv.visitLdcInsn(compiledVersion);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newRequires", REQUIRES_SET_STRING_STRING_SIG, false);
+                } else {
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newRequires", REQUIRES_SET_STRING_SIG, false);
+                }
+            }
+
+            /*
+             * Call Builder::newExports to create Exports instances and
+             * then pass it to the builder by calling:
+             *      Builder.exports(Exports[])
+             *
+             */
+            void exports(Set<Exports> exports) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                pushInt(mv, exports.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Exports");
+                int arrayIndex = 0;
+                for (Exports export : exports) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(mv, arrayIndex++);
+                    newExports(export.modifiers(), export.source(), export.targets());
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "exports", EXPORTS_ARRAY_SIG, false);
+            }
+
+            /*
+             * Invoke
+             *     Builder.newExports(Set<Exports.Modifier> ms, String pn,
+             *                        Set<String> targets)
+             * or
+             *     Builder.newExports(Set<Exports.Modifier> ms, String pn)
+             *
+             * Set<String> targets = new HashSet<>();
+             * targets.add(t);
+             * :
+             * :
+             *
+             * Set<Modifier> mods = ...
+             * Builder.newExports(mods, pn, targets);
+             */
+            void newExports(Set<Exports.Modifier> ms, String pn, Set<String> targets) {
+                int modifiersSetIndex = dedupSetBuilder.indexOfExportsModifiers(ms);
+                if (!targets.isEmpty()) {
+                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitVarInsn(ALOAD, stringSetIndex);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newExports", EXPORTS_MODIFIER_SET_STRING_SET_SIG, false);
+                } else {
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newExports", EXPORTS_MODIFIER_SET_STRING_SIG, false);
+                }
+            }
+
+
+            /**
+             * Call Builder::newOpens to create Opens instances and
+             * then pass it to the builder by calling:
+             * Builder.opens(Opens[])
+             */
+            void opens(Set<Opens> opens) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                pushInt(mv, opens.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Opens");
+                int arrayIndex = 0;
+                for (Opens open : opens) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(mv, arrayIndex++);
+                    newOpens(open.modifiers(), open.source(), open.targets());
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "opens", OPENS_ARRAY_SIG, false);
+            }
+
+            /*
+             * Invoke
+             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn,
+             *                        Set<String> targets)
+             * or
+             *     Builder.newOpens(Set<Opens.Modifier> ms, String pn)
+             *
+             * Set<String> targets = new HashSet<>();
+             * targets.add(t);
+             * :
+             * :
+             *
+             * Set<Modifier> mods = ...
+             * Builder.newOpens(mods, pn, targets);
+             */
+            void newOpens(Set<Opens.Modifier> ms, String pn, Set<String> targets) {
+                int modifiersSetIndex = dedupSetBuilder.indexOfOpensModifiers(ms);
+                if (!targets.isEmpty()) {
+                    int stringSetIndex = dedupSetBuilder.indexOfStringSet(targets);
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitVarInsn(ALOAD, stringSetIndex);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newOpens", OPENS_MODIFIER_SET_STRING_SET_SIG, false);
+                } else {
+                    mv.visitVarInsn(ALOAD, modifiersSetIndex);
+                    mv.visitLdcInsn(pn);
+                    mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                        "newOpens", OPENS_MODIFIER_SET_STRING_SIG, false);
+                }
+            }
+
+            /*
+             * Invoke Builder.uses(Set<String> uses)
+             */
+            void uses(Set<String> uses) {
+                int varIndex = dedupSetBuilder.indexOfStringSet(uses);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, varIndex);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "uses", SET_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+            * Call Builder::newProvides to create Provides instances and
+            * then pass it to the builder by calling:
+            *      Builder.provides(Provides[] provides)
+            *
+            */
+            void provides(Collection<Provides> provides) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                pushInt(mv, provides.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/module/ModuleDescriptor$Provides");
+                int arrayIndex = 0;
+                for (Provides provide : provides) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(mv, arrayIndex++);
+                    newProvides(provide.service(), provide.providers());
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "provides", PROVIDES_ARRAY_SIG, false);
+            }
+
+            /*
+             * Invoke Builder.newProvides(String service, Set<String> providers)
+             *
+             * Set<String> providers = new HashSet<>();
+             * providers.add(impl);
+             * :
+             * :
+             * Builder.newProvides(service, providers);
+             */
+            void newProvides(String service, List<String> providers) {
+                mv.visitLdcInsn(service);
+                pushInt(mv, providers.size());
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+                int arrayIndex = 0;
+                for (String provider : providers) {
+                    mv.visitInsn(DUP);    // arrayref
+                    pushInt(mv, arrayIndex++);
+                    mv.visitLdcInsn(provider);
+                    mv.visitInsn(AASTORE);
+                }
+                mv.visitMethodInsn(INVOKESTATIC, "java/util/List",
+                    "of", "([Ljava/lang/Object;)Ljava/util/List;", true);
+                mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                    "newProvides", PROVIDES_STRING_LIST_SIG, false);
+            }
+
+            /*
+             * Invoke Builder.packages(String pn)
+             */
+            void packages(Set<String> packages) {
+                int varIndex = dedupSetBuilder.newStringSet(packages);
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitVarInsn(ALOAD, varIndex);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "packages", SET_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.mainClass(String cn)
+             */
+            void mainClass(String cn) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(cn);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "mainClass", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            /*
+             * Invoke Builder.version(Version v);
+             */
+            void version(Version v) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(v.toString());
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "version", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+        }
+
+        class ModuleHashesBuilder {
+            private static final String MODULE_HASHES_BUILDER =
+                "jdk/internal/module/ModuleHashes$Builder";
+            private static final String MODULE_HASHES_BUILDER_TYPE =
+                "L" + MODULE_HASHES_BUILDER + ";";
+            static final String STRING_BYTE_ARRAY_SIG =
+                "(Ljava/lang/String;[B)" + MODULE_HASHES_BUILDER_TYPE;
+
+            final ModuleHashes recordedHashes;
+            final MethodVisitor hmv;
+            final int index;
+
+            ModuleHashesBuilder(ModuleHashes hashes, int index, MethodVisitor hmv) {
+                this.recordedHashes = hashes;
+                this.hmv = hmv;
+                this.index = index;
+            }
+
+            /**
+             * Build ModuleHashes
+             */
+            void build() {
+                if (recordedHashes == null)
+                    return;
+
+                // new jdk.internal.module.ModuleHashes.Builder
+                newModuleHashesBuilder();
+
+                // Invoke ModuleHashes.Builder::hashForModule
+                recordedHashes
+                    .names()
+                    .forEach(mn -> hashForModule(mn, recordedHashes.hashFor(mn)));
+
+                // Put ModuleHashes into the hashes array
+                pushModuleHashes();
+            }
+
+
+            /*
+             * Create ModuleHashes.Builder instance
+             */
+            void newModuleHashesBuilder() {
+                hmv.visitTypeInsn(NEW, MODULE_HASHES_BUILDER);
+                hmv.visitInsn(DUP);
+                hmv.visitLdcInsn(recordedHashes.algorithm());
+                pushInt(hmv, ((4 * recordedHashes.names().size()) / 3) + 1);
+                hmv.visitMethodInsn(INVOKESPECIAL, MODULE_HASHES_BUILDER,
+                    "<init>", "(Ljava/lang/String;I)V", false);
+                hmv.visitVarInsn(ASTORE, BUILDER_VAR);
+                hmv.visitVarInsn(ALOAD, BUILDER_VAR);
+            }
+
+
+            /*
+             * Invoke ModuleHashes.Builder::build and put the returned
+             * ModuleHashes to the hashes array
+             */
+            void pushModuleHashes() {
+                hmv.visitVarInsn(ALOAD, MH_VAR);
+                pushInt(hmv, index);
+                hmv.visitVarInsn(ALOAD, BUILDER_VAR);
+                hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER,
+                    "build", "()Ljdk/internal/module/ModuleHashes;",
+                    false);
+                hmv.visitInsn(AASTORE);
+            }
+
+            /*
+             * Invoke ModuleHashes.Builder.hashForModule(String name, byte[] hash);
+             */
+            void hashForModule(String name, byte[] hash) {
+                hmv.visitVarInsn(ALOAD, BUILDER_VAR);
+                hmv.visitLdcInsn(name);
+
+                pushInt(hmv, hash.length);
+                hmv.visitIntInsn(NEWARRAY, T_BYTE);
+                for (int i = 0; i < hash.length; i++) {
+                    hmv.visitInsn(DUP);              // arrayref
+                    pushInt(hmv, i);
+                    hmv.visitIntInsn(BIPUSH, hash[i]);
+                    hmv.visitInsn(BASTORE);
+                }
+
+                hmv.visitMethodInsn(INVOKEVIRTUAL, MODULE_HASHES_BUILDER,
+                    "hashForModule", STRING_BYTE_ARRAY_SIG, false);
+                hmv.visitInsn(POP);
+            }
+        }
+
+        /*
+         * Wraps set creation, ensuring identical sets are properly deduplicated.
+         */
+        class DedupSetBuilder {
+            // map Set<String> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<String>, SetBuilder<String>> stringSets = new HashMap<>();
+
+            // map Set<Requires.Modifier> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<Requires.Modifier>, EnumSetBuilder<Requires.Modifier>>
+                requiresModifiersSets = new HashMap<>();
+
+            // map Set<Exports.Modifier> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<Exports.Modifier>, EnumSetBuilder<Exports.Modifier>>
+                exportsModifiersSets = new HashMap<>();
+
+            // map Set<Opens.Modifier> to a specialized builder to allow them to be
+            // deduplicated as they are requested
+            final Map<Set<Opens.Modifier>, EnumSetBuilder<Opens.Modifier>>
+                opensModifiersSets = new HashMap<>();
+
+            private final int stringSetVar;
+            private final int enumSetVar;
+            private final IntSupplier localVarSupplier;
+
+            DedupSetBuilder(IntSupplier localVarSupplier) {
+                this.stringSetVar = localVarSupplier.getAsInt();
+                this.enumSetVar = localVarSupplier.getAsInt();
+                this.localVarSupplier = localVarSupplier;
+            }
+
+            /*
+             * Add the given set of strings to this builder.
+             */
+            void stringSet(Set<String> strings) {
+                stringSets.computeIfAbsent(strings,
+                    s -> new SetBuilder<>(s, stringSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Add the given set of Exports.Modifiers
+             */
+            void exportsModifiers(Set<Exports.Modifier> mods) {
+                exportsModifiersSets.computeIfAbsent(mods, s ->
+                                new EnumSetBuilder<>(s, EXPORTS_MODIFIER_CLASSNAME,
+                                        enumSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Add the given set of Opens.Modifiers
+             */
+            void opensModifiers(Set<Opens.Modifier> mods) {
+                opensModifiersSets.computeIfAbsent(mods, s ->
+                                new EnumSetBuilder<>(s, OPENS_MODIFIER_CLASSNAME,
+                                        enumSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Add the given set of Requires.Modifiers
+             */
+            void requiresModifiers(Set<Requires.Modifier> mods) {
+                requiresModifiersSets.computeIfAbsent(mods, s ->
+                    new EnumSetBuilder<>(s, REQUIRES_MODIFIER_CLASSNAME,
+                                         enumSetVar, localVarSupplier)
+                ).increment();
+            }
+
+            /*
+             * Retrieve the index to the given set of Strings. Emit code to
+             * generate it when SetBuilder::build is called.
+             */
+            int indexOfStringSet(Set<String> names) {
+                return stringSets.get(names).build();
+            }
+
+            /*
+             * Retrieve the index to the given set of Exports.Modifier.
+             * Emit code to generate it when EnumSetBuilder::build is called.
+             */
+            int indexOfExportsModifiers(Set<Exports.Modifier> mods) {
+                return exportsModifiersSets.get(mods).build();
+            }
+
+            /**
+             * Retrieve the index to the given set of Opens.Modifier.
+             * Emit code to generate it when EnumSetBuilder::build is called.
+             */
+            int indexOfOpensModifiers(Set<Opens.Modifier> mods) {
+                return opensModifiersSets.get(mods).build();
+            }
+
+
+            /*
+             * Retrieve the index to the given set of Requires.Modifier.
+             * Emit code to generate it when EnumSetBuilder::build is called.
+             */
+            int indexOfRequiresModifiers(Set<Requires.Modifier> mods) {
+                return requiresModifiersSets.get(mods).build();
+            }
+
+            /*
+             * Build a new string set without any attempt to deduplicate it.
+             */
+            int newStringSet(Set<String> names) {
+                int index = new SetBuilder<>(names, stringSetVar, localVarSupplier).build();
+                assert index == stringSetVar;
+                return index;
+            }
+        }
+
+        /*
+         * SetBuilder generates bytecode to create one single instance of Set
+         * for a given set of elements and assign to a local variable slot.
+         * When there is only one single reference to a Set<T>,
+         * it will reuse defaultVarIndex.  For a Set with multiple references,
+         * it will use a new local variable retrieved from the nextLocalVar
+         */
+        class SetBuilder<T> {
+            private final Set<T> elements;
+            private final int defaultVarIndex;
+            private final IntSupplier nextLocalVar;
+            private int refCount;
+            private int localVarIndex;
+
+            SetBuilder(Set<T> elements,
+                       int defaultVarIndex,
+                       IntSupplier nextLocalVar) {
+                this.elements = elements;
+                this.defaultVarIndex = defaultVarIndex;
+                this.nextLocalVar = nextLocalVar;
+            }
+
+            /*
+             * Increments the number of references to this particular set.
+             */
+            final void increment() {
+                refCount++;
+            }
+
+            /**
+             * Generate the appropriate instructions to load an object reference
+             * to the element onto the stack.
+             */
+            void visitElement(T element, MethodVisitor mv) {
+                mv.visitLdcInsn(element);
+            }
+
+            /*
+             * Build bytecode for the Set represented by this builder,
+             * or get the local variable index of a previously generated set
+             * (in the local scope).
+             *
+             * @return local variable index of the generated set.
+             */
+            final int build() {
+                int index = localVarIndex;
+                if (localVarIndex == 0) {
+                    // if non-empty and more than one set reference this builder,
+                    // emit to a unique local
+                    index = refCount <= 1 ? defaultVarIndex
+                                          : nextLocalVar.getAsInt();
+                    if (index < MAX_LOCAL_VARS) {
+                        localVarIndex = index;
+                    } else {
+                        // overflow: disable optimization by using localVarIndex = 0
+                        index = defaultVarIndex;
+                    }
+
+                    generateSetOf(index);
+                }
+                return index;
+            }
+
+            private void generateSetOf(int index) {
+                if (elements.size() <= 10) {
+                    // call Set.of(e1, e2, ...)
+                    StringBuilder sb = new StringBuilder("(");
+                    for (T t : elements) {
+                        sb.append("Ljava/lang/Object;");
+                        visitElement(t, mv);
+                    }
+                    sb.append(")Ljava/util/Set;");
+                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
+                            "of", sb.toString(), true);
+                } else {
+                    // call Set.of(E... elements)
+                    pushInt(mv, elements.size());
+                    mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+                    int arrayIndex = 0;
+                    for (T t : elements) {
+                        mv.visitInsn(DUP);    // arrayref
+                        pushInt(mv, arrayIndex);
+                        visitElement(t, mv);  // value
+                        mv.visitInsn(AASTORE);
+                        arrayIndex++;
+                    }
+                    mv.visitMethodInsn(INVOKESTATIC, "java/util/Set",
+                            "of", "([Ljava/lang/Object;)Ljava/util/Set;", true);
+                }
+                mv.visitVarInsn(ASTORE, index);
+            }
+        }
+
+        /*
+         * Generates bytecode to create one single instance of EnumSet
+         * for a given set of modifiers and assign to a local variable slot.
+         */
+        class EnumSetBuilder<T> extends SetBuilder<T> {
+
+            private final String className;
+
+            EnumSetBuilder(Set<T> modifiers, String className,
+                           int defaultVarIndex,
+                           IntSupplier nextLocalVar) {
+                super(modifiers, defaultVarIndex, nextLocalVar);
+                this.className = className;
+            }
+
+            /**
+             * Loads an Enum field.
+             */
+            void visitElement(T t, MethodVisitor mv) {
+                mv.visitFieldInsn(GETSTATIC, className, t.toString(),
+                                  "L" + className + ";");
+            }
+        }
+    }
+}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties	Mon Dec 19 16:05:38 2016 +0000
@@ -53,6 +53,11 @@
 main.opt.output=\
 \      --output <path>                   Location of output path
 
+main.opt.launcher=\
+\      --launcher <command>=<module>     Launcher command name for the module\n\
+\      --launcher <command>=<module>/<main>\n\
+\                                        Launcher command name for the module and the main class
+
 main.command.files=\
 \      @<filename>                       Read options from file
 
@@ -91,6 +96,9 @@
 
 
 err.unknown.byte.order:unknown byte order {0}
+err.launcher.main.class.empty:launcher main class name cannot be empty: {0}
+err.launcher.module.name.empty:launcher module name cannot be empty: {0}
+err.launcher.value.format:launcher value should be of form <command>=<module>[/<main-class>]: {0}
 err.output.must.be.specified:--output must be specified
 err.modulepath.must.be.specified:--module-path must be specified
 err.mods.must.be.specified:no modules specified to {0}
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Mon Dec 19 16:05:38 2016 +0000
@@ -66,6 +66,7 @@
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -98,10 +99,11 @@
 import jdk.internal.joptsimple.OptionSpec;
 import jdk.internal.joptsimple.ValueConverter;
 import jdk.internal.loader.ResourceHelper;
-import jdk.internal.misc.JavaLangModuleAccess;
-import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModulePath;
+import jdk.internal.module.ModuleResolution;
 import jdk.tools.jlink.internal.Utils;
 
 import static java.util.stream.Collectors.joining;
@@ -163,6 +165,7 @@
         Mode mode;
         Path jmodFile;
         boolean help;
+        boolean helpExtra;
         boolean version;
         List<Path> classpath;
         List<Path> cmds;
@@ -178,6 +181,7 @@
         String osArch;
         String osVersion;
         Pattern modulesToHash;
+        ModuleResolution moduleResolution;
         boolean dryrun;
         List<PathMatcher> excludes;
         Path extractDir;
@@ -191,7 +195,7 @@
                 showUsageSummary();
                 return EXIT_CMDERR;
             }
-            if (options.help) {
+            if (options.help || options.helpExtra) {
                 showHelp();
                 return EXIT_OK;
             }
@@ -287,8 +291,8 @@
     private boolean describe() throws IOException {
         try (JmodFile jf = new JmodFile(options.jmodFile)) {
             try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
-                ModuleDescriptor md = ModuleDescriptor.read(in);
-                printModuleDescriptor(md);
+                ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
+                printModuleDescriptor(attrs.descriptor(), attrs.recordedHashes());
                 return true;
             } catch (IOException e) {
                 throw new CommandException("err.module.descriptor.not.found");
@@ -302,9 +306,7 @@
                   .collect(joining(" "));
     }
 
-    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
-
-    private void printModuleDescriptor(ModuleDescriptor md)
+    private void printModuleDescriptor(ModuleDescriptor md, ModuleHashes hashes)
         throws IOException
     {
         StringBuilder sb = new StringBuilder();
@@ -350,15 +352,24 @@
 
         md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 
-        JLMA.hashes(md).ifPresent(
-            hashes -> hashes.names().stream().sorted().forEach(
-                mod -> sb.append("\n  hashes ").append(mod).append(" ")
-                         .append(hashes.algorithm()).append(" ")
-                         .append(hashes.hashFor(mod))));
+        if (hashes != null) {
+            hashes.names().stream().sorted().forEach(
+                    mod -> sb.append("\n  hashes ").append(mod).append(" ")
+                             .append(hashes.algorithm()).append(" ")
+                             .append(toHex(hashes.hashFor(mod))));
+        }
 
         out.println(sb.toString());
     }
 
+    private String toHex(byte[] ba) {
+        StringBuilder sb = new StringBuilder(ba.length);
+        for (byte b: ba) {
+            sb.append(String.format("%02x", b & 0xff));
+        }
+        return sb.toString();
+    }
+
     private boolean create() throws IOException {
         JmodFileWriter jmod = new JmodFileWriter();
 
@@ -400,6 +411,7 @@
         final String osVersion = options.osVersion;
         final List<PathMatcher> excludes = options.excludes;
         final Hasher hasher = hasher();
+        final ModuleResolution moduleResolution = options.moduleResolution;
 
         JmodFileWriter() { }
 
@@ -509,6 +521,10 @@
                     }
                 }
 
+                if (moduleResolution != null && moduleResolution.value() != 0) {
+                    extender.moduleResolution(moduleResolution);
+                }
+
                 // write the (possibly extended or modified) module-info.class
                 out.writeEntry(extender.toByteArray(), Section.CLASSES, MODULE_INFO);
             }
@@ -537,12 +553,12 @@
                 }
 
                 URI uri = options.jmodFile.toUri();
-                ModuleReference mref = new ModuleReference(descriptor, uri, new Supplier<>() {
+                ModuleReference mref = new ModuleReference(descriptor, uri) {
                     @Override
-                    public ModuleReader get() {
+                    public ModuleReader open() {
                         throw new UnsupportedOperationException();
                     }
-                });
+                };
 
                 // compose a module finder with the module path and also
                 // a module finder that can find the jmod file being created
@@ -1139,6 +1155,28 @@
         @Override public String valuePattern() { return "module-version"; }
     }
 
+    static class WarnIfResolvedReasonConverter
+        implements ValueConverter<ModuleResolution>
+    {
+        @Override
+        public ModuleResolution convert(String value) {
+            if (value.equals("deprecated"))
+                return ModuleResolution.empty().withDeprecated();
+            else if (value.equals("deprecated-for-removal"))
+                return ModuleResolution.empty().withDeprecatedForRemoval();
+            else if (value.equals("incubating"))
+                return ModuleResolution.empty().withIncubating();
+            else
+                throw new CommandException("err.bad.WarnIfResolvedReason", value);
+        }
+
+        @Override public Class<ModuleResolution> valueType() {
+            return ModuleResolution.class;
+        }
+
+        @Override public String valuePattern() { return "reason"; }
+    }
+
     static class PatternConverter implements ValueConverter<Pattern> {
         @Override
         public Pattern convert(String value) {
@@ -1182,12 +1220,24 @@
      */
     private static final class JmodHelpFormatter extends BuiltinHelpFormatter {
 
-        private JmodHelpFormatter() { super(80, 2); }
+        private final Options opts;
+
+        private JmodHelpFormatter(Options opts) {
+            super(80, 2);
+            this.opts = opts;
+        }
 
         @Override
         public String format(Map<String, ? extends OptionDescriptor> options) {
-            Map<String, OptionDescriptor> all = new HashMap<>();
+            Map<String, OptionDescriptor> all = new LinkedHashMap<>();
             all.putAll(options);
+
+            // extra options
+            if (!opts.helpExtra) {
+                all.remove("do-not-resolve-by-default");
+                all.remove("warn-if-resolved");
+            }
+
             all.put(CMD_FILENAME, new OptionDescriptor() {
                 @Override
                 public Collection<String> options() {
@@ -1243,7 +1293,8 @@
     private final OptionParser parser = new OptionParser("hp");
 
     private void handleOptions(String[] args) {
-        parser.formatHelpWith(new JmodHelpFormatter());
+        options = new Options();
+        parser.formatHelpWith(new JmodHelpFormatter(options));
 
         OptionSpec<Path> classPath
                 = parser.accepts("class-path", getMessage("main.opt.class-path"))
@@ -1285,6 +1336,9 @@
                 = parser.acceptsAll(Set.of("h", "help"), getMessage("main.opt.help"))
                         .forHelp();
 
+        OptionSpec<Void> helpExtra
+                = parser.accepts("help-extra", getMessage("main.opt.help-extra"));
+
         OptionSpec<Path> headerFiles
                 = parser.accepts("header-files", getMessage("main.opt.header-files"))
                         .withRequiredArg()
@@ -1342,6 +1396,15 @@
                         .withRequiredArg()
                         .describedAs(getMessage("main.opt.os-version.arg"));
 
+        OptionSpec<Void> doNotResolveByDefault
+                = parser.accepts("do-not-resolve-by-default",
+                                 getMessage("main.opt.do-not-resolve-by-default"));
+
+        OptionSpec<ModuleResolution> warnIfResolved
+                = parser.accepts("warn-if-resolved", getMessage("main.opt.warn-if-resolved"))
+                        .withRequiredArg()
+                        .withValuesConvertedBy(new WarnIfResolvedReasonConverter());
+
         OptionSpec<Void> version
                 = parser.accepts("version", getMessage("main.opt.version"));
 
@@ -1351,9 +1414,9 @@
         try {
             OptionSet opts = parser.parse(args);
 
-            if (opts.has(help) || opts.has(version)) {
-                options = new Options();
+            if (opts.has(help) || opts.has(helpExtra) || opts.has(version)) {
                 options.help = opts.has(help);
+                options.helpExtra = opts.has(helpExtra);
                 options.version = opts.has(version);
                 return;  // informational message will be shown
             }
@@ -1362,7 +1425,6 @@
             if (words.isEmpty())
                 throw new CommandException("err.missing.mode").showUsage(true);
             String verb = words.get(0);
-            options = new Options();
             try {
                 options.mode = Enum.valueOf(Mode.class, verb.toUpperCase());
             } catch (IllegalArgumentException e) {
@@ -1391,7 +1453,7 @@
                 options.legalNotices = opts.valuesOf(legalNotices);
             if (opts.has(modulePath)) {
                 Path[] dirs = opts.valuesOf(modulePath).toArray(new Path[0]);
-                options.moduleFinder = JLMA.newModulePath(Runtime.version(), true, dirs);
+                options.moduleFinder = new ModulePath(Runtime.version(), true, dirs);
             }
             if (opts.has(moduleVersion))
                 options.moduleVersion = opts.valueOf(moduleVersion);
@@ -1403,6 +1465,13 @@
                 options.osArch = opts.valueOf(osArch);
             if (opts.has(osVersion))
                 options.osVersion = opts.valueOf(osVersion);
+            if (opts.has(warnIfResolved))
+                options.moduleResolution = opts.valueOf(warnIfResolved);
+            if (opts.has(doNotResolveByDefault)) {
+                if (options.moduleResolution == null)
+                    options.moduleResolution = ModuleResolution.empty();
+                options.moduleResolution = options.moduleResolution.withDoNotResolveByDefault();
+            }
             if (opts.has(hashModules)) {
                 options.modulesToHash = opts.valueOf(hashModules);
                 // if storing hashes then the module path is required
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties	Mon Dec 19 16:05:38 2016 +0000
@@ -47,6 +47,7 @@
 \hash      - Records hashes of tied modules.
 
 main.opt.help=Print this usage message
+main.opt.help-extra=Print help on extra options
 main.opt.version=Version information
 main.opt.class-path=Application jar files|dir containing classes
 main.opt.libs=Location of native libraries
@@ -74,6 +75,9 @@
 \ with modules matching the given <regex-pattern> and depending upon it directly\
 \ or indirectly. The hashes are recorded in the JMOD file being created, or\
 \ a JMOD file or modular JAR on the module path specified the jmod hash command.
+main.opt.do-not-resolve-by-default=Exclude from the default root set of modules
+main.opt.warn-if-resolved=Hint for a tool to issue a warning if the module \
+is resolved. One of deprecated, deprecated-for-removal, or incubating
 
 main.opt.cmdfile=Read options from the specified file
 
@@ -96,6 +100,8 @@
 err.file.already.exists=file already exists: {0}
 err.jmod.not.found=no jmod file found: {0}
 err.bad.pattern=bad pattern {0}
+err.bad.WarnIfResolvedReason=bad reason: {0}, must be one of deprecated,\
+\ deprecated-for-removal, or incubating
 err.unknown.option=unknown option(s): {0}
 err.missing.arg=no value given for {0}
 err.internal.error=internal error: {0} {1} {2}
--- a/jdk/src/jdk.jlink/share/classes/module-info.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/module-info.java	Mon Dec 19 16:05:38 2016 +0000
@@ -41,7 +41,7 @@
         jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin,
         jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin,
         jdk.tools.jlink.internal.plugins.LegalNoticeFilePlugin,
-        jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin,
+        jdk.tools.jlink.internal.plugins.SystemModulesPlugin,
         jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin,
         jdk.tools.jlink.internal.plugins.OrderResourcesPlugin,
         jdk.tools.jlink.internal.plugins.DefaultCompressPlugin,
--- a/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java	Mon Dec 19 16:05:38 2016 +0000
@@ -27,8 +27,10 @@
 
 import jdk.internal.vm.annotation.ForceInline;
 import jdk.internal.misc.VM;
+import jdk.internal.ref.Cleaner;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
+import sun.nio.ch.DirectBuffer;
 
 import java.lang.reflect.Field;
 import java.security.ProtectionDomain;
@@ -1228,4 +1230,28 @@
     public void fullFence() {
         theInternalUnsafe.fullFence();
     }
+
+    /**
+     * Invokes the given direct byte buffer's cleaner, if any.
+     *
+     * @param directBuffer a direct byte buffer
+     * @throws NullPointerException if {@code directBuffer} is null
+     * @throws IllegalArgumentException if {@code directBuffer} is non-direct,
+     * or is a {@link java.nio.Buffer#slice slice}, or is a
+     * {@link java.nio.Buffer#duplicate duplicate}
+     * @since 9
+     */
+    public void invokeCleaner(java.nio.ByteBuffer directBuffer) {
+        if (!directBuffer.isDirect())
+            throw new IllegalArgumentException("buffer is non-direct");
+
+        DirectBuffer db = (DirectBuffer)directBuffer;
+        if (db.attachment() != null)
+            throw new IllegalArgumentException("duplicate or slice");
+
+        Cleaner cleaner = db.cleaner();
+        if (cleaner != null) {
+            cleaner.clean();
+        }
+    }
 }
--- a/jdk/test/ProblemList.txt	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/ProblemList.txt	Mon Dec 19 16:05:38 2016 +0000
@@ -205,6 +205,8 @@
 
 java/rmi/transport/dgcDeadLock/DGCDeadLock.java                 8029360 macosx-all
 
+java/rmi/registry/readTest/readTest.sh                          7146543 generic-all
+
 ############################################################################
 
 # jdk_security
@@ -217,6 +219,10 @@
 
 sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java         8161232 macosx-all
 
+sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java  8171043 windows-all
+
+javax/net/ssl/DTLS/PacketLossRetransmission.java                8169086 macosx-x64
+
 ############################################################################
 
 # jdk_sound
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Dialog/DialogAboveFrame/DialogAboveFrameTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8169589
+ * @summary Activating a dialog puts to back another dialog owned by the same frame
+ * @author Dmitry Markov
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main DialogAboveFrameTest
+ */
+
+import java.awt.Color;
+import java.awt.Dialog;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Robot;
+
+import test.java.awt.regtesthelpers.Util;
+
+public class DialogAboveFrameTest {
+    public static void main(String[] args) {
+        Robot robot = Util.createRobot();
+
+        Frame frame = new Frame("Frame");
+        frame.setBackground(Color.BLUE);
+        frame.setBounds(200, 50, 300, 300);
+        frame.setVisible(true);
+
+        Dialog dialog1 = new Dialog(frame, "Dialog 1", false);
+        dialog1.setBackground(Color.RED);
+        dialog1.setBounds(100, 100, 200, 200);
+        dialog1.setVisible(true);
+
+        Dialog dialog2 = new Dialog(frame, "Dialog 2", false);
+        dialog2.setBackground(Color.GREEN);
+        dialog2.setBounds(400, 100, 200, 200);
+        dialog2.setVisible(true);
+
+        Util.waitForIdle(robot);
+
+        Util.clickOnComp(dialog2, robot);
+        Util.waitForIdle(robot);
+
+        Point point = dialog1.getLocationOnScreen();
+        int x = point.x + (int)(dialog1.getWidth() * 0.9);
+        int y = point.y + (int)(dialog1.getHeight() * 0.9);
+
+        try {
+            if (!robot.getPixelColor(x, y).equals(dialog1.getBackground())) {
+                throw new RuntimeException("Test FAILED: Dialog is behind the frame");
+            }
+        } finally {
+            frame.dispose();
+            dialog1.dispose();
+            dialog2.dispose();
+        }
+    }
+}
+
--- a/jdk/test/java/awt/JAWT/Makefile.unix	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/awt/JAWT/Makefile.unix	Mon Dec 19 16:05:38 2016 +0000
@@ -1,4 +1,4 @@
-# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+# 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
@@ -32,7 +32,7 @@
 
 J_INC =		$(TESTJAVA)/include
 INCLUDES =	-I$(J_INC) -I$(J_INC)/$(SYST) -I.
-LIBS =		-L$(TESTJAVA)/lib/$(ARCH) -ljawt -lX11
+LIBS =		-L$(TESTJAVA)/lib -ljawt -lX11
 
 all:		$(CLASSES) libmylib.so
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Menu/WrongParentAfterRemoveMenu/WrongParentAfterRemoveMenu.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.awt.Frame;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.PopupMenu;
+import java.awt.Window;
+
+/**
+ * @test
+ * @bug 8165769
+ * @key headful
+ */
+public final class WrongParentAfterRemoveMenu {
+
+    public static void main(final String[] args) {
+        testMenuBar();
+        testComponent();
+        testFrame();
+    }
+
+    private static void testFrame() {
+        // peer exists
+        Frame frame = new Frame();
+        try {
+            frame.pack();
+            PopupMenu popupMenu = new PopupMenu();
+            frame.add(popupMenu);
+            checkParent(popupMenu, frame);
+            frame.remove(popupMenu);
+            checkParent(popupMenu, null);
+        } finally {
+            frame.dispose();
+        }
+        // peer is null
+        frame = new Frame();
+        PopupMenu popupMenu = new PopupMenu();
+        frame.add(popupMenu);
+        checkParent(popupMenu, frame);
+        frame.remove(popupMenu);
+        checkParent(popupMenu, null);
+    }
+
+    private static void testComponent() {
+        // peer exists
+        Window w = new Window(null);
+        try {
+            w.pack();
+            PopupMenu popupMenu = new PopupMenu();
+            w.add(popupMenu);
+            checkParent(popupMenu, w);
+            w.remove(popupMenu);
+            checkParent(popupMenu, null);
+        } finally {
+            w.dispose();
+        }
+        // peer is null
+        w = new Window(null);
+        PopupMenu popupMenu = new PopupMenu();
+        w.add(popupMenu);
+        checkParent(popupMenu, w);
+        w.remove(popupMenu);
+        checkParent(popupMenu, null);
+    }
+
+    private static void testMenuBar() {
+        // peer exists
+        MenuBar mb = new MenuBar();
+        try {
+            mb.addNotify();
+            Menu m1 = new Menu();
+            Menu m2 = new Menu();
+            m1.add(m2);
+            mb.add(m1);
+            checkParent(m1, mb);
+            checkParent(m2, m1);
+            m1.remove(m2);
+            checkParent(m2, null);
+            mb.remove(m1);
+            checkParent(m1, null);
+        } finally {
+            mb.removeNotify();
+        }
+        // peer is null
+        mb = new MenuBar();
+        Menu m1 = new Menu();
+        Menu m2 = new Menu();
+        m1.add(m2);
+        mb.add(m1);
+        checkParent(m1, mb);
+        checkParent(m2, m1);
+        m1.remove(m2);
+        checkParent(m2, null);
+        mb.remove(m1);
+        checkParent(m1, null);
+    }
+
+    private static void checkParent(final Menu menu, final Object parent) {
+        if (menu.getParent() != parent) {
+            System.err.println("Expected: " + parent);
+            System.err.println("Actual: " + menu.getParent());
+            throw new RuntimeException("Wrong parent");
+        }
+    }
+}
--- a/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -44,9 +44,11 @@
 import javax.imageio.ImageIO;
 
 /**
- * @test @bug 8145174 8151787
+ * @test
+ * @bug 8145174 8151787 8168657
  * @summary HiDPI splash screen support on Linux
  * @modules java.desktop/sun.java2d
+ * @requires (os.family == "linux")
  * @run main UnixMultiResolutionSplashTest
  */
 public class UnixMultiResolutionSplashTest {
--- a/jdk/test/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.java	Mon Dec 19 16:05:38 2016 +0000
@@ -25,6 +25,7 @@
   test
   @bug 6242241
   @summary Tests basic DnD functionality in an applet
+  @requires (os.family == "windows")
   @author Your Name: Alexey Utkin area=dnd
   @run applet/manual=yesno DnDFileGroupDescriptor.html
 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/Fallback/SurrogatesFallbackTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 JetBrains s.r.o.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/* @test
+ * @bug 8169202
+ * @summary verify font fallback for surrogate pairs on macOS
+ * @requires os.family == "mac"
+ */
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.font.GlyphVector;
+import java.awt.image.BufferedImage;
+import java.util.function.Consumer;
+
+public class SurrogatesFallbackTest {
+    private static final int CHARACTER = 0x1d400; // MATHEMATICAL BOLD CAPITAL A
+    private static final Font FONT = new Font("Menlo", // expected to fallback to STIXGeneral for the character above
+                                              Font.PLAIN,
+                                              12);
+    private static final int IMAGE_WIDTH = 20;
+    private static final int IMAGE_HEIGHT = 20;
+    private static final int GLYPH_X = 5;
+    private static final int GLYPH_Y = 15;
+
+    public static void main(String[] args) {
+        BufferedImage noGlyph = createImage(g -> {});
+        BufferedImage missingGlyph = createImage(g -> {
+            GlyphVector gv = FONT.createGlyphVector(g.getFontRenderContext(), new int[]{FONT.getMissingGlyphCode()});
+            g.drawGlyphVector(gv, GLYPH_X, GLYPH_Y);
+        });
+        BufferedImage surrogateCharGlyph = createImage(g -> {
+            g.setFont(FONT);
+            g.drawString(new String(Character.toChars(CHARACTER)), GLYPH_X, GLYPH_Y);
+        });
+
+        if (imagesAreEqual(surrogateCharGlyph, noGlyph)) {
+            throw new RuntimeException("Character was not rendered");
+        }
+        if (imagesAreEqual(surrogateCharGlyph, missingGlyph)) {
+            throw new RuntimeException("Character is rendered as missing");
+        }
+    }
+
+    private static BufferedImage createImage(Consumer<Graphics2D> drawing) {
+        BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g = image.createGraphics();
+        g.setColor(Color.white);
+        g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
+        g.setColor(Color.black);
+        drawing.accept(g);
+        g.dispose();
+        return image;
+    }
+
+    private static boolean imagesAreEqual(BufferedImage i1, BufferedImage i2) {
+        if (i1.getWidth() != i2.getWidth() || i1.getHeight() != i2.getHeight()) return false;
+        for (int i = 0; i < i1.getWidth(); i++) {
+            for (int j = 0; j < i1.getHeight(); j++) {
+                if (i1.getRGB(i, j) != i2.getRGB(i, j)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/TextLayout/ArabicDiacriticTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ *
+ * 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
+ */
+
+/* @test
+ * @summary verify Arab Diacritic Positioning
+ * @bug 8168759
+ */
+
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.Rectangle;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.util.Locale;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+public class ArabicDiacriticTest {
+
+    static final String SAMPLE =
+     "\u0627\u0644\u0639\u064e\u0631\u064e\u0628\u0650\u064a\u064e\u0651\u0629";
+
+    static final String STR1 = "\u0644\u0639\u064e\u0629";
+    static final String STR2 = "\u0644\u0639\u0629";
+
+    static JFrame frame;
+    static final String FONT = "DejaVu Sans";
+
+    public static void main(String args[]) throws Exception {
+        showText(); // for a human
+        measureText(); // for the test harness
+        Thread.sleep(5000);
+        frame.dispose();
+    }
+
+    static void showText() {
+        SwingUtilities.invokeLater(() -> {
+            frame = new JFrame();
+            JLabel label = new JLabel(SAMPLE);
+            Font font = new Font(FONT, Font.PLAIN, 36);
+            label.setFont(font);
+            frame.setLayout(new GridLayout(3,1));
+            frame.add(label);
+            label = new JLabel(STR1);
+            label.setFont(font);
+            frame.add(label);
+            label = new JLabel(STR2);
+            label.setFont(font);
+            frame.add(label);
+            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+            frame.pack();
+            frame.setLocationRelativeTo(null);
+            frame.setVisible(true);
+        });
+    }
+
+    static void measureText() {
+        Font font = new Font(FONT, Font.PLAIN, 36);
+        if (!font.getFamily(Locale.ENGLISH).equals(FONT)) {
+            return;
+        }
+        FontRenderContext frc = new FontRenderContext(null, false, false);
+        TextLayout tl1 = new TextLayout(STR1, font, frc);
+        TextLayout tl2 = new TextLayout(STR2, font, frc);
+        Rectangle r1 = tl1.getPixelBounds(frc, 0f, 0f);
+        Rectangle r2 = tl2.getPixelBounds(frc, 0f, 0f);
+        if (r1.height > r2.height) {
+            System.out.println(font);
+            System.out.println(r1);
+            System.out.println(r2);
+            throw new RuntimeException("BAD BOUNDS");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/StrictMath/ExpTests.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8139688
+ * @key randomness
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.RandomFactory
+ * @build Tests
+ * @build FdlibmTranslit
+ * @build ExpTests
+ * @run main ExpTests
+ * @summary Tests specifically for StrictMath.exp
+ */
+
+import jdk.testlibrary.RandomFactory;
+
+/**
+ * The role of this test is to verify that the FDLIBM exp algorithm is
+ * being used by running golden file style tests on values that may
+ * vary from one conforming exponential implementation to another.
+ */
+
+public class ExpTests {
+    private ExpTests(){}
+
+    public static void main(String [] argv) {
+        int failures = 0;
+
+        failures += testExp();
+        failures += testAgainstTranslit();
+
+        if (failures > 0) {
+            System.err.println("Testing the exponential incurred "
+                               + failures + " failures.");
+            throw new RuntimeException();
+        }
+    }
+
+    // From the fdlibm source, the overflow threshold in hex is:
+    // 0x4086_2E42_FEFA_39EF.
+    static final double EXP_OVERFLOW_THRESH  = Double.longBitsToDouble(0x4086_2E42_FEFA_39EFL);
+
+    // From the fdlibm source, the underflow threshold in hex is:
+    // 0xc087_4910_D52D_3051L.
+    static final double EXP_UNDERFLOW_THRESH = Double.longBitsToDouble(0xc087_4910_D52D_3051L);
+
+    static int testExp() {
+        int failures = 0;
+
+        double [][] testCases = {
+            // Some of these could be moved to common Math/StrictMath exp testing.
+            {Double.NaN,                      Double.NaN},
+            {Double.MAX_VALUE,                Double.POSITIVE_INFINITY},
+            {Double.POSITIVE_INFINITY,        Double.POSITIVE_INFINITY},
+            {Double.NEGATIVE_INFINITY,        +0.0},
+            {EXP_OVERFLOW_THRESH,                 0x1.ffff_ffff_fff2ap1023},
+            {Math.nextUp(EXP_OVERFLOW_THRESH),    Double.POSITIVE_INFINITY},
+            {Math.nextDown(EXP_UNDERFLOW_THRESH), +0.0},
+            {EXP_UNDERFLOW_THRESH,                +Double.MIN_VALUE},
+        };
+
+        for(double[] testCase: testCases)
+            failures+=testExpCase(testCase[0], testCase[1]);
+
+        return failures;
+    }
+
+    static int testExpCase(double input, double expected) {
+        int failures = 0;
+
+        failures+=Tests.test("StrictMath.exp(double)", input,
+                             StrictMath.exp(input), expected);
+        return failures;
+    }
+
+    // Initialize shared random number generator
+    private static java.util.Random random = RandomFactory.getRandom();
+
+    /**
+     * Test StrictMath.exp against transliteration port of exp.
+     */
+    private static int testAgainstTranslit() {
+        int failures = 0;
+
+        double[] decisionPoints = {
+            // Near overflow threshold
+            EXP_OVERFLOW_THRESH - 512*Math.ulp(EXP_OVERFLOW_THRESH),
+
+            // Near underflow threshold
+            EXP_UNDERFLOW_THRESH - 512*Math.ulp(EXP_UNDERFLOW_THRESH),
+
+            // Straddle algorithm conditional checks
+            Double.longBitsToDouble(0x4086_2E42_0000_0000L - 512L),
+            Double.longBitsToDouble(0x3fd6_2e42_0000_0000L - 512L),
+            Double.longBitsToDouble(0x3FF0_A2B2_0000_0000L - 512L),
+            Double.longBitsToDouble(0x3e30_0000_0000_0000L - 512L),
+
+            // Other notable points
+            Double.MIN_NORMAL - Math.ulp(Double.MIN_NORMAL)*512,
+            -Double.MIN_VALUE*512,
+        };
+
+        for (double decisionPoint : decisionPoints) {
+            double ulp = Math.ulp(decisionPoint);
+            failures += testRange(decisionPoint - 1024*ulp, ulp, 1_024);
+        }
+
+        // Try out some random values
+        for (int i = 0; i < 100; i++) {
+            double x = Tests.createRandomDouble(random);
+            failures += testRange(x, Math.ulp(x), 100);
+        }
+
+        return failures;
+    }
+
+    private static int testRange(double start, double increment, int count) {
+        int failures = 0;
+        double x = start;
+        for (int i = 0; i < count; i++, x += increment) {
+            failures += testExpCase(x, FdlibmTranslit.Exp.compute(x));
+        }
+        return failures;
+    }
+}
--- a/jdk/test/java/lang/StrictMath/FdlibmTranslit.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/StrictMath/FdlibmTranslit.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -48,7 +48,8 @@
      */
     private static double __LO(double x, int low) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L)|low );
+        return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L) |
+                                       (low    & 0x0000_0000_FFFF_FFFFL));
     }
 
     /**
@@ -65,7 +66,8 @@
      */
     private static double __HI(double x, int high) {
         long transX = Double.doubleToRawLongBits(x);
-        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL)|( ((long)high)) << 32 );
+        return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL) |
+                                       ( ((long)high)) << 32 );
     }
 
     public static double hypot(double x, double y) {
@@ -250,4 +252,136 @@
                 return w;
         }
     }
+
+    /**
+     * Returns the exponential of x.
+     *
+     * Method
+     *   1. Argument reduction:
+     *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+     *      Given x, find r and integer k such that
+     *
+     *               x = k*ln2 + r,  |r| <= 0.5*ln2.
+     *
+     *      Here r will be represented as r = hi-lo for better
+     *      accuracy.
+     *
+     *   2. Approximation of exp(r) by a special rational function on
+     *      the interval [0,0.34658]:
+     *      Write
+     *          R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+     *      We use a special Reme algorithm on [0,0.34658] to generate
+     *      a polynomial of degree 5 to approximate R. The maximum error
+     *      of this polynomial approximation is bounded by 2**-59. In
+     *      other words,
+     *          R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+     *      (where z=r*r, and the values of P1 to P5 are listed below)
+     *      and
+     *          |                  5          |     -59
+     *          | 2.0+P1*z+...+P5*z   -  R(z) | <= 2
+     *          |                             |
+     *      The computation of exp(r) thus becomes
+     *                             2*r
+     *              exp(r) = 1 + -------
+     *                            R - r
+     *                                 r*R1(r)
+     *                     = 1 + r + ----------- (for better accuracy)
+     *                                2 - R1(r)
+     *      where
+     *                               2       4             10
+     *              R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+     *
+     *   3. Scale back to obtain exp(x):
+     *      From step 1, we have
+     *         exp(x) = 2^k * exp(r)
+     *
+     * Special cases:
+     *      exp(INF) is INF, exp(NaN) is NaN;
+     *      exp(-INF) is 0, and
+     *      for finite argument, only exp(0)=1 is exact.
+     *
+     * Accuracy:
+     *      according to an error analysis, the error is always less than
+     *      1 ulp (unit in the last place).
+     *
+     * Misc. info.
+     *      For IEEE double
+     *          if x >  7.09782712893383973096e+02 then exp(x) overflow
+     *          if x < -7.45133219101941108420e+02 then exp(x) underflow
+     *
+     * Constants:
+     * The hexadecimal values are the intended ones for the following
+     * constants. The decimal values may be used, provided that the
+     * compiler will convert from decimal to binary accurately enough
+     * to produce the hexadecimal values shown.
+     */
+    static class Exp {
+        private static final double one     = 1.0;
+        private static final double[] halF = {0.5,-0.5,};
+        private static final double huge    = 1.0e+300;
+        private static final double twom1000= 9.33263618503218878990e-302;      /* 2**-1000=0x01700000,0*/
+        private static final double o_threshold=  7.09782712893383973096e+02;   /* 0x40862E42, 0xFEFA39EF */
+        private static final double u_threshold= -7.45133219101941108420e+02;   /* 0xc0874910, 0xD52D3051 */
+        private static final double[] ln2HI   ={ 6.93147180369123816490e-01,    /* 0x3fe62e42, 0xfee00000 */
+                                                 -6.93147180369123816490e-01};  /* 0xbfe62e42, 0xfee00000 */
+        private static final double[] ln2LO   ={ 1.90821492927058770002e-10,    /* 0x3dea39ef, 0x35793c76 */
+                                                 -1.90821492927058770002e-10,}; /* 0xbdea39ef, 0x35793c76 */
+        private static final double invln2 =  1.44269504088896338700e+00;       /* 0x3ff71547, 0x652b82fe */
+        private static final double P1   =  1.66666666666666019037e-01;         /* 0x3FC55555, 0x5555553E */
+        private static final double P2   = -2.77777777770155933842e-03;         /* 0xBF66C16C, 0x16BEBD93 */
+        private static final double P3   =  6.61375632143793436117e-05;         /* 0x3F11566A, 0xAF25DE2C */
+        private static final double P4   = -1.65339022054652515390e-06;         /* 0xBEBBBD41, 0xC5D26BF1 */
+        private static final double P5   =  4.13813679705723846039e-08;         /* 0x3E663769, 0x72BEA4D0 */
+
+        public static strictfp double compute(double x) {
+            double y,hi=0,lo=0,c,t;
+            int k=0,xsb;
+            /*unsigned*/ int hx;
+
+            hx  = __HI(x);  /* high word of x */
+            xsb = (hx>>31)&1;               /* sign bit of x */
+            hx &= 0x7fffffff;               /* high word of |x| */
+
+            /* filter out non-finite argument */
+            if(hx >= 0x40862E42) {                  /* if |x|>=709.78... */
+                if(hx>=0x7ff00000) {
+                    if(((hx&0xfffff)|__LO(x))!=0)
+                        return x+x;                /* NaN */
+                    else return (xsb==0)? x:0.0;    /* exp(+-inf)={inf,0} */
+                }
+                if(x > o_threshold) return huge*huge; /* overflow */
+                if(x < u_threshold) return twom1000*twom1000; /* underflow */
+            }
+
+            /* argument reduction */
+            if(hx > 0x3fd62e42) {           /* if  |x| > 0.5 ln2 */
+                if(hx < 0x3FF0A2B2) {       /* and |x| < 1.5 ln2 */
+                    hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+                } else {
+                    k  = (int)(invln2*x+halF[xsb]);
+                    t  = k;
+                    hi = x - t*ln2HI[0];    /* t*ln2HI is exact here */
+                    lo = t*ln2LO[0];
+                }
+                x  = hi - lo;
+            }
+            else if(hx < 0x3e300000)  {     /* when |x|<2**-28 */
+                if(huge+x>one) return one+x;/* trigger inexact */
+            }
+            else k = 0;
+
+            /* x is now in primary range */
+            t  = x*x;
+            c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+            if(k==0)        return one-((x*c)/(c-2.0)-x);
+            else            y = one-((lo-(x*c)/(2.0-c))-hi);
+            if(k >= -1021) {
+                y = __HI(y, __HI(y) + (k<<20)); /* add k to y's exponent */
+                return y;
+            } else {
+                y = __HI(y, __HI(y) + ((k+1000)<<20));/* add k to y's exponent */
+                return y*twom1000;
+            }
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/DropLookupModeTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @run testng DropLookupModeTest
+ * @summary Basic unit tests Lookup::dropLookupMode
+ */
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.*;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class DropLookupModeTest {
+
+    /**
+     * Basic test of dropLookupMode
+     */
+    public void testBasic() {
+        final Lookup fullPowerLookup = MethodHandles.lookup();
+        final Class<?> lc = fullPowerLookup.lookupClass();
+        assertTrue(fullPowerLookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE));
+
+        Lookup lookup = fullPowerLookup.dropLookupMode(PRIVATE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE));
+
+        lookup = fullPowerLookup.dropLookupMode(PROTECTED);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
+
+        lookup = fullPowerLookup.dropLookupMode(PACKAGE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE));
+
+        lookup = fullPowerLookup.dropLookupMode(MODULE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC));
+
+        lookup = fullPowerLookup.dropLookupMode(PUBLIC);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == 0);
+    }
+
+    /**
+     * Starting with a full power Lookup, use dropLookupMode to create new Lookups
+     * with reduced access.
+     */
+    public void testReducingAccess() {
+        Lookup lookup = MethodHandles.lookup();
+        final Class<?> lc = lookup.lookupClass();
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PROTECTED|PRIVATE));
+
+        lookup = lookup.dropLookupMode(PROTECTED);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
+
+        lookup = lookup.dropLookupMode(PRIVATE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE));
+
+        lookup = lookup.dropLookupMode(PACKAGE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE));
+
+        lookup = lookup.dropLookupMode(MODULE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = lookup.dropLookupMode(PUBLIC);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == 0);
+
+        // repeat with lookup has no access
+        lookup = lookup.dropLookupMode(PUBLIC);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == 0);
+    }
+
+    /**
+     * Test dropLookupMode on the public Lookup.
+     */
+    public void testPublicLookup() {
+        final Lookup publicLookup = MethodHandles.publicLookup();
+        final Class<?> lc = publicLookup.lookupClass();
+        assertTrue(publicLookup.lookupModes() == PUBLIC);
+
+        Lookup lookup = publicLookup.dropLookupMode(PRIVATE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = publicLookup.dropLookupMode(PROTECTED);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = publicLookup.dropLookupMode(PACKAGE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = publicLookup.dropLookupMode(MODULE);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
+
+        lookup = publicLookup.dropLookupMode(PUBLIC);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == 0);
+    }
+
+    @DataProvider(name = "badInput")
+    public Object[][] badInput() {
+        return new Object[][] {
+                { 0,                        null },
+                { (PACKAGE|PRIVATE),        null },    // two modes
+                { Integer.MAX_VALUE,        null },
+                { Integer.MIN_VALUE,        null },
+        };
+    }
+
+    /**
+     * Check that IllegalArgumentException is thrown for bad input
+     */
+    @Test(dataProvider = "badInput", expectedExceptions = {IllegalArgumentException.class})
+    public void testBadInput(Integer modeToDrop, Object ignore) {
+        MethodHandles.lookup().dropLookupMode(modeToDrop);
+    }
+
+}
\ No newline at end of file
--- a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java	Mon Dec 19 16:05:38 2016 +0000
@@ -84,8 +84,7 @@
 
     // Invoke MethodHandles.privateLookupIn with a reduced-power caller
     public void testReducedAccessCallerSameModule() throws Throwable {
-        // drop access
-        Lookup caller = MethodHandles.lookup().in(publicType);
+        Lookup caller = MethodHandles.lookup().dropLookupMode(PACKAGE);
         assertTrue((caller.lookupModes() & PRIVATE) == 0);
         assertTrue((caller.lookupModes() & PACKAGE) == 0);
         assertTrue((caller.lookupModes() & MODULE) != 0);
--- a/jdk/test/java/lang/module/ModuleDescriptorTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -23,8 +23,7 @@
 
 /**
  * @test
- * @modules java.base/java.lang.module:open
- *          java.base/jdk.internal.module
+ * @modules java.base/jdk.internal.module
  * @run testng ModuleDescriptorTest
  * @summary Basic test for java.lang.module.ModuleDescriptor and its builder
  */
@@ -41,16 +40,13 @@
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires.Modifier;
 import java.lang.module.ModuleDescriptor.Version;
-import java.lang.reflect.Constructor;
 import java.lang.reflect.Module;
 import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
 
@@ -66,10 +62,20 @@
     public Object[][] invalidJavaIdentifiers() {
         return new Object[][]{
 
-            { null,         null },
-            { ".foo",       null },
-            { "foo.",       null },
-            { "[foo]",      null },
+            { null,             null },
+            { "1",              null },
+            { "1foo",           null },
+            { ".foo",           null },
+            { "foo.",           null },
+            { "[foo]",          null },
+            { "foo.1",          null },
+            { "1foo.bar",       null },
+            { "foo.1bar",       null },
+            { "foo.[bar]",      null },
+            { "foo..bar",       null },
+            { "foo.bar.1",      null },
+            { "foo.bar.1gus",   null },
+            { "foo.bar.[gus]",  null },
 
         };
     }
@@ -86,6 +92,15 @@
             .next();
     }
 
+    private Requires requires(Set<Modifier> mods, String mn, Version v) {
+        return ModuleDescriptor.module("m")
+            .requires(mods, mn, v)
+            .build()
+            .requires()
+            .iterator()
+            .next();
+    }
+
     private Requires requires(String mn) {
         return requires(Collections.emptySet(), mn);
     }
@@ -103,6 +118,7 @@
         assertTrue(r.compareTo(r) == 0);
         assertTrue(r.modifiers().isEmpty());
         assertEquals(r.name(), "foo");
+        assertFalse(r.compiledVersion().isPresent());
     }
 
     public void testRequiresWithOneModifier() {
@@ -111,6 +127,7 @@
         assertTrue(r.compareTo(r) == 0);
         assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE));
         assertEquals(r.name(), "foo");
+        assertFalse(r.compiledVersion().isPresent());
     }
 
     public void testRequiresWithTwoModifiers() {
@@ -119,6 +136,7 @@
         assertTrue(r.compareTo(r) == 0);
         assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, SYNTHETIC));
         assertEquals(r.name(), "foo");
+        assertFalse(r.compiledVersion().isPresent());
     }
 
     public void testRequiresWithAllModifiers() {
@@ -127,6 +145,18 @@
         assertTrue(r.compareTo(r) == 0);
         assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, STATIC, SYNTHETIC, MANDATED));
         assertEquals(r.name(), "foo");
+        assertFalse(r.compiledVersion().isPresent());
+    }
+
+    public void testRequiresWithCompiledVersion() {
+        Version v = Version.parse("1.0");
+        Requires r = requires(Set.of(), "foo", v);
+        assertEquals(r, r);
+        assertTrue(r.compareTo(r) == 0);
+        assertEquals(r.modifiers(), Set.of());
+        assertEquals(r.name(), "foo");
+        assertTrue(r.compiledVersion().isPresent());
+        assertEquals(r.compiledVersion().get().toString(), "1.0");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
@@ -167,6 +197,16 @@
         ModuleDescriptor.module("m").requires((Requires) null);
     }
 
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testRequiresWithNullModifiers() {
+        ModuleDescriptor.module("m").requires(null, "foo");
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testRequiresWithNullVersion() {
+        ModuleDescriptor.module("m").requires(Set.of(), "foo", null);
+    }
+
     public void testRequiresCompare() {
         Requires r1 = requires(EnumSet.noneOf(Modifier.class), "foo");
         Requires r2 = requires(EnumSet.noneOf(Modifier.class), "bar");
@@ -190,6 +230,20 @@
         assertTrue(r2.compareTo(r1) == 0);
     }
 
+    public void testRequiresCompareWithSameCompiledVersion() {
+        Requires r1 = requires(Set.of(), "foo", Version.parse("2.0"));
+        Requires r2 = requires(Set.of(), "foo", Version.parse("2.0"));
+        assertTrue(r1.compareTo(r2) == 0);
+        assertTrue(r2.compareTo(r1) == 0);
+    }
+
+    public void testRequiresCompareWithDifferentCompiledVersion() {
+        Requires r1 = requires(Set.of(), "foo", Version.parse("1.0"));
+        Requires r2 = requires(Set.of(), "foo", Version.parse("2.0"));
+        assertTrue(r1.compareTo(r2) < 0);
+        assertTrue(r2.compareTo(r1) > 0);
+    }
+
     public void testRequiresEqualsAndHashCode() {
         Requires r1 = requires("foo");
         Requires r2 = requires("foo");
@@ -208,6 +262,17 @@
         r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
         r2 = requires(Set.of(), "foo");
         assertNotEquals(r1, r2);
+
+        Version v1 = Version.parse("1.0");
+        r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
+        r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
+        assertEquals(r1, r2);
+        assertTrue(r1.hashCode() == r2.hashCode());
+
+        Version v2 = Version.parse("2.0");
+        r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v1);
+        r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo", v2);
+        assertNotEquals(r1, r2);
     }
 
     public void testRequiresToString() {
@@ -938,7 +1003,7 @@
     };
 
     // basic test reading module-info.class
-    public void testRead1() throws Exception {
+    public void testRead() throws Exception {
         Module base = Object.class.getModule();
 
         try (InputStream in = base.getResourceAsStream("module-info.class")) {
@@ -954,45 +1019,6 @@
             assertEquals(descriptor.name(), "java.base");
         }
     }
-
-    /**
-     * Test reading a module-info.class that has a module name, requires,
-     * and qualified exports with module names that are not supported in the
-     * Java Language.
-     */
-    public void testRead2() throws Exception {
-        // use non-public constructor to create a Builder that is not strict
-        Constructor<?> ctor = Builder.class.getDeclaredConstructor(String.class, boolean.class);
-        ctor.setAccessible(true);
-
-        Builder builder = (ModuleDescriptor.Builder) ctor.newInstance("m?1", false);
-        ModuleDescriptor descriptor = builder
-                .requires("java.base")
-                .requires("-m1")
-                .exports("p", Set.of("m2-"))
-                .build();
-
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        ModuleInfoWriter.write(descriptor, baos);
-        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
-
-        descriptor = ModuleDescriptor.read(bb);
-        assertEquals(descriptor.name(), "m?1");
-
-        Set<String> requires = descriptor.requires()
-                .stream()
-                .map(Requires::name)
-                .collect(Collectors.toSet());
-        assertTrue(requires.size() == 2);
-        assertTrue(requires.contains("java.base"));
-        assertTrue(requires.contains("-m1"));
-
-        assertTrue(descriptor.exports().size() == 1);
-        Exports e = descriptor.exports().iterator().next();
-        assertTrue(e.targets().size() == 1);
-        assertTrue(e.targets().contains("m2-"));
-    }
-
     /**
      * Test ModuleDescriptor with a packager finder
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/module/ModuleNamesTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,261 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @modules java.base/jdk.internal.misc
+ *          java.base/jdk.internal.module
+ * @run testng ModuleNamesTest
+ * @summary Basic test of reading a module-info.class with module names that
+ *          are legal in class files but not legal in the Java Language
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.nio.ByteBuffer;
+import java.util.Optional;
+import java.util.Set;
+
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleInfoWriter;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class ModuleNamesTest {
+
+    @DataProvider(name = "legalModuleNames")
+    public Object[][] legalModuleNames() {
+        return new Object[][] {
+
+                { ".",              "." },
+                { ".foo",           ".foo" },
+                { "foo.",           "foo." },
+                { "foo.bar",        "foo.bar" },
+
+                { "..",             ".." },
+                { "..foo",          "..foo" },
+                { "foo..",          "foo.." },
+                { "foo..bar",       "foo..bar" },
+
+                { "[",              "[" },
+                { "[foo",           "[foo" },
+                { "foo[",           "foo[" },
+                { "foo[bar",        "foo[bar" },
+
+                { ";",              ";" },
+                { ";foo",           ";foo" },
+                { "foo;",           "foo;" },
+                { "foo;bar",        "foo;bar" },
+
+                { "\\\\",           "\\" },
+                { "\\\\foo",        "\\foo" },
+                { "foo\\\\",        "foo\\" },
+                { "foo\\\\bar",     "foo\\bar" },
+
+                { "\\\\\\\\",       "\\\\" },
+                { "\\\\\\\\foo",    "\\\\foo" },
+                { "foo\\\\\\\\",    "foo\\\\" },
+                { "foo\\\\\\\\bar", "foo\\\\bar" },
+
+                { "\\:",            ":" },
+                { "\\:foo",         ":foo" },
+                { "foo\\:",         "foo:" },
+                { "foo\\:bar",      "foo:bar" },
+
+                { "\\:\\:",         "::" },
+                { "\\:\\:foo",      "::foo" },
+                { "foo\\:\\:",      "foo::" },
+                { "foo\\:\\:bar",   "foo::bar" },
+
+                { "\\@",            "@" },
+                { "\\@foo",         "@foo" },
+                { "foo\\@",         "foo@" },
+                { "foo\\@bar",      "foo@bar" },
+
+                { "\\@\\@",         "@@" },
+                { "\\@\\@foo",      "@@foo" },
+                { "foo\\@\\@",      "foo@@" },
+                { "foo\\@\\@bar",   "foo@@bar" },
+
+                { makeString("", 0x20, ""),        " "  },
+                { makeString("foo", 0x20, ""),     "foo " },
+                { makeString("", 0x20, "foo"),     " foo" },
+                { makeString("foo", 0x20, "bar"),  "foo bar" },
+        };
+    }
+
+    @DataProvider(name = "illegalModuleNames")
+    public Object[][] illegalModuleNames() {
+        return new Object[][] {
+
+                { "",               null },
+
+                { ":",              null },
+                { ":foo",           null },
+                { "foo:",           null },
+                { "foo:bar",        null },
+
+                { "@",              null },
+                { "@foo",           null },
+                { "foo@",           null },
+                { "foo@bar",        null },
+
+                { "\\",            null },
+                { "\\foo",         null },
+                { "foo\\",         null },
+                { "foo\\bar",      null },
+
+                { makeString("", 0x00, ""),         null },
+                { makeString("", 0x00, "foo"),      null },
+                { makeString("foo", 0x00, ""),      null },
+                { makeString("foo", 0x00, "bar"),   null },
+
+                { makeString("", 0x1f, ""),         null },
+                { makeString("", 0x1f, "foo"),      null },
+                { makeString("foo", 0x1f, ""),      null },
+                { makeString("foo", 0x1f, "bar"),   null },
+
+        };
+    }
+
+    @Test(dataProvider = "legalModuleNames")
+    public void testLegalModuleName(String mn, String expected) throws Exception {
+        ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
+        ByteBuffer bb = toBuffer(md);
+        String name = ModuleDescriptor.read(bb).name();
+        assertEquals(name, expected);
+    }
+
+    @Test(dataProvider = "illegalModuleNames",
+          expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testIllegalModuleName(String mn, String ignore) throws Exception {
+        ModuleDescriptor md = newBuilder(mn).requires("java.base").build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor.read(bb);  // throws InvalidModuleDescriptorException
+    }
+
+    @Test(dataProvider = "legalModuleNames")
+    public void testLegalRequires(String mn, String expected) throws Exception {
+        ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+        Optional<Requires> requires = descriptor.requires().stream()
+                .filter(r -> !r.name().equals("java.base"))
+                .findAny();
+        assertTrue(requires.isPresent());
+        assertEquals(requires.get().name(), expected);
+    }
+
+    @Test(dataProvider = "illegalModuleNames",
+          expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testIllegalRequires(String mn, String ignore) throws Exception {
+        ModuleDescriptor md = newBuilder("m").requires("java.base").requires(mn).build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
+    }
+
+    @Test(dataProvider = "legalModuleNames")
+    public void testLegalExports(String mn, String expected) throws Exception {
+        ModuleDescriptor md = newBuilder("m")
+                .requires("java.base")
+                .exports("p", Set.of(mn))
+                .build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+        Optional<Exports> export = descriptor.exports().stream().findAny();
+        assertTrue(export.isPresent());
+        assertTrue(export.get().targets().contains(expected));
+    }
+
+    @Test(dataProvider = "illegalModuleNames",
+          expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testIllegalExports(String mn, String ignore) throws Exception {
+        ModuleDescriptor md = newBuilder("m")
+                .requires("java.base")
+                .exports("p", Set.of(mn))
+                .build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
+    }
+
+    @Test(dataProvider = "legalModuleNames")
+    public void testLegalOpens(String mn, String expected) throws Exception {
+        ModuleDescriptor md = newBuilder("m")
+                .requires("java.base")
+                .opens("p", Set.of(mn))
+                .build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor descriptor = ModuleDescriptor.read(bb);
+        Optional<Opens> opens = descriptor.opens().stream().findAny();
+        assertTrue(opens.isPresent());
+        assertTrue(opens.get().targets().contains(expected));
+    }
+
+    @Test(dataProvider = "illegalModuleNames",
+          expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testIllegalOpens(String mn, String ignore) throws Exception {
+        ModuleDescriptor md = newBuilder("m")
+                .requires("java.base")
+                .opens("p", Set.of(mn))
+                .build();
+        ByteBuffer bb = toBuffer(md);
+        ModuleDescriptor.read(bb);   // throws InvalidModuleDescriptorException
+    }
+
+    /**
+     * Returns a Builder that does not validate module names.
+     */
+    private Builder newBuilder(String mn) {
+        return SharedSecrets.getJavaLangModuleAccess()
+                            .newModuleBuilder(mn, false, false, false);
+    }
+
+    /**
+     * Returns a {@code ByteBuffer} containing the given module descriptor
+     * in module-info.class format.
+     */
+    private ByteBuffer toBuffer(ModuleDescriptor descriptor) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ModuleInfoWriter.write(descriptor, baos);
+        return ByteBuffer.wrap(baos.toByteArray());
+    }
+
+    /**
+     * Returns a string containing a given code point.
+     */
+    private String makeString(String prefix, int codePoint, String suffix) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(prefix);
+        sb.appendCodePoint(codePoint);
+        sb.append(suffix);
+        return sb.toString();
+    }
+}
--- a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -24,7 +24,7 @@
 /**
  * @test
  * @library /lib/testlibrary
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/jdk.internal.module
  *          jdk.compiler
  * @build ModuleReaderTest CompilerUtils JarUtils
  * @run testng ModuleReaderTest
@@ -53,7 +53,7 @@
 import java.util.stream.Collectors;
 import java.util.spi.ToolProvider;
 
-import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModulePath;
 
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
@@ -216,9 +216,7 @@
      */
     void test(Path mp) throws IOException {
 
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, mp);
-
+        ModuleFinder finder = new ModulePath(Runtime.version(), true, mp);
         ModuleReference mref = finder.find(TEST_MODULE).get();
         ModuleReader reader = mref.open();
 
--- a/jdk/test/java/lang/module/ModuleReferenceTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/module/ModuleReferenceTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -31,7 +31,6 @@
 import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
 import java.net.URI;
-import java.util.function.Supplier;
 
 import org.testng.annotations.Test;
 import static org.testng.Assert.*;
@@ -39,8 +38,13 @@
 @Test
 public class ModuleReferenceTest {
 
-    private Supplier<ModuleReader> makeSupplier() {
-        return () -> { throw new UnsupportedOperationException(); };
+    private ModuleReference newModuleReference(ModuleDescriptor descriptor, URI uri) {
+        return new ModuleReference(descriptor, uri) {
+            @Override
+            public ModuleReader open() {
+                throw new UnsupportedOperationException();
+            }
+        };
     }
 
     public void testBasic() throws Exception {
@@ -53,25 +57,16 @@
 
         URI uri = URI.create("module:/m");
 
-        Supplier<ModuleReader> supplier = makeSupplier();
-
-        ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
+        ModuleReference mref = newModuleReference(descriptor, uri);
 
         assertTrue(mref.descriptor().equals(descriptor));
         assertTrue(mref.location().get().equals(uri));
-
-        // check that the supplier is called
-        try {
-            mref.open();
-            assertTrue(false);
-        } catch (UnsupportedOperationException expected) { }
     }
 
-
     @Test(expectedExceptions = { NullPointerException.class })
     public void testNullDescriptor() throws Exception {
         URI location = URI.create("module:/m");
-        new ModuleReference(null, location, makeSupplier());
+        newModuleReference(null, location);
     }
 
     public void testNullLocation() {
@@ -79,55 +74,8 @@
             = ModuleDescriptor.module("m")
                 .exports("p")
                 .build();
-        Supplier<ModuleReader> supplier = makeSupplier();
-        ModuleReference mref = new ModuleReference(descriptor, null, supplier);
+        ModuleReference mref = newModuleReference(descriptor, null);
         assertTrue(!mref.location().isPresent());
     }
 
-    @Test(expectedExceptions = { NullPointerException.class })
-    public void testNullSupplier() throws Exception {
-        ModuleDescriptor descriptor = ModuleDescriptor.module("m").build();
-        URI location = URI.create("module:/m");
-        new ModuleReference(descriptor, location, null);
-    }
-
-
-    public void testEqualsAndHashCode() {
-        ModuleDescriptor descriptor1
-            = ModuleDescriptor.module("m1")
-                .exports("p")
-                .build();
-        ModuleDescriptor descriptor2
-            = ModuleDescriptor.module("m1")
-                .exports("p")
-                .build();
-
-        URI uri = URI.create("module:/m1");
-        Supplier<ModuleReader> supplier = makeSupplier();
-
-        ModuleReference mref1 = new ModuleReference(descriptor1, uri, supplier);
-        ModuleReference mref2 = new ModuleReference(descriptor2, uri, supplier);
-        ModuleReference mref3 = new ModuleReference(descriptor1, null, supplier);
-
-        assertTrue(mref1.equals(mref1));
-        assertTrue(mref1.equals(mref2));
-        assertTrue(mref2.equals(mref1));
-        assertTrue(mref1.hashCode() == mref2.hashCode());
-
-        assertTrue(mref3.equals(mref3));
-        assertFalse(mref3.equals(mref1));
-        assertFalse(mref1.equals(mref3));
-    }
-
-
-    public void testToString() {
-        ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build();
-        URI uri = URI.create("module:/m1");
-        Supplier<ModuleReader> supplier = makeSupplier();
-        ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
-        String s = mref.toString();
-        assertTrue(s.contains("m1"));
-        assertTrue(s.contains(uri.toString()));
-    }
-
 }
--- a/jdk/test/java/lang/reflect/Module/AnnotationsTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -119,7 +119,6 @@
             List<Attribute> attrs = new ArrayList<>();
             attrs.add(new ClassFileAttributes.ModuleAttribute());
             attrs.add(new ClassFileAttributes.ModulePackagesAttribute());
-            attrs.add(new ClassFileAttributes.ModuleVersionAttribute());
             attrs.add(new ClassFileAttributes.ModuleTargetAttribute());
             cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
 
--- a/jdk/test/java/net/URLClassLoader/closetest/CloseTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/net/URLClassLoader/closetest/CloseTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -21,10 +21,11 @@
  * questions.
  */
 
-/**
+/*
  * @test
  * @bug 4167874
- * @modules jdk.httpserver
+ * @modules java.logging
+ *          jdk.httpserver
  * @library ../../../../com/sun/net/httpserver
  * @library /lib/testlibrary
  * @build FileServerHandler jdk.testlibrary.FileUtils
@@ -33,10 +34,13 @@
  * @summary URL-downloaded jar files can consume all available file descriptors
  */
 
-import java.io.*;
-import java.net.*;
-import java.lang.reflect.*;
-import com.sun.net.httpserver.*;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpServer;
 
 public class CloseTest extends Common {
 
@@ -130,7 +134,7 @@
         // load tests
         loadClass ("com.foo.TestClass1", loader, false);
         loadClass ("com.foo.TestClass", loader, true);
-        loadClass ("java.sql.Array", loader, true);
+        loadClass ("java.util.ArrayList", loader, true);
 
         // now check we can delete the path
         rm_minus_rf (new File(name));
--- a/jdk/test/java/rmi/registry/reexport/Reexport.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/java/rmi/registry/reexport/Reexport.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -67,10 +67,6 @@
             System.err.println("Creating duplicate registry, this should fail...");
             reg = createReg(true, regPort);
 
-            if (reg != null) {
-                TestLibrary.bomb("failed was able to duplicate the registry?!?");
-            }
-
             // Kill the first registry.
             System.err.println("Bringing down the first registry");
             try {
@@ -105,6 +101,9 @@
 
         try {
             reg = LocateRegistry.createRegistry(port);
+            if (remoteOk) {
+                TestLibrary.bomb("Remote registry is up, an Exception is expected!");
+            }
         } catch (Throwable e) {
             if (remoteOk) {
                 System.err.println("EXPECTING PORT IN USE EXCEPTION:");
--- a/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/MultiPageImageTIFFFieldTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -223,7 +223,7 @@
         ImageReader reader = getTIFFReader();
 
         ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME));
-        reader.setInput(s, false, true);
+        reader.setInput(s, false, false);
 
         int ni = reader.getNumImages(true);
         check(ni == 2, "invalid number of images");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/ReadUnknownTagsTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug     8154058
+ * @author  a.stepanov
+ * @summary Some checks for ignoring metadata
+ * @run     main ReadUnknownTagsTest
+ */
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import javax.imageio.*;
+import javax.imageio.metadata.*;
+
+import javax.imageio.stream.*;
+import javax.imageio.plugins.tiff.*;
+
+
+public class ReadUnknownTagsTest {
+
+    private final static int SZ = 50;
+    private final static Color C = Color.RED;
+
+    private final static int DESCRIPTION_TAG =
+        BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION;
+    private final static String DESCRIPTION = "A Test Image";
+
+    private final static int FAX_TAG = FaxTIFFTagSet.TAG_CLEAN_FAX_DATA;
+    private final static short FAX_DATA =
+        FaxTIFFTagSet.CLEAN_FAX_DATA_ERRORS_UNCORRECTED;
+
+    private final boolean ignoreMetadata;
+    private final boolean readUnknownTags;
+
+    public ReadUnknownTagsTest(boolean ignoreMetadata,
+        boolean readUnknownTags) {
+        this.ignoreMetadata = ignoreMetadata;
+        this.readUnknownTags = readUnknownTags;
+    }
+
+    private ImageWriter getTIFFWriter() {
+
+        java.util.Iterator<ImageWriter> writers =
+            ImageIO.getImageWritersByFormatName("TIFF");
+        if (!writers.hasNext()) {
+            throw new RuntimeException("No writers available for TIFF format");
+        }
+        return writers.next();
+    }
+
+    private ImageReader getTIFFReader() {
+
+        java.util.Iterator<ImageReader> readers =
+            ImageIO.getImageReadersByFormatName("TIFF");
+        if (!readers.hasNext()) {
+            throw new RuntimeException("No readers available for TIFF format");
+        }
+        return readers.next();
+    }
+
+
+    private void writeImage() throws Exception {
+
+        String fn = "test-" + ignoreMetadata + ".tiff";
+        OutputStream s = new BufferedOutputStream(new FileOutputStream(fn));
+        try (ImageOutputStream ios = ImageIO.createImageOutputStream(s)) {
+
+            ImageWriter writer = getTIFFWriter();
+            writer.setOutput(ios);
+
+            BufferedImage img = new BufferedImage(SZ, SZ,
+                BufferedImage.TYPE_INT_RGB);
+            Graphics g = img.getGraphics();
+            g.setColor(C);
+            g.fillRect(0, 0, SZ, SZ);
+            g.dispose();
+
+            ImageWriteParam param = writer.getDefaultWriteParam();
+
+            IIOMetadata md = writer.getDefaultImageMetadata(
+                    new ImageTypeSpecifier(img), param);
+
+            TIFFDirectory dir = TIFFDirectory.createFromMetadata(md);
+
+            TIFFTag descTag =
+                BaselineTIFFTagSet.getInstance().getTag(DESCRIPTION_TAG);
+            dir.addTIFFField(new TIFFField(descTag, TIFFTag.TIFF_ASCII, 1,
+                new String[] {DESCRIPTION}));
+
+            TIFFTag faxTag = FaxTIFFTagSet.getInstance().getTag(FAX_TAG);
+            dir.addTIFFField(new TIFFField(faxTag, FAX_DATA));
+
+            writer.write(new IIOImage(img, null, dir.getAsMetadata()));
+
+            ios.flush();
+            writer.dispose();
+        }
+        s.close();
+    }
+
+    private void readAndCheckImage() throws Exception {
+
+        ImageReader reader = getTIFFReader();
+
+        String fn = "test-" + ignoreMetadata + ".tiff";
+        ImageInputStream s = ImageIO.createImageInputStream(new File(fn));
+
+        reader.setInput(s, false, ignoreMetadata);
+
+        int ni = reader.getNumImages(true);
+        check(ni == 1, "invalid number of images");
+
+
+        TIFFImageReadParam param = new TIFFImageReadParam();
+        // fax data are allowed by default
+        param.removeAllowedTagSet(FaxTIFFTagSet.getInstance());
+
+        // readUnknownTags setting
+        if (param.getReadUnknownTags()) {
+            throw new RuntimeException("Default readUnknownTags is not false");
+        }
+        param.setReadUnknownTags(readUnknownTags);
+        if (param.getReadUnknownTags() != readUnknownTags) {
+            throw new RuntimeException("Incorrect readUnknownTags setting "
+                + "\"" + readUnknownTags + "\"");
+        }
+
+        // read images and metadata
+        IIOImage i = reader.readAll(0, param);
+        BufferedImage bi = (BufferedImage) i.getRenderedImage();
+
+        check(bi.getWidth()  == SZ, "invalid width");
+        check(bi.getHeight() == SZ, "invalid height");
+        Color c = new Color(bi.getRGB(SZ / 2, SZ / 2));
+        check(c.equals(C), "invalid color");
+
+        IIOMetadata metadata = i.getMetadata();
+
+        //
+        // Verify presence of image metadata
+        //
+        if (metadata == null) {
+            throw new RuntimeException("No image metadata retrieved");
+        }
+
+        TIFFDirectory dir = TIFFDirectory.createFromMetadata(metadata);
+
+        //
+        // Verify presence of essential ImageWidth field regardless of
+        // settings of ignoreMetadata and readUnknownTags
+        //
+        int failures = 0;
+        if (!dir.containsTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH)) {
+            System.err.println("Metadata is missing essential ImageWidth tag");
+            failures++;
+        } else {
+            TIFFField widthField =
+                dir.getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH);
+            System.out.printf("ImageWidth: %d%n", widthField.getAsLong(0));
+        }
+
+        //
+        // Verify presence of non-essential baseline ImageDescription field
+        // if and only if ignoreMetadata == false
+        //
+        boolean hasDescription = dir.containsTIFFField(DESCRIPTION_TAG);
+        System.out.println("ImageDescription (" + !ignoreMetadata + "): "
+            + hasDescription);
+        if (ignoreMetadata && hasDescription) {
+            System.err.println
+                ("Description metadata present despite ignoreMetadata");
+            failures++;
+        } else if (!ignoreMetadata && !hasDescription) {
+            System.err.println
+                ("Description metadata absent despite !ignoreMetadata");
+            failures++;
+        }
+
+        //
+        // Verify presence of CleanFaxData field if and only if
+        // ignoreMetadata == false and readUnknownTags == true
+        //
+        boolean shouldHaveFaxField = !ignoreMetadata && readUnknownTags;
+        boolean hasFaxField = dir.containsTIFFField(FAX_TAG);
+        System.out.println("CleanFaxData (" + shouldHaveFaxField + "): "
+            + hasFaxField);
+
+        if (ignoreMetadata) {
+            if (hasFaxField) {
+                System.err.println
+                    ("Fax metadata present despite ignoreMetadata");
+                failures++;
+            }
+        } else { // !ignoreMetadata
+            if (!readUnknownTags && hasFaxField) {
+                System.err.println
+                    ("Fax metadata present despite !readUnknownTags");
+                failures++;
+            } else if (readUnknownTags && !hasFaxField) {
+                System.err.println
+                    ("Fax metadata absent despite readUnknownTags");
+                failures++;
+            }
+        }
+
+        if (failures > 0) {
+            throw new RuntimeException("Test failed for ignoreMetadata "
+                + ignoreMetadata + " and readUnknownTags " + readUnknownTags);
+        }
+    }
+
+    public void run() {
+        try {
+            writeImage();
+            readAndCheckImage();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void check(boolean ok, String msg) {
+        if (!ok) { throw new RuntimeException(msg); }
+    }
+
+    public static void main(String[] args) {
+        int failures = 0;
+
+        System.out.println();
+        for (boolean ignoreMetadata : new boolean[] {false, true}) {
+            for (boolean readUnknownTags : new boolean[] {false, true}) {
+                try {
+                    System.out.printf
+                        ("ignoreMetadata: %s, readUnknownTags: %s%n",
+                        ignoreMetadata, readUnknownTags);
+                    (new ReadUnknownTagsTest(ignoreMetadata,
+                        readUnknownTags)).run();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    failures++;
+                } finally {
+                    System.out.println();
+                }
+            }
+        }
+    }
+}
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFDirectoryTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -154,7 +154,7 @@
             "must return null TIFFField");
 
         long offset = 4L;
-        long a[] = {Long.MIN_VALUE, 0, Long.MAX_VALUE};
+        long a[] = {0, Integer.MAX_VALUE, (1 << 32) - 1};
         int v = 100500;
         TIFFField
                 f1 = new TIFFField(tag1, type, offset, d),
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFFieldTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug     8152183 8149562
+ * @bug     8152183 8149562 8169725 8169728
  * @author  a.stepanov
  * @summary Some checks for TIFFField methods
  * @run     main TIFFFieldTest
@@ -65,7 +65,26 @@
         ok = false;
         try { new TIFFField(tag, -1); }
         catch (IllegalArgumentException e) { ok = true; }
-        check(ok, CONSTRUCT + "invalid count");
+        check(ok, CONSTRUCT + "negative value");
+
+        ok = false;
+        try { new TIFFField(tag, 1L << 32); }
+        catch (IllegalArgumentException e) { ok = true; }
+        check(ok, CONSTRUCT + "value > 0xffffffff");
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SHORT);
+            new TIFFField(t, 0x10000);
+        } catch (IllegalArgumentException e) { ok = true; }
+        check(ok, CONSTRUCT + "value 0x10000 incompatible with TIFF_SHORT");
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
+            new TIFFField(t, 0xffff);
+        } catch (IllegalArgumentException e) { ok = true; }
+        check(ok, CONSTRUCT + "value 0xffff incompatible with TIFF_LONG");
 
         // check value type recognition
         int v = 1 << 16;
@@ -152,6 +171,94 @@
         check((f.getDirectory() == null) && !f.hasDirectory(),
             "must not have directory");
 
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
+            long[][] tiffRationals = new long[6][3];
+            new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
+                tiffRationals);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_SRATIONAL);
+            int[][] tiffSRationals = new int[6][3];
+            new TIFFField(t, TIFFTag.TIFF_SRATIONAL, tiffSRationals.length,
+                tiffSRationals);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
+            long[] tiffLongs = new long[] {0, -7, 10};
+            new TIFFField(t, TIFFTag.TIFF_LONG, tiffLongs.length,
+                tiffLongs);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_LONG);
+            long[] tiffLongs = new long[] {0, 7, 0x100000000L};
+            new TIFFField(t, TIFFTag.TIFF_LONG, tiffLongs.length,
+                tiffLongs);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_IFD_POINTER);
+            long[] tiffLongs = new long[] {-7};
+            new TIFFField(t, TIFFTag.TIFF_IFD_POINTER, tiffLongs.length,
+                tiffLongs);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_IFD_POINTER);
+            long[] tiffLongs = new long[] {0x100000000L};
+            new TIFFField(t, TIFFTag.TIFF_IFD_POINTER, tiffLongs.length,
+                tiffLongs);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
+            long[][] tiffRationals = new long[][] {
+                {10, 2},
+                {1, -3},
+                {4,  7}
+            };
+            new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
+                tiffRationals);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
+        ok = false;
+        try {
+            TIFFTag t = new TIFFTag(NAME, NUM, 1 << TIFFTag.TIFF_RATIONAL);
+            long[][] tiffRationals = new long[][] {
+                {10, 2},
+                {0x100000000L, 3},
+                {4,  7}
+            };
+            new TIFFField(t, TIFFTag.TIFF_RATIONAL, tiffRationals.length,
+                tiffRationals);
+        } catch (IllegalArgumentException e) {
+            ok = true;
+        }
+
         // constructor: TIFFField(tag, type, offset, dir)
         List<TIFFTag> tags = new ArrayList<>();
         tags.add(tag);
--- a/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/imageio/plugins/tiff/TIFFImageReadParamTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -159,7 +159,7 @@
         ImageReader reader = getTIFFReader();
 
         ImageInputStream s = ImageIO.createImageInputStream(new File(FILENAME));
-        reader.setInput(s, false, true);
+        reader.setInput(s, false, false);
 
         int ni = reader.getNumImages(true);
         check(ni == 1, "invalid number of images: " + ni);
--- a/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java	Mon Dec 19 16:05:38 2016 +0000
@@ -34,15 +34,17 @@
     static final String ERROR = "ERROR";
     X509ExtendedKeyManager akm;
     String expectedAP;
+    boolean doCheck = true;
 
     MyX509ExtendedKeyManager(X509ExtendedKeyManager akm) {
         this.akm = akm;
     }
 
     public MyX509ExtendedKeyManager(
-            X509ExtendedKeyManager akm, String expectedAP) {
+            X509ExtendedKeyManager akm, String expectedAP, boolean doCheck) {
         this.akm = akm;
         this.expectedAP = expectedAP;
+        this.doCheck = doCheck;
 
     }
 
@@ -104,6 +106,12 @@
 
     private void checkALPN(String ap) {
 
+        if (!doCheck) {
+            System.out.println("Skipping KeyManager checks " +
+                "because a callback has been registered");
+            return;
+        }
+
         if (ERROR.equals(expectedAP)) {
             throw new RuntimeException("Should not reach here");
         }
--- a/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -26,23 +26,53 @@
 
 /*
  * @test
- * @bug 8051498 8145849
+ * @bug 8051498 8145849 8170282
  * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
  * @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLEngineAlpnTest h2          h2          h2
- * @run main/othervm SSLEngineAlpnTest h2          h2,http/1.1 h2
- * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLEngineAlpnTest h4,h3,h2    h1,h2       h2
- * @run main/othervm SSLEngineAlpnTest EMPTY       h2,http/1.1 NONE
- * @run main/othervm SSLEngineAlpnTest h2          EMPTY       NONE
- * @run main/othervm SSLEngineAlpnTest H2          h2          ERROR
- * @run main/othervm SSLEngineAlpnTest h2          http/1.1    ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   h2          h2
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 UNUSED   h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest h4,h3,h2    UNUSED   h1,h2       h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY       UNUSED   h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   EMPTY       NONE
+ * @run main/othervm SSLEngineAlpnTest H2          UNUSED   h2          ERROR
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   http/1.1    ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       h2          h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       http/1.1,h2 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED      http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest UNUSED      EMPTY    h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       EMPTY       NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED      H2       h2          ERROR
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       http/1.1    ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest h2          h2       h2          h2
+ * @run main/othervm SSLEngineAlpnTest H2          h2       h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2       h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY       h2       h2          h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 EMPTY    http/1.1    NONE
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2       EMPTY       NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED      UNUSED   http/1.1,h2 NONE
+ * @run main/othervm SSLEngineAlpnTest h2          h2       http/1.1    ERROR
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 H2       http/1.1    ERROR
  */
 /**
  * A simple SSLEngine-based client/server that demonstrates the proposed API
  * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
  *
+ * Usage:
+ *     java SSLEngineAlpnTest <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ *      EMPTY  indicates that ALPN is disabled
+ *      UNUSED indicates that no ALPN values are supplied (server-side only)
+ *      ERROR  indicates that an exception is expected
+ *      NONE   indicates that no ALPN is expected
+ *
  * This example is based on our standard SSLEngineTemplate.
  *
  * The immediate consumer of ALPN will be HTTP/2 (RFC 7540), aka H2. The H2 IETF
@@ -98,6 +128,7 @@
 import java.io.*;
 import java.security.*;
 import java.nio.*;
+import java.util.Arrays;
 
 public class SSLEngineAlpnTest {
 
@@ -117,6 +148,9 @@
      */
     private static final boolean debug = false;
 
+    private static boolean hasServerAPs; // whether server APs are present
+    private static boolean hasCallback; // whether a callback is present
+
     private final SSLContext sslc;
 
     private SSLEngine clientEngine;     // client Engine
@@ -157,17 +191,21 @@
         if (debug) {
             System.setProperty("javax.net.debug", "all");
         }
+        System.out.println("Test args: " + Arrays.toString(args));
 
         // Validate parameters
-        if (args.length != 3) {
+        if (args.length != 4) {
             throw new Exception("Invalid number of test parameters");
         }
 
-        SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[2]);
+        hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+        hasCallback = !args[1].equals("UNUSED"); // is callback being used?
+
+        SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[3]);
         try {
-            test.runTest(convert(args[0]), convert(args[1]), args[2]);
+            test.runTest(convert(args[0]), args[1], convert(args[2]), args[3]);
         } catch (SSLHandshakeException she) {
-            if (args[2].equals("ERROR")) {
+            if (args[3].equals("ERROR")) {
                 System.out.println("Caught the expected exception: " + she);
             } else {
                 throw she;
@@ -199,7 +237,8 @@
         }
 
         kms = new KeyManager[] { new MyX509ExtendedKeyManager(
-                (X509ExtendedKeyManager) kms[0], expectedAP) };
+                (X509ExtendedKeyManager) kms[0], expectedAP,
+                !hasCallback && hasServerAPs) };
 
         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
         tmf.init(ts);
@@ -215,12 +254,15 @@
      * Convert a comma-separated list into an array of strings.
      */
     private static String[] convert(String list) {
-        String[] strings = null;
+        if (list.equals("UNUSED")) {
+            return null;
+        }
 
         if (list.equals("EMPTY")) {
             return new String[0];
         }
 
+        String[] strings;
         if (list.indexOf(',') > 0) {
             strings = list.split(",");
         } else {
@@ -247,12 +289,12 @@
      * One could easily separate these phases into separate
      * sections of code.
      */
-    private void runTest(String[] serverAPs, String[] clientAPs,
-            String expectedAP) throws Exception {
+    private void runTest(String[] serverAPs, String callbackAP,
+            String[] clientAPs, String expectedAP) throws Exception {
 
         boolean dataDone = false;
 
-        createSSLEngines(serverAPs, clientAPs);
+        createSSLEngines(serverAPs, callbackAP, clientAPs);
         createBuffers();
 
         SSLEngineResult clientResult;   // results from client's last operation
@@ -364,8 +406,8 @@
      * Using the SSLContext created during object creation,
      * create/configure the SSLEngines we'll use for this test.
      */
-    private void createSSLEngines(String[] serverAPs, String[] clientAPs)
-        throws Exception {
+    private void createSSLEngines(String[] serverAPs, String callbackAP,
+            String[] clientAPs) throws Exception {
         /*
          * Configure the serverEngine to act as a server in the SSL/TLS
          * handshake.  Also, require SSL client authentication.
@@ -385,18 +427,42 @@
          */
         String[] suites = sslp.getCipherSuites();
         sslp.setCipherSuites(suites);
-        sslp.setApplicationProtocols(serverAPs);
+        if (serverAPs != null) {
+            sslp.setApplicationProtocols(serverAPs);
+        }
         sslp.setUseCipherSuitesOrder(true);  // Set server side order
 
         serverEngine.setSSLParameters(sslp);
 
+        // check that no callback has been registered
+        if (serverEngine.getHandshakeApplicationProtocolSelector() != null) {
+            throw new Exception("getHandshakeApplicationProtocolSelector() " +
+                "should return null");
+        }
+
+        if (hasCallback) {
+            serverEngine.setHandshakeApplicationProtocolSelector(
+                (sslEngine, clientProtocols) -> {
+                    return callbackAP.equals("EMPTY") ? "" : callbackAP;
+                });
+
+            // check that the callback can be retrieved
+            if (serverEngine.getHandshakeApplicationProtocolSelector()
+                    == null) {
+                throw new Exception("getHandshakeApplicationProtocolSelector()"
+                    + " should return non-null");
+            }
+        }
+
         /*
          * Similar to above, but using client mode instead.
          */
         clientEngine = sslc.createSSLEngine("client", 80);
         clientEngine.setUseClientMode(true);
         sslp = clientEngine.getSSLParameters();
-        sslp.setApplicationProtocols(clientAPs);
+        if (clientAPs != null) {
+            sslp.setApplicationProtocols(clientAPs);
+        }
         clientEngine.setSSLParameters(sslp);
 
         if ((clientEngine.getHandshakeApplicationProtocol() != null) ||
--- a/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -26,22 +26,61 @@
 
 /*
  * @test
- * @bug 8051498 8145849 8158978
+ * @bug 8051498 8145849 8158978 8170282
  * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
  * @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLServerSocketAlpnTest h2          h2          h2
- * @run main/othervm SSLServerSocketAlpnTest h2          h2,http/1.1 h2
- * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLServerSocketAlpnTest h4,h3,h2    h1,h2       h2
- * @run main/othervm SSLServerSocketAlpnTest EMPTY       h2,http/1.1 NONE
- * @run main/othervm SSLServerSocketAlpnTest h2          EMPTY       NONE
- * @run main/othervm SSLServerSocketAlpnTest H2          h2          ERROR
- * @run main/othervm SSLServerSocketAlpnTest h2          http/1.1    ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest h2          UNUSED   h2          h2
+ * @run main/othervm SSLServerSocketAlpnTest h2          UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 UNUSED   h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest h4,h3,h2    UNUSED   h1,h2       h2
+ * @run main/othervm SSLServerSocketAlpnTest EMPTY       UNUSED   h2,http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2          UNUSED   EMPTY       NONE
+ * @run main/othervm SSLServerSocketAlpnTest H2          UNUSED   h2          ERROR
+ * @run main/othervm SSLServerSocketAlpnTest h2          UNUSED   http/1.1    ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       h2          h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       http/1.1,h2 h2
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      EMPTY    h2,http/1.1 NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       EMPTY       NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      H2       h2          ERROR
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      h2       http/1.1    ERROR
+ *
+ * @run main/othervm SSLServerSocketAlpnTest h2          h2       h2          h2
+ * @run main/othervm SSLServerSocketAlpnTest H2          h2       h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2       h2,http/1.1 h2
+ * @run main/othervm SSLServerSocketAlpnTest EMPTY       h2       h2          h2
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 EMPTY    http/1.1    NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2       EMPTY       NONE
+ * @run main/othervm SSLServerSocketAlpnTest UNUSED      UNUSED   http/1.1,h2 NONE
+ * @run main/othervm SSLServerSocketAlpnTest h2          h2       http/1.1    ERROR
+ * @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 H2       http/1.1    ERROR
+ *
  * @author Brad Wetmore
  */
+/**
+ * A simple SSLSocket-based client/server that demonstrates the proposed API
+ * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
+ *
+ * Usage:
+ *     java SSLServerSocketAlpnTest
+ *             <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ *      EMPTY  indicates that ALPN is disabled
+ *      UNUSED indicates that no ALPN values are supplied (server-side only)
+ *      ERROR  indicates that an exception is expected
+ *      NONE   indicates that no ALPN is expected
+ *
+ * This example is based on our standard SSLSocketTemplate.
+ */
 import java.io.*;
 import java.security.KeyStore;
+import java.util.Arrays;
 
 import javax.net.ssl.*;
 
@@ -73,6 +112,9 @@
     static String trustFilename = System.getProperty("test.src", ".") + "/"
             + pathToStores + "/" + trustStoreFile;
 
+    private static boolean hasServerAPs; // whether server APs are present
+    private static boolean hasCallback; // whether a callback is present
+
     /*
      * SSLContext
      */
@@ -89,6 +131,7 @@
     static boolean debug = false;
 
     static String[] serverAPs;
+    static String callbackAP;
     static String[] clientAPs;
     static String expectedAP;
 
@@ -129,7 +172,9 @@
         sslp.setUseCipherSuitesOrder(true); // Set server side order
 
         // Set the ALPN selection.
-        sslp.setApplicationProtocols(serverAPs);
+        if (serverAPs != null) {
+            sslp.setApplicationProtocols(serverAPs);
+        }
         sslServerSocket.setSSLParameters(sslp);
 
         serverPort = sslServerSocket.getLocalPort();
@@ -146,6 +191,25 @@
                     + "return null before the handshake starts");
         }
 
+        // check that no callback has been registered
+        if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {
+            throw new Exception("getHandshakeApplicationProtocolSelector() " +
+                "should return null");
+        }
+
+        if (hasCallback) {
+            sslSocket.setHandshakeApplicationProtocolSelector(
+                (serverSocket, clientProtocols) -> {
+                    return callbackAP.equals("EMPTY") ? "" : callbackAP;
+                });
+
+            // check that the callback can be retrieved
+            if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {
+                throw new Exception("getHandshakeApplicationProtocolSelector()"
+                    + " should return non-null");
+            }
+        }
+
         sslSocket.startHandshake();
 
         if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -276,14 +340,19 @@
         if (debug) {
             System.setProperty("javax.net.debug", "all");
         }
+        System.out.println("Test args: " + Arrays.toString(args));
 
         // Validate parameters
-        if (args.length != 3) {
+        if (args.length != 4) {
             throw new Exception("Invalid number of test parameters");
         }
         serverAPs = convert(args[0]);
-        clientAPs = convert(args[1]);
-        expectedAP = args[2];
+        callbackAP = args[1];
+        clientAPs = convert(args[2]);
+        expectedAP = args[3];
+
+        hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+        hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?
 
         /*
          * Start the tests.
@@ -291,7 +360,7 @@
         try {
             new SSLServerSocketAlpnTest();
         } catch (SSLHandshakeException she) {
-            if (args[2].equals("ERROR")) {
+            if (args[3].equals("ERROR")) {
                 System.out.println("Caught the expected exception: " + she);
             } else {
                 throw she;
@@ -322,7 +391,8 @@
         }
 
         kms = new KeyManager[] { new MyX509ExtendedKeyManager(
-                (X509ExtendedKeyManager) kms[0], expectedAP) };
+                (X509ExtendedKeyManager) kms[0], expectedAP,
+                !hasCallback && hasServerAPs) };
 
         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
         tmf.init(trustKS);
@@ -338,12 +408,15 @@
      * Convert a comma-separated list into an array of strings.
      */
     private static String[] convert(String list) {
-        String[] strings;
+        if (list.equals("UNUSED")) {
+            return null;
+        }
 
         if (list.equals("EMPTY")) {
             return new String[0];
         }
 
+        String[] strings;
         if (list.indexOf(',') > 0) {
             strings = list.split(",");
         } else {
--- a/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -26,22 +26,60 @@
 
 /*
  * @test
- * @bug 8051498 8145849
+ * @bug 8051498 8145849 8170282
  * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
  * @compile MyX509ExtendedKeyManager.java
- * @run main/othervm SSLSocketAlpnTest h2          h2          h2
- * @run main/othervm SSLSocketAlpnTest h2          h2,http/1.1 h2
- * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2,http/1.1 h2
- * @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2,http/1.1 http/1.1
- * @run main/othervm SSLSocketAlpnTest h4,h3,h2    h1,h2       h2
- * @run main/othervm SSLSocketAlpnTest EMPTY       h2,http/1.1 NONE
- * @run main/othervm SSLSocketAlpnTest h2          EMPTY       NONE
- * @run main/othervm SSLSocketAlpnTest H2          h2          ERROR
- * @run main/othervm SSLSocketAlpnTest h2          http/1.1    ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest h2          UNUSED   h2          h2
+ * @run main/othervm SSLSocketAlpnTest h2          UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest http/1.1,h2 UNUSED   h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest h4,h3,h2    UNUSED   h1,h2       h2
+ * @run main/othervm SSLSocketAlpnTest EMPTY       UNUSED   h2,http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest h2          UNUSED   EMPTY       NONE
+ * @run main/othervm SSLSocketAlpnTest H2          UNUSED   h2          ERROR
+ * @run main/othervm SSLSocketAlpnTest h2          UNUSED   http/1.1    ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       h2          h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       http/1.1,h2 h2
+ * @run main/othervm SSLSocketAlpnTest UNUSED      http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest UNUSED      EMPTY    h2,http/1.1 NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       EMPTY       NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED      H2       h2          ERROR
+ * @run main/othervm SSLSocketAlpnTest UNUSED      h2       http/1.1    ERROR
+ *
+ * @run main/othervm SSLSocketAlpnTest h2          h2       h2          h2
+ * @run main/othervm SSLSocketAlpnTest H2          h2       h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2       h2,http/1.1 h2
+ * @run main/othervm SSLSocketAlpnTest EMPTY       h2       h2          h2
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 EMPTY    http/1.1    NONE
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2       EMPTY       NONE
+ * @run main/othervm SSLSocketAlpnTest UNUSED      UNUSED   http/1.1,h2 NONE
+ * @run main/othervm SSLSocketAlpnTest h2          h2       http/1.1    ERROR
+ * @run main/othervm SSLSocketAlpnTest h2,http/1.1 H2       http/1.1    ERROR
+ *
  * @author Brad Wetmore
  */
+/**
+ * A simple SSLSocket-based client/server that demonstrates the proposed API
+ * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
+ *
+ * Usage:
+ *     java SSLSocketAlpnTest <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ *      EMPTY  indicates that ALPN is disabled
+ *      UNUSED indicates that no ALPN values are supplied (server-side only)
+ *      ERROR  indicates that an exception is expected
+ *      NONE   indicates that no ALPN is expected
+ *
+ * This example is based on our standard SSLSocketTemplate.
+ */
 import java.io.*;
 import java.security.KeyStore;
+import java.util.Arrays;
 
 import javax.net.ssl.*;
 
@@ -73,6 +111,9 @@
     static String trustFilename = System.getProperty("test.src", ".") + "/"
             + pathToStores + "/" + trustStoreFile;
 
+    private static boolean hasServerAPs; // whether server APs are present
+    private static boolean hasCallback; // whether a callback is present
+
     /*
      * SSLContext
      */
@@ -89,6 +130,7 @@
     static boolean debug = false;
 
     static String[] serverAPs;
+    static String callbackAP;
     static String[] clientAPs;
     static String expectedAP;
 
@@ -136,7 +178,9 @@
         sslp.setUseCipherSuitesOrder(true); // Set server side order
 
         // Set the ALPN selection.
-        sslp.setApplicationProtocols(serverAPs);
+        if (serverAPs != null) {
+            sslp.setApplicationProtocols(serverAPs);
+        }
         sslSocket.setSSLParameters(sslp);
 
         if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -144,6 +188,24 @@
                     + "return null before the handshake starts");
         }
 
+        // check that no callback has been registered
+        if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {
+            throw new Exception("getHandshakeApplicationProtocolSelector() " +
+                "should return null");
+        }
+
+        if (hasCallback) {
+            sslSocket.setHandshakeApplicationProtocolSelector(
+                (serverSocket, clientProtocols) -> {
+                    return callbackAP.equals("EMPTY") ? "" : callbackAP;
+                });
+
+            // check that the callback can be retrieved
+            if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {
+                throw new Exception("getHandshakeApplicationProtocolSelector()"                     + " should return non-null");
+            }
+        }
+
         sslSocket.startHandshake();
 
         if (sslSocket.getHandshakeApplicationProtocol() != null) {
@@ -274,14 +336,19 @@
         if (debug) {
             System.setProperty("javax.net.debug", "all");
         }
+        System.out.println("Test args: " + Arrays.toString(args));
 
         // Validate parameters
-        if (args.length != 3) {
+        if (args.length != 4) {
             throw new Exception("Invalid number of test parameters");
         }
         serverAPs = convert(args[0]);
-        clientAPs = convert(args[1]);
-        expectedAP = args[2];
+        callbackAP = args[1];
+        clientAPs = convert(args[2]);
+        expectedAP = args[3];
+
+        hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+        hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?
 
         /*
          * Start the tests.
@@ -289,7 +356,7 @@
         try {
             new SSLSocketAlpnTest();
         } catch (SSLHandshakeException she) {
-            if (args[2].equals("ERROR")) {
+            if (args[3].equals("ERROR")) {
                 System.out.println("Caught the expected exception: " + she);
             } else {
                 throw she;
@@ -320,7 +387,8 @@
         }
 
         kms = new KeyManager[] { new MyX509ExtendedKeyManager(
-                (X509ExtendedKeyManager) kms[0], expectedAP) };
+                (X509ExtendedKeyManager) kms[0], expectedAP,
+                !hasCallback && hasServerAPs) };
 
         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
         tmf.init(trustKS);
@@ -336,12 +404,15 @@
      * Convert a comma-separated list into an array of strings.
      */
     private static String[] convert(String list) {
-        String[] strings;
+        if (list.equals("UNUSED")) {
+            return null;
+        }
 
         if (list.equals("EMPTY")) {
             return new String[0];
         }
 
+        String[] strings;
         if (list.indexOf(',') > 0) {
             strings = list.split(",");
         } else {
--- a/jdk/test/javax/print/PrintServiceLookup/GetPrintServices.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/print/PrintServiceLookup/GetPrintServices.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -29,30 +29,37 @@
 
 /*
  * @test
- * @bug 8013810
- * @summary Test that print service returned without filter are of the same class as with name filter
+ * @bug 8013810 8025439
+ * @summary Test that print service returned without filter are of the same class
+ *          as with name filter
  */
 public class GetPrintServices {
 
-  public static void main(String[] args) throws Exception {
-    for (PrintService service : PrintServiceLookup.lookupPrintServices(null, null)) {
-      String serviceName = service.getName();
-      PrintService serviceByName = lookupByName(serviceName);
-      if (!service.equals(serviceByName)) {
-        throw new RuntimeException("NOK " + serviceName
+    public static void main(String[] args) throws Exception {
+        for (PrintService service : PrintServiceLookup.lookupPrintServices(null, null)) {
+            String serviceName = service.getName();
+            PrinterName name = service.getAttribute(PrinterName.class);
+            String printerName = name.getValue();
+
+            PrintService serviceByName = lookupByName(printerName);
+            System.out.println("service " + service);
+            System.out.println("serviceByName " + serviceByName);
+            if (!service.equals(serviceByName)) {
+                throw new RuntimeException("NOK " + serviceName
                                    + " expected: " + service.getClass().getName()
                                    + " got: " + serviceByName.getClass().getName());
-      }
+            }
+        }
+        System.out.println("Test PASSED");
     }
-    System.out.println("Test PASSED");
-  }
 
-  private static PrintService lookupByName(String name) {
-    AttributeSet attributes = new HashAttributeSet();
-    attributes.add(new PrinterName(name, null));
-    for (PrintService service : PrintServiceLookup.lookupPrintServices(null, attributes)) {
-      return service;
+    private static PrintService lookupByName(String name) {
+        AttributeSet attributes = new HashAttributeSet();
+        attributes.add(new PrinterName(name, null));
+        for (PrintService service :
+             PrintServiceLookup.lookupPrintServices(null, attributes)) {
+            return service;
+        }
+        return null;
     }
-    return null;
-  }
 }
--- a/jdk/test/javax/swing/JComboBox/8041909/ActionListenerExceptionTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/JComboBox/8041909/ActionListenerExceptionTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -26,7 +26,7 @@
   * @summary Test to check JComboBox does not lose its ability to invoke
   * registerd ActionListener in case of exception in ActionListener
   * @run main ActionListenerExceptionTest
-  */
+ */
 
 import java.awt.AWTEvent;
 import java.awt.AWTException;
@@ -44,6 +44,7 @@
 import javax.swing.JComponent;
 import javax.swing.JFrame;
 import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
 import javax.swing.SwingUtilities;
 
 public class ActionListenerExceptionTest {
@@ -133,7 +134,11 @@
         SwingUtilities.invokeAndWait(new Runnable() {
             public void run() {
                 Object comp = combo.getUI().getAccessibleChild(combo, 0);
-                JComponent scrollPane = (JComponent) ((JPopupMenu) comp).getComponent(0);
+                int i = 0;
+                JComponent scrollPane;
+                do {
+                    scrollPane = (JComponent) ((JPopupMenu) comp).getComponent(i++);
+                } while (!(scrollPane instanceof JScrollPane));
 
                 menuItemHeight = scrollPane.getSize().height / TOTAL_MENU_ITEMS;
                 yPos = scrollPane.getLocationOnScreen().y + menuItemHeight / 2;
--- a/jdk/test/javax/swing/JDialog/Transparency/TransparencyTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/JDialog/Transparency/TransparencyTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -24,10 +24,12 @@
  /*
  @test
  @key headful
- @bug 8062946
+ @bug 8062946 8159906
  @summary Verify Transparency upon iconify/deiconify sequence
  @run main TransparencyTest
  */
+import java.awt.GraphicsEnvironment;
+import java.awt.GraphicsDevice;
 import java.awt.Color;
 import java.awt.Point;
 import java.awt.Robot;
@@ -43,7 +45,7 @@
     private static final int WIDTH = 250;
     private static final int HEIGHT = 250;
     private static final float OPACITY = 0.60f;
-    private static Point dlgPos;
+    private static volatile Point dlgPos;
 
     public static void createAndShowGUI() {
         frame = new JFrame("JFrame");
@@ -67,6 +69,14 @@
 
     public static void main(String[] args) throws Exception {
 
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        GraphicsDevice gd = ge.getDefaultScreenDevice();
+        GraphicsDevice.WindowTranslucency mode = GraphicsDevice.WindowTranslucency.TRANSLUCENT;
+        boolean translucencyCheck = gd.isWindowTranslucencySupported(mode);
+        if(!translucencyCheck) {
+            return;
+    }
+
         Robot robot = new Robot();
         // create a GUI
         SwingUtilities.invokeAndWait(new Runnable() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JLightweightFrame/JLightweightFrameRoundTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8170387
+ * @summary JLightweightFrame#syncCopyBuffer() may throw IOOBE
+ * @modules java.desktop/sun.swing
+ * @run main JLightweightFrameRoundTest
+ */
+
+import sun.swing.JLightweightFrame;
+import sun.swing.LightweightContent;
+
+import javax.swing.*;
+
+public class JLightweightFrameRoundTest {
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(() -> {
+            JLightweightFrame jLightweightFrame = new JLightweightFrame();
+            jLightweightFrame.setContent(new XLightweightContent());
+            jLightweightFrame.setSize(600, 600);
+            jLightweightFrame.notifyDisplayChanged(1.0001, 1.0001);
+        });
+    }
+
+    static class XLightweightContent implements LightweightContent {
+        @Override
+        public JComponent getComponent() {
+            return new JPanel();
+        }
+
+        @Override
+        public void paintLock() {}
+
+        @Override
+        public void paintUnlock() {}
+
+        @Override
+        public void imageBufferReset(int[] data, int x, int y, int width,
+                                     int height, int linestride,
+                                     double scaleX,
+                                     double scaleY) {}
+
+        @Override
+        public void imageReshaped(int x, int y, int width, int height) {}
+
+        @Override
+        public void imageUpdated(int dirtyX, int dirtyY, int dirtyWidth,
+                                 int dirtyHeight) {}
+
+        @Override
+        public void focusGrabbed() {}
+
+        @Override
+        public void focusUngrabbed() {}
+
+        @Override
+        public void preferredSizeChanged(int width, int height) {}
+
+        @Override
+        public void maximumSizeChanged(int width, int height) {}
+
+        @Override
+        public void minimumSizeChanged(int width, int height) {}
+    }
+}
--- a/jdk/test/javax/swing/JRadioButton/8033699/bug8033699.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/JRadioButton/8033699/bug8033699.java	Mon Dec 19 16:05:38 2016 +0000
@@ -26,22 +26,31 @@
  * @key headful
  * @library ../../regtesthelpers
  * @build Util
- * @bug 8033699 8154043
+ * @bug 8033699 8154043 8167160
  * @summary  Incorrect radio button behavior when pressing tab key
- * @author Vivi An
  * @run main bug8033699
  */
-
-import javax.swing.*;
-import javax.swing.event.*;
-import java.awt.event.*;
-import java.awt.*;
+import java.awt.KeyboardFocusManager;
+import java.awt.Robot;
+import java.awt.event.KeyEvent;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
 
 public class bug8033699 {
+
+    private static JFrame mainFrame;
     private static Robot robot;
-
     private static JButton btnStart;
-    private static ButtonGroup btnGrp;
     private static JButton btnEnd;
     private static JButton btnMiddle;
     private static JRadioButton radioBtn1;
@@ -51,7 +60,9 @@
 
     public static void main(String args[]) throws Throwable {
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
+                changeLAF();
                 createAndShowGUI();
             }
         });
@@ -84,11 +95,30 @@
 
         // down key circle back to first button in grouped radio button
         runTest8();
+
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                mainFrame.dispose();
+            }
+        });
+    }
+
+    private static void changeLAF() {
+        String currentLAF = UIManager.getLookAndFeel().toString();
+        System.out.println(currentLAF);
+        currentLAF = currentLAF.toLowerCase();
+        if (currentLAF.contains("aqua") || currentLAF.contains("nimbus")) {
+            try {
+                UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+        }
     }
 
     private static void createAndShowGUI() {
-        JFrame mainFrame = new JFrame("Bug 8033699 - 8 Tests for Grouped/Non Group Radio Buttons");
-
+        mainFrame = new JFrame("Bug 8033699 - 8 Tests for Grouped/Non Group Radio Buttons");
         btnStart = new JButton("Start");
         btnEnd = new JButton("End");
         btnMiddle = new JButton("Middle");
@@ -132,12 +162,13 @@
     }
 
     // Radio button Group as a single component when traversing through tab key
-    private static void runTest1() throws Exception{
+    private static void runTest1() throws Exception {
         hitKey(robot, KeyEvent.VK_TAB);
         hitKey(robot, KeyEvent.VK_TAB);
         hitKey(robot, KeyEvent.VK_TAB);
 
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) {
                     System.out.println("Radio Button Group Go To Next Component through Tab Key failed");
@@ -148,9 +179,10 @@
     }
 
     // Non-Grouped Radio button as a single component when traversing through tab key
-    private static void runTest2() throws Exception{
+    private static void runTest2() throws Exception {
         hitKey(robot, KeyEvent.VK_TAB);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnEnd) {
                     System.out.println("Non Grouped Radio Button Go To Next Component through Tab Key failed");
@@ -161,11 +193,12 @@
     }
 
     // Non-Grouped Radio button and Group Radio button as a single component when traversing through shift-tab key
-    private static void runTest3() throws Exception{
+    private static void runTest3() throws Exception {
         hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
         hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
         hitKey(robot, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) {
                     System.out.println("Radio button Group/Non Grouped Radio Button SHIFT-Tab Key Test failed");
@@ -176,10 +209,11 @@
     }
 
     // Using arrow key to move focus in radio button group
-    private static void runTest4() throws Exception{
+    private static void runTest4() throws Exception {
         hitKey(robot, KeyEvent.VK_DOWN);
         hitKey(robot, KeyEvent.VK_RIGHT);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn3) {
                     System.out.println("Radio button Group UP/LEFT Arrow Key Move Focus Failed");
@@ -189,10 +223,11 @@
         });
     }
 
-    private static void runTest5() throws Exception{
+    private static void runTest5() throws Exception {
         hitKey(robot, KeyEvent.VK_UP);
         hitKey(robot, KeyEvent.VK_LEFT);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn1) {
                     System.out.println("Radio button Group Left/Up Arrow Key Move Focus Failed");
@@ -202,10 +237,11 @@
         });
     }
 
-    private static void runTest6() throws Exception{
+    private static void runTest6() throws Exception {
         hitKey(robot, KeyEvent.VK_UP);
         hitKey(robot, KeyEvent.VK_UP);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtn2) {
                     System.out.println("Radio button Group Circle Back To First Button Test");
@@ -215,9 +251,10 @@
         });
     }
 
-    private static void runTest7() throws Exception{
+    private static void runTest7() throws Exception {
         hitKey(robot, KeyEvent.VK_TAB);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != btnMiddle) {
                     System.out.println("Separate Component added in button group layout");
@@ -227,9 +264,10 @@
         });
     }
 
-    private static void runTest8() throws Exception{
+    private static void runTest8() throws Exception {
         hitKey(robot, KeyEvent.VK_TAB);
         SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
             public void run() {
                 if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() != radioBtnSingle) {
                     System.out.println("Separate Component added in button group layout");
--- a/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/JRadioButton/FocusTraversal/FocusTraversal.java	Mon Dec 19 16:05:38 2016 +0000
@@ -42,7 +42,6 @@
 import javax.swing.JRadioButton;
 import javax.swing.JTextField;
 import javax.swing.KeyStroke;
-import javax.swing.LookAndFeel;
 import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.UnsupportedLookAndFeelException;
@@ -133,43 +132,21 @@
     }
 
     private static void runTestCase() throws Exception {
-        LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
         focusOn(a);
-        if (isExcludedLookAndFeel(lookAndFeel)) {
-            robot.keyPress(KeyEvent.VK_ENTER);
-            robot.keyRelease(KeyEvent.VK_ENTER);
-            robot.waitForIdle();
-            isFocusOwner(b, "forward");
-            robot.keyPress(KeyEvent.VK_SHIFT);
-            robot.keyPress(KeyEvent.VK_TAB);
-            robot.keyRelease(KeyEvent.VK_TAB);
-            robot.keyRelease(KeyEvent.VK_SHIFT);
-            robot.waitForIdle();
-            isFocusOwner(a, "backward");
-
-        } else {
 
-            robot.keyPress(KeyEvent.VK_ENTER);
-            robot.keyRelease(KeyEvent.VK_ENTER);
-            robot.waitForIdle();
-            isFocusOwner(next, "forward");
-            robot.keyPress(KeyEvent.VK_SHIFT);
-            robot.keyPress(KeyEvent.VK_TAB);
-            robot.keyRelease(KeyEvent.VK_TAB);
-            robot.keyRelease(KeyEvent.VK_SHIFT);
-            robot.waitForIdle();
-            isFocusOwner(d, "backward");
-        }
+        robot.keyPress(KeyEvent.VK_ENTER);
+        robot.keyRelease(KeyEvent.VK_ENTER);
+        robot.waitForIdle();
+        isFocusOwner(next, "forward");
+        robot.keyPress(KeyEvent.VK_SHIFT);
+        robot.keyPress(KeyEvent.VK_TAB);
+        robot.keyRelease(KeyEvent.VK_TAB);
+        robot.keyRelease(KeyEvent.VK_SHIFT);
+        robot.waitForIdle();
+        isFocusOwner(a, "backward");
 
     }
 
-    private static boolean isExcludedLookAndFeel(LookAndFeel lookAndFeel) {
-
-        return lookAndFeel.toString().toLowerCase().contains("aqua")
-                || lookAndFeel.toString().toLowerCase().contains("nimbus")
-                || lookAndFeel.toString().toLowerCase().contains("gtk");
-    }
-
     private static void focusOn(Component component)
             throws Exception {
         SwingUtilities.invokeAndWait(new Runnable() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JTable/SorterIOOBEtest/DefaultRowSorterIOOBEtest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8160087
+ * @summary Change IOOBE to warning in the scenarios when it had not being
+ *          thrown before the JDK-8078514
+ * @run main/othervm DefaultRowSorterIOOBEtest
+ */
+
+import javax.swing.*;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DefaultRowSorterIOOBEtest extends TableRowSorter<TableModel> {
+    static List<String> rows = new ArrayList<>();
+
+    static TableModel tableModel = new AbstractTableModel() {
+
+        @Override
+        public int getRowCount() {
+            return rows.size();
+        }
+
+        @Override
+        public int getColumnCount() {
+            return 1;
+        }
+
+        @Override
+        public Object getValueAt(int rowIndex, int columnIndex) {
+            return rows.get(rowIndex);
+        }
+    };
+
+    public static void main(String[] args) {
+        DefaultRowSorter<TableModel, Integer> sorter =
+            new DefaultRowSorter<>() {
+            {
+                setModelWrapper(new SorterModelWrapper());
+            }
+        };
+
+        PrintStream err = System.err;
+        ByteArrayOutputStream bos = new ByteArrayOutputStream(10000) {
+            @Override
+            public synchronized void write(byte[] b, int off, int len) {
+                super.write(b, off, len);
+                err.print(new String(b, off, len));
+            }
+        };
+        System.setErr(new PrintStream(bos));
+
+        rows.add("New");
+
+        sorter.convertRowIndexToView(0);
+        sorter.convertRowIndexToModel(0);
+
+        String out = new String(bos.toByteArray());
+        if(out.indexOf("WARNING:") < 0) {
+            throw new RuntimeException("No warnings found");
+        }
+    }
+
+    static class SorterModelWrapper extends
+                            DefaultRowSorter.ModelWrapper<TableModel, Integer> {
+
+        @Override
+        public TableModel getModel() {
+            return tableModel;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return tableModel.getColumnCount();
+        }
+
+        @Override
+        public int getRowCount() {
+            return tableModel.getRowCount();
+        }
+
+        @Override
+        public Object getValueAt(int row, int column) {
+            return tableModel.getValueAt(row, column);
+        }
+
+        @Override
+        public Integer getIdentifier(int row) {
+            return row;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/RepaintManager/8162350/RepaintManagerFPUIScaleTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BaseMultiResolutionImage;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+/*
+ * @test
+ * @bug 8162350
+ * @summary RepaintManager shifts repainted region when the floating point UI scale is used
+ * @run main/manual/othervm -Dsun.java2d.uiScale=1.5 RepaintManagerFPUIScaleTest
+ */
+public class RepaintManagerFPUIScaleTest {
+
+    private static volatile boolean testResult = false;
+    private static volatile CountDownLatch countDownLatch;
+    private static final String INSTRUCTIONS = "INSTRUCTIONS:\n"
+            + "Check JScrollPane correctly repaints the view"
+            + " when UI scale has floating point value:\n"
+            + "\n"
+            + "1. Scroll down the JScrollPane\n"
+            + "2. Select some values\n"
+            + "If the scrolled selected value is painted without artifacts,"
+            + "press PASS, else press FAIL.";
+
+    public static void main(String args[]) throws Exception {
+
+        countDownLatch = new CountDownLatch(1);
+
+        SwingUtilities.invokeLater(RepaintManagerFPUIScaleTest::createUI);
+        countDownLatch.await(15, TimeUnit.MINUTES);
+
+        if (!testResult) {
+            throw new RuntimeException("Test fails!");
+        }
+    }
+
+    private static void createUI() {
+
+        final JFrame mainFrame = new JFrame("Motif L&F icons test");
+        GridBagLayout layout = new GridBagLayout();
+        JPanel mainControlPanel = new JPanel(layout);
+        JPanel resultButtonPanel = new JPanel(layout);
+
+        GridBagConstraints gbc = new GridBagConstraints();
+
+        JComponent testPanel = createComponent();
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        mainControlPanel.add(testPanel, gbc);
+
+        JTextArea instructionTextArea = new JTextArea();
+        instructionTextArea.setText(INSTRUCTIONS);
+        instructionTextArea.setEditable(false);
+        instructionTextArea.setBackground(Color.white);
+
+        gbc.gridx = 0;
+        gbc.gridy = 1;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        mainControlPanel.add(instructionTextArea, gbc);
+
+        JButton passButton = new JButton("Pass");
+        passButton.setActionCommand("Pass");
+        passButton.addActionListener((ActionEvent e) -> {
+            testResult = true;
+            mainFrame.dispose();
+            countDownLatch.countDown();
+
+        });
+
+        JButton failButton = new JButton("Fail");
+        failButton.setActionCommand("Fail");
+        failButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                mainFrame.dispose();
+                countDownLatch.countDown();
+            }
+        });
+
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        resultButtonPanel.add(passButton, gbc);
+
+        gbc.gridx = 1;
+        gbc.gridy = 0;
+        resultButtonPanel.add(failButton, gbc);
+
+        gbc.gridx = 0;
+        gbc.gridy = 2;
+        mainControlPanel.add(resultButtonPanel, gbc);
+
+        mainFrame.add(mainControlPanel);
+        mainFrame.pack();
+
+        mainFrame.addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                mainFrame.dispose();
+                countDownLatch.countDown();
+            }
+        });
+        mainFrame.setVisible(true);
+    }
+
+    private static JComponent createComponent() {
+
+        int N = 100;
+        String[] data = new String[N];
+        for (int i = 0; i < N; i++) {
+            data[i] = "Floating point test List Item: " + i;
+        }
+        JList list = new JList(data);
+        list.setCellRenderer(new TestListCellRenderer());
+
+        JScrollPane scrollPane = new JScrollPane(list);
+        return scrollPane;
+    }
+
+    private static Color[] COLORS = {
+        Color.RED, Color.ORANGE, Color.GREEN, Color.BLUE, Color.GRAY
+    };
+
+    private static Image createTestImage(int width, int height, int colorindex) {
+
+        Color color = COLORS[colorindex % COLORS.length];
+
+        AffineTransform tx = GraphicsEnvironment
+                .getLocalGraphicsEnvironment()
+                .getDefaultScreenDevice()
+                .getDefaultConfiguration()
+                .getDefaultTransform();
+
+        Image baseImage = createTestImage(width, height, 1, 1, color);
+        Image rvImage = createTestImage(width, height, tx.getScaleX(), tx.getScaleY(), color);
+
+        return new BaseMultiResolutionImage(baseImage, rvImage);
+    }
+
+    private static Image createTestImage(int w, int h,
+            double scaleX, double scaleY, Color color) {
+
+        int width = (int) Math.ceil(scaleX * w);
+        int height = (int) Math.ceil(scaleY * h);
+        BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+
+        Graphics2D g = img.createGraphics();
+        g.setColor(Color.WHITE);
+        g.fillRect(0, 0, width, height);
+        g.scale(scaleX, scaleY);
+        g.setColor(color);
+        int d = 1;
+        int d2 = 2 * d;
+        g.drawLine(d, h / 2, w - d2, h / 2);
+        g.drawLine(w / 2, d, w / 2, h - d2);
+        g.drawRect(d, d, w - d2, h - d2);
+        g.dispose();
+
+        return img;
+    }
+
+    static class TestListCellRenderer extends DefaultListCellRenderer {
+
+        public Component getListCellRendererComponent(
+                JList list,
+                Object value,
+                int index,
+                boolean isSelected,
+                boolean cellHasFocus) {
+            Component retValue = super.getListCellRendererComponent(
+                    list, value, index, isSelected, cellHasFocus
+            );
+            setIcon(new ImageIcon(createTestImage(20, 10, index)));
+            return retValue;
+        }
+    }
+}
--- a/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/plaf/basic/BasicScrollPaneUI/8166591/TooMuchWheelRotationEventsTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -44,20 +44,20 @@
  * @key headful
  * @summary [macos 10.12] Trackpad scrolling of text on OS X 10.12 Sierra
  *    is very fast (Trackpad, Retina only)
+ * @requires (os.family == "windows" | os.family == "mac")
  * @run main/manual/othervm TooMuchWheelRotationEventsTest
  */
 public class TooMuchWheelRotationEventsTest {
 
     private static volatile boolean testResult = false;
     private static volatile CountDownLatch countDownLatch;
-    private static final String INSTRUCTIONS = "INSTRUCTIONS:\n"
-            + "Try to check the issue on Mac OS X 10.12 Sierra with trackpad"
-            + " on Retina display.\n"
+    private static final String INSTRUCTIONS = " INSTRUCTIONS:\n"
+            + " Try to check the issue with trackpad\n"
             + "\n"
-            + "If the trackpad is not supported, press PASS\n"
+            + " If the trackpad is not supported, press PASS\n"
             + "\n"
-            + "Use the trackpad to slightly scroll the JTextArea horizontally and vertically.\n"
-            + "If the text area is scrolled too fast press FAIL, else press PASS.";
+            + " Use the trackpad to slightly scroll the JTextArea horizontally and vertically.\n"
+            + " If the text area is scrolled too fast press FAIL, else press PASS.";
 
     public static void main(String args[]) throws Exception {
         countDownLatch = new CountDownLatch(1);
@@ -138,6 +138,7 @@
                 countDownLatch.countDown();
             }
         });
+        mainFrame.setLocationRelativeTo(null);
         mainFrame.setVisible(true);
     }
 
--- a/jdk/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/javax/swing/text/GlyphPainter2/6427244/bug6427244.java	Mon Dec 19 16:05:38 2016 +0000
@@ -23,7 +23,7 @@
  */
 
 /* @test
-   @bug 6427244 8144240 8166003
+   @bug 6427244 8144240 8166003 8169879
    @summary Test that pressing HOME correctly moves caret in I18N document.
    @author Sergey Groznyh
    @library ../../../regtesthelpers
@@ -69,10 +69,12 @@
         bug6427244 t = new bug6427244();
         for (String space: SPACES) {
             t.init(space);
-            t.runAllTests();
+            t.testCaretPosition();
         }
 
         System.out.println("OK");
+        // Dispose the test interface upon completion
+        t.destroyTestInterface();
     }
 
     void init(final String space) {
@@ -113,29 +115,65 @@
         }
     }
 
-    void blockTillDisplayed(JComponent comp) {
-        if(comp != null) {
-            while (!comp.isVisible()) {
-                try {
+    void destroyTestInterface() {
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    // Dispose the frame
+                    jf.dispose();
+                 }
+            });
+        } catch (Exception ex) {
+            // No-op
+        }
+    }
+
+    void blockTillDisplayed(JComponent comp) throws Exception {
+        while (comp != null && isCompVisible == false) {
+            try {
+                SwingUtilities.invokeAndWait(new Runnable() {
+                    @Override
+                    public void run() {
+                        isCompVisible = comp.isVisible();
+                     }
+                });
+
+                if (isCompVisible == false) {
+                    // A short wait for component to be visible
                     Thread.sleep(1000);
-                } catch (InterruptedException ie) {
-                    /* No-op */
                 }
+            } catch (InterruptedException ex) {
+                // No-op. Thread resumed from sleep
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
             }
         }
     }
 
     public void testCaretPosition() {
-        Point p = tp.getLocationOnScreen();
-        // the right-top corner position
-        p.x += (dim.width - 5);
-        p.y += 5;
-        ROBOT.mouseMove(p.x, p.y);
+        final Point p[] = new Point[1];
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                public void run() {
+                    p[0] = tp.getLocationOnScreen();
+
+                    // the right-top corner position
+                    p[0].x += (dim.width - 5);
+                    p[0].y += 5;
+                }
+            });
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+        ROBOT.mouseMove(p[0].x, p[0].y);
         ROBOT.clickMouse();
         ROBOT.hitKey(KeyEvent.VK_HOME);
         ROBOT.waitForIdle();
         // this will fail if caret moves out of the 1st line.
         if (getCaretOrdinate() != 0) {
+            // Dispose the test interface upon completion
+            destroyTestInterface();
             throw new RuntimeException("Test Failed.");
         }
     }
@@ -162,7 +200,8 @@
         return y[0];
     }
 
-    JFrame jf;
-    JTextPane tp;
-    Dimension dim;
+    private JFrame jf;
+    private JTextPane tp;
+    private Dimension dim;
+    private volatile boolean isCompVisible = false;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/html/StyleSheet/bug4936917.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+/* @test
+   @bug 4936917 7190578
+   @summary  Tests if background is correctly painted when <BODY> has css margins
+   @author Denis Sharypov
+   @library ../../../regtesthelpers
+   @run main bug4936917
+*/
+
+
+
+import java.awt.Color;
+import java.awt.Point;
+import java.awt.Robot;
+import java.util.Timer;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JFrame;
+import javax.swing.SwingUtilities;
+
+
+public class bug4936917 {
+
+    private boolean passed = false;
+    private Timer timer;
+    private JEditorPane editorPane;
+    private static JFrame f;
+    private volatile Point p = null;
+
+    private String text =
+                "<html><head><style>" +
+                "body {background-color: #cccccc; margin-top: 36.000000pt;}" +
+                "</style></head>" +
+                "<body> some text </body></html>";
+
+    public void init() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                editorPane = new JEditorPane("text/html", "");
+                editorPane.setEditable(false);
+                editorPane.setMargin(new java.awt.Insets(0, 0, 0, 0));
+                editorPane.setText(text);
+
+                f = new JFrame();
+                f.getContentPane().add(editorPane);
+                f.setSize(600, 400);
+                f.setVisible(true);
+            }
+        });
+        blockTillDisplayed(editorPane);
+        Robot robot  = new Robot();
+        robot.waitForIdle();
+
+        int x0 = p.x + 15 ;
+        int y = p.y + 15;
+        int match = 0;
+        int nonmatch = 0;
+
+        passed = true;
+        for (int x = x0; x < x0 + 10; x++) {
+            System.out.println("color ("+x+"," + y +")=" + robot.getPixelColor(x,y));
+            if (!robot.getPixelColor(x, y).equals(new Color(0xcc, 0xcc, 0xcc))) {
+                nonmatch++;
+            } else match++;
+        }
+        if (nonmatch > match) {
+            passed = false;
+        }
+    }
+
+    void blockTillDisplayed(JComponent comp) throws Exception {
+        while (p == null) {
+            try {
+                SwingUtilities.invokeAndWait(() -> {
+                    p = comp.getLocationOnScreen();
+                });
+            } catch (IllegalStateException e) {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException ie) {
+                }
+            }
+        }
+    }
+
+    public void destroy() throws Exception {
+        SwingUtilities.invokeAndWait(()->f.dispose());
+        if(!passed) {
+            throw new RuntimeException("Test failed.");
+        }
+    }
+
+
+    public static void main(String args[]) throws Exception {
+            bug4936917 test = new bug4936917();
+            test.init();
+            test.destroy();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/DefaultImage.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8170859
+ * @summary Ensure no incubator modules are resolved by default in the image
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build CompilerUtils
+ * @run testng DefaultImage
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static jdk.testlibrary.ProcessTools.executeCommand;
+import static org.testng.Assert.*;
+
+public class DefaultImage {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+    private static final Path TEST_SRC = Paths.get(System.getProperty("test.src"));
+    private static final Path CP_DIR = Paths.get("cp");
+
+    @BeforeTest
+    private void setup() throws Throwable {
+        Path src = TEST_SRC.resolve("src").resolve("cp").resolve("listmods");
+        assertTrue(CompilerUtils.compile(src, CP_DIR));
+    }
+
+    public void test() throws Throwable {
+        if (isExplodedBuild()) {
+            System.out.println("Test cannot run on exploded build");
+            return;
+        }
+
+        java("-cp", CP_DIR.toString(),
+             "listmods.ListModules")
+            .assertSuccess()
+            .resultChecker(r -> r.assertOutputContains("java.base"))
+            .resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator"));
+    }
+
+    @DataProvider(name = "tokens")
+    public Object[][] singleModuleValues() throws IOException {
+        return new Object[][]{ { "ALL-DEFAULT" }, { "ALL-SYSTEM"} };
+    }
+
+    @Test(dataProvider = "tokens")
+    public void testAddMods(String addModsToken) throws Throwable {
+        if (isExplodedBuild()) {
+            System.out.println("Test cannot run on exploded build");
+            return;
+        }
+
+        java("--add-modules", addModsToken,
+             "-cp", CP_DIR.toString(),
+             "listmods.ListModules")
+            .assertSuccess()
+            .resultChecker(r -> r.assertOutputContains("java.base"))
+            .resultChecker(r -> r.assertOutputDoesNotContain("jdk.incubator"));
+    }
+
+    static ToolResult java(String... opts) throws Throwable {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        String[] options = Stream.concat(Stream.of(getJava()), Stream.of(opts))
+                .toArray(String[]::new);
+
+        ProcessBuilder pb = new ProcessBuilder(options);
+        int exitValue = executeCommand(pb).outputTo(ps)
+                .errorTo(ps)
+                .getExitValue();
+
+        return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8));
+    }
+
+    static class ToolResult {
+        final int exitCode;
+        final String output;
+
+        ToolResult(int exitValue, String output) {
+            this.exitCode = exitValue;
+            this.output = output;
+        }
+
+        ToolResult assertSuccess() {
+            assertEquals(exitCode, 0,
+                    "Expected exit code 0, got " + exitCode
+                            + ", with output[" + output + "]");
+            return this;
+        }
+
+        ToolResult resultChecker(Consumer<ToolResult> r) {
+            r.accept(this);
+            return this;
+        }
+
+        ToolResult assertOutputContains(String subString) {
+            assertTrue(output.contains(subString),
+                       "Expected to find [" + subString + "], in output ["
+                            + output + "]" + "\n");
+            return this;
+        }
+
+        ToolResult assertOutputDoesNotContain(String subString) {
+            assertFalse(output.contains(subString),
+                        "Expected to NOT find [" + subString + "], in output ["
+                            + output + "]" + "\n");
+            return this;
+        }
+    }
+
+    static String getJava() {
+        Path image = Paths.get(JAVA_HOME);
+        boolean isWindows = System.getProperty("os.name").startsWith("Windows");
+        Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java");
+        if (Files.notExists(java))
+            throw new RuntimeException(java + " not found");
+        return java.toAbsolutePath().toString();
+    }
+
+    static boolean isExplodedBuild() {
+        Path modulesPath = Paths.get(JAVA_HOME).resolve("lib").resolve("modules");
+        return Files.notExists(modulesPath);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/ImageModules.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,382 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8170859
+ * @summary Basic test for incubator modules in jmods and images
+ * @library /lib/testlibrary
+ * @modules jdk.compiler jdk.jartool jdk.jlink
+ * @build CompilerUtils
+ * @run testng/othervm ImageModules
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.spi.ToolProvider;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.FileUtils;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static jdk.testlibrary.ProcessTools.executeCommand;
+import static org.testng.Assert.*;
+
+public class ImageModules {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+    private static final Path JDK_JMODS = Paths.get(JAVA_HOME, "jmods");
+
+    private static final Path TEST_SRC = Paths.get(System.getProperty("test.src"));
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path CP_DIR = Paths.get("cp");
+    private static final Path JARS_DIR = Paths.get("jars");
+    private static final Path JMODS_DIR = Paths.get("jmods");
+    private static final Path IMAGE = Paths.get("image");
+
+    private static final String JAVA_BASE = "java.base";
+    private final String[] modules = new String[] { "message.writer",
+                                                    "message.converter" };
+
+    @BeforeTest
+    private void setup() throws Throwable {
+        Path src = TEST_SRC.resolve("src");
+        for (String name : modules) {
+            assertTrue(CompilerUtils.compile(src.resolve(name),
+                                             MODS_DIR,
+                                             "--module-source-path", src.toString()));
+        }
+
+        assertTrue(CompilerUtils.compile(src.resolve("cp"),
+                                         CP_DIR,
+                                         "--module-path", MODS_DIR.toString(),
+                                         "--add-modules", "message.writer"));
+    }
+
+    @DataProvider(name = "singleModule")
+    public Object[][] singleModuleValues() throws IOException {
+        Object[][] values = new Object[][]{
+         // { Extra args to the build the message.converter jmod
+         //   Tokens to pass to the run time --add-modules option
+         //   SUCCESS or FAILURE expected
+         //   Messages expected in the run time output
+         //   Messages that must not appear in the run time output },
+            { "",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("hello world", "message.converter", "java.base"),
+              List.of("WARNING") },
+            { "--do-not-resolve-by-default",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_FAILURE,
+              List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"),
+              List.of("WARNING", "message.converter") },
+            { "--warn-if-resolved=incubating",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("hello world", "message.converter", "java.base",
+                      "WARNING: Using incubator modules: message.converter"),
+              List.of() },
+            { "--do-not-resolve-by-default --warn-if-resolved=incubating",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_FAILURE,
+              List.of("java.base", "java.lang.ClassNotFoundException: converter.MessageConverter"),
+              List.of("WARNING", "message.converter") },
+            { "--do-not-resolve-by-default --warn-if-resolved=incubating",
+              List.of("message.converter"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("hello world", "message.converter", "java.base", "WARNING"),
+              List.of() }
+        };
+        return values;
+    }
+
+    @Test(dataProvider = "singleModule")
+    public void singleModule(String extraJmodArg,
+                             List<String> addModsTokens,
+                             Consumer<ToolResult> assertExitCode,
+                             List<String> expectedOutput,
+                             List<String> unexpectedOutput)
+        throws Throwable
+    {
+        if (Files.notExists(JDK_JMODS)) {
+            System.out.println("JDK jmods not found test cannot run.");
+            return;
+        }
+
+        FileUtils.deleteFileTreeUnchecked(JMODS_DIR);
+        FileUtils.deleteFileTreeUnchecked(IMAGE);
+        Files.createDirectories(JMODS_DIR);
+        Path converterJmod = JMODS_DIR.resolve("converter.jmod");
+
+        jmod("create",
+             "--class-path", MODS_DIR.resolve("message.converter").toString(),
+             extraJmodArg,
+             converterJmod.toString())
+            .assertSuccess();
+
+        String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString();
+        jlink("--module-path", mpath,
+              "--add-modules", JAVA_BASE + ",message.converter",
+              "--output", IMAGE.toString())
+             .assertSuccess();
+
+        for (String addModsToken : addModsTokens) {
+            String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"};
+            for (String systemProp : props)
+                java(IMAGE,
+                     systemProp,
+                     "--add-modules", addModsToken,
+                     "-cp", CP_DIR.toString(),
+                     "test.ConvertToLowerCase", "HEllo WoRlD")
+                    .resultChecker(assertExitCode)
+                    .resultChecker(r -> {
+                        expectedOutput.forEach(e -> r.assertContains(e));
+                        unexpectedOutput.forEach(e -> r.assertDoesNotContains(e));
+                    });
+        }
+    }
+
+    @Test
+    public void singleModularJar() throws Throwable {
+        FileUtils.deleteFileTreeUnchecked(JARS_DIR);
+        Files.createDirectories(JARS_DIR);
+        Path converterJar = JARS_DIR.resolve("converter.jar");
+
+        jar("--create",
+            "--file", converterJar.toString(),
+            "--warn-if-resolved=incubating",
+            "-C", MODS_DIR.resolve("message.converter").toString() , ".")
+            .assertSuccess();
+
+
+        java(Paths.get(JAVA_HOME),
+             "--module-path", JARS_DIR.toString(),
+             "--add-modules", "message.converter",
+             "-cp", CP_DIR.toString(),
+             "test.ConvertToLowerCase", "HEllo WoRlD")
+            .assertSuccess()
+            .resultChecker(r -> {
+                r.assertContains("WARNING: Using incubator modules: message.converter");
+            });
+    }
+
+    @DataProvider(name = "twoModules")
+    public Object[][] twoModulesValues() throws IOException {
+        Object[][] values = new Object[][]{
+         // { Extra args to the build the message.writer jmod
+         //   Extra args to the build the message.converter jmod
+         //   Tokens to pass to the run time --add-modules option
+         //   SUCCESS or FAILURE expected
+         //   Messages expected in the run time output
+         //   Messages that must not appear in the run time output },
+            { "",
+              "",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"),
+              List.of() },
+            { "",
+              "--do-not-resolve-by-default",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base"),
+              List.of() },
+            { "--do-not-resolve-by-default",
+              "",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_FAILURE,
+              List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"),
+              List.of("message.writer") },
+            { "--do-not-resolve-by-default",
+              "--do-not-resolve-by-default",
+              List.of("ALL-DEFAULT", "ALL-SYSTEM"),
+              ToolResult.ASSERT_FAILURE,
+              List.of("java.lang.ClassNotFoundException: writer.MessageWriter", "java.base"),
+              List.of("message.converter", "message.writer") },
+        // now add in warnings
+            { "--do-not-resolve-by-default --warn-if-resolved=incubating",
+              "",
+              List.of("message.writer"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base",
+                      "WARNING: Using incubator modules: message.writer"),
+              List.of() },
+            { "",
+              "--do-not-resolve-by-default --warn-if-resolved=incubating",
+              List.of("message.writer"),
+              ToolResult.ASSERT_SUCCESS,
+              List.of("HELLO CHEGAR !!!", "message.writer", "message.converter", "java.base",
+                      "WARNING: Using incubator modules: message.converter"),
+              List.of() } };
+        return values;
+    }
+
+    @Test(dataProvider = "twoModules")
+    public void doNotResolveByDefaultTwoModules(String extraFirstJmodArg,
+                                                String extraSecondJmodArg,
+                                                List<String> addModsTokens,
+                                                Consumer<ToolResult> assertExitCode,
+                                                List<String> expectedOutput,
+                                                List<String> unexpectedOutput)
+        throws Throwable
+    {
+        if (Files.notExists(JDK_JMODS)) {
+            System.out.println("JDK jmods not found test cannot run.");
+            return;
+        }
+
+        FileUtils.deleteFileTreeUnchecked(JMODS_DIR);
+        FileUtils.deleteFileTreeUnchecked(IMAGE);
+        Files.createDirectories(JMODS_DIR);
+        Path writerJmod = JMODS_DIR.resolve("writer.jmod");
+        Path converterJmod = JMODS_DIR.resolve("converter.jmod");
+
+        jmod("create",
+             extraFirstJmodArg,
+             "--class-path", MODS_DIR.resolve("message.writer").toString(),
+             writerJmod.toString());
+
+        jmod("create",
+             "--class-path", MODS_DIR.resolve("message.converter").toString(),
+             extraSecondJmodArg,
+             converterJmod.toString())
+            .assertSuccess();
+
+        String mpath = JDK_JMODS.toString() + File.pathSeparator + JMODS_DIR.toString();
+        jlink("--module-path", mpath,
+              "--add-modules", JAVA_BASE + ",message.writer,message.converter",
+              "--output", IMAGE.toString())
+             .assertSuccess();
+
+        for (String addModsToken : addModsTokens) {
+            String[] props = new String[] {"", "-Djdk.system.module.finder.disabledFastPath"};
+            for (String systemProp : props)
+                java(IMAGE,
+                     systemProp,
+                     "--add-modules", addModsToken,
+                     "-cp", CP_DIR.toString(),
+                     "test.WriteUpperCase", "hello chegar !!!")
+                    .resultChecker(assertExitCode)
+                    .resultChecker(r -> {
+                        expectedOutput.forEach(e -> r.assertContains(e));
+                        unexpectedOutput.forEach(e -> r.assertDoesNotContains(e));
+                    });
+        }
+    }
+
+    static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
+            .orElseThrow(() -> new RuntimeException("jmod tool not found"));
+    static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
+            .orElseThrow(() -> new RuntimeException("jar tool not found"));
+    static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
+            .orElseThrow(() -> new RuntimeException("jlink tool not found"));
+
+    static ToolResult jmod(String... args) { return execTool(JMOD_TOOL, args); }
+
+    static ToolResult jar(String... args) { return execTool(JAR_TOOL, args); }
+
+    static ToolResult jlink(String... args) { return execTool(JLINK_TOOL, args); }
+
+    static ToolResult java(Path image, String... opts) throws Throwable {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        String[] options = Stream.concat(Stream.of(getJava(image)),
+                                         Stream.of(opts).filter(s -> !s.equals("")))
+                                 .toArray(String[]::new);
+
+        ProcessBuilder pb = new ProcessBuilder(options);
+        int exitValue = executeCommand(pb).outputTo(ps)
+                                          .errorTo(ps)
+                                          .getExitValue();
+
+        return new ToolResult(exitValue, new String(baos.toByteArray(), UTF_8));
+    }
+
+    static ToolResult execTool(ToolProvider tool, String... args) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream ps = new PrintStream(baos);
+        List<String> filteredArgs = Stream.of(args)
+                                          .map(s -> s.split(" ")).flatMap(Stream::of)
+                                          .filter(s -> !s.equals(""))
+                                          .collect(Collectors.toList());
+        System.out.println(tool + " " + filteredArgs);
+        int ec = tool.run(ps, ps, filteredArgs.toArray(new String[] {}));
+        return new ToolResult(ec, new String(baos.toByteArray(), UTF_8));
+    }
+
+    static class ToolResult {
+        final int exitCode;
+        final String output;
+
+        ToolResult(int exitValue, String output) {
+            this.exitCode = exitValue;
+            this.output = output;
+        }
+
+        static Consumer<ToolResult> ASSERT_SUCCESS = r ->
+            assertEquals(r.exitCode, 0,
+                        "Expected exit code 0, got " + r.exitCode
+                                + ", with output[" + r.output + "]");
+        static Consumer<ToolResult> ASSERT_FAILURE = r ->
+            assertNotEquals(r.exitCode, 0,
+                           "Expected exit code != 0, got " + r.exitCode
+                                   + ", with output[" + r.output + "]");
+
+        ToolResult assertSuccess() { ASSERT_SUCCESS.accept(this); return this; }
+        ToolResult assertFailure() { ASSERT_FAILURE.accept(this); return this; }
+        ToolResult resultChecker(Consumer<ToolResult> r) { r.accept(this); return this; }
+
+        ToolResult assertContains(String subString) {
+            assertTrue(output.contains(subString),
+                       "Expected to find [" + subString + "], in output ["
+                            + output + "]" + "\n");
+            return this;
+        }
+        ToolResult assertDoesNotContains(String subString) {
+            assertFalse(output.contains(subString),
+                       "Expected to NOT find [" + subString + "], in output ["
+                           + output + "]" + "\n");
+            return this;
+        }
+    }
+
+    static String getJava(Path image) {
+        boolean isWindows = System.getProperty("os.name").startsWith("Windows");
+        Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java");
+        if (Files.notExists(java))
+            throw new RuntimeException(java + " not found");
+        return java.toAbsolutePath().toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/cp/listmods/ListModules.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ * 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 listmods;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import static java.util.stream.Collectors.joining;
+
+public class ListModules {
+    public static void main(String[] args) throws Exception {
+        System.out.println(Layer.boot()
+                                .modules()
+                                .stream()
+                                .map(Module::getName)
+                                .sorted()
+                                .collect(joining("\n")));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/cp/test/ConvertToLowerCase.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * 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 test;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import static java.util.stream.Collectors.joining;
+
+public class ConvertToLowerCase {
+    public static void main(String[] args) {
+        System.out.println(Layer.boot()
+                                .modules()
+                                .stream()
+                                .map(Module::getName)
+                                .sorted()
+                                .collect(joining("\n")));
+        System.out.println(converter.MessageConverter.toLowerCase(args[0]));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/cp/test/WriteUpperCase.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * 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 test;
+
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import static java.util.stream.Collectors.joining;
+
+public class WriteUpperCase {
+    public static void main(String[] args) {
+        System.out.println(Layer.boot()
+                                .modules()
+                                .stream()
+                                .map(Module::getName)
+                                .sorted()
+                                .collect(joining("\n")));
+        writer.MessageWriter.writeOn(args[0], System.out);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/message.converter/converter/MessageConverter.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ * 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 converter;
+
+public class MessageConverter {
+    public static String toUpperCase(String message) {
+        return message.toUpperCase(java.util.Locale.ROOT);
+    }
+
+    public static String toLowerCase(String message) {
+        return message.toLowerCase(java.util.Locale.ROOT);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/message.converter/module-info.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+module message.converter {
+    exports converter;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/message.writer/module-info.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+module message.writer {
+    requires message.converter;
+    exports writer;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/incubator/src/message.writer/writer/MessageWriter.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ *
+ * 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 writer;
+
+import java.io.PrintStream;
+import java.util.Locale;
+
+public class MessageWriter {
+    public static void writeOn(String message, PrintStream out) {
+        String newMesssage = converter.MessageConverter.toUpperCase(message);
+        if (!newMesssage.equals(message.toUpperCase(Locale.ROOT)))
+            throw new RuntimeException("Expected " + message.toUpperCase(Locale.ROOT)
+                                       + ", got " + newMesssage );
+
+        out.println(newMesssage);
+    }
+}
--- a/jdk/test/lib/testlibrary/ModuleUtils.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/lib/testlibrary/ModuleUtils.java	Mon Dec 19 16:05:38 2016 +0000
@@ -32,7 +32,6 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.function.Supplier;
 
 
 /**
@@ -58,12 +57,13 @@
 
             URI uri = URI.create("module:/" + name);
 
-            Supplier<ModuleReader> supplier = () -> {
-                throw new UnsupportedOperationException();
+            ModuleReference mref = new ModuleReference(descriptor, uri) {
+                @Override
+                public ModuleReader open() {
+                    throw new UnsupportedOperationException();
+                }
             };
 
-            ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
-
             namesToReference.put(name, mref);
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/misc/InvokeCleaner.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/* @test
+ * @bug 8171377
+ * @summary Basic test for Unsafe::invokeCleaner
+ * @modules jdk.unsupported
+ * @run testng/othervm InvokeCleaner
+ */
+
+import java.io.Closeable;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import sun.misc.Unsafe;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+public class InvokeCleaner {
+
+    static Unsafe UNSAFE;
+    static Path bob = Paths.get("bob");
+    static List<Closeable> closeables = new ArrayList<>();
+
+    @BeforeClass
+    static void init() throws Exception {
+        UNSAFE = getUnsafe();
+
+        byte[] srcData = new byte[20];
+        for (int i=0; i<20; i++)
+            srcData[i] = (byte)i;
+        Files.write(bob, srcData);
+    }
+
+    @DataProvider(name = "badBuffers")
+    static Object[][] createBadBuffers() throws Exception {
+        FileChannel fc = FileChannel.open(bob);
+        closeables.add(fc);
+        MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 10);
+
+        return new Object[][] {
+                { ByteBuffer.allocate(0) },
+                { ByteBuffer.allocate(10) },
+                { ByteBuffer.allocate(10).duplicate() },
+                { ByteBuffer.allocate(10).slice() },
+                { ByteBuffer.allocateDirect(10).duplicate() },
+                { ByteBuffer.allocateDirect(10).slice() },
+                { ByteBuffer.allocateDirect(0).duplicate() },
+                { ByteBuffer.allocateDirect(0).slice() },
+                { mbb.duplicate() },
+                { mbb.slice() }
+        };
+    }
+
+    @Test(dataProvider="badBuffers",
+          expectedExceptions = IllegalArgumentException.class)
+    public void badBuffers(ByteBuffer buffer) throws Exception {
+        UNSAFE.invokeCleaner(buffer);
+    }
+
+    @DataProvider(name = "goodBuffers")
+    static Object[][] createGoodBuffers() throws Exception {
+        FileChannel fc = FileChannel.open(bob);
+        closeables.add(fc);
+        MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, 10);
+        mbb.load();
+
+        return new Object[][] {
+                { ByteBuffer.allocateDirect(0) },
+                { ByteBuffer.allocateDirect(10) },
+                { mbb },
+                { fc.map(FileChannel.MapMode.READ_ONLY, 1, 11) }
+        };
+    }
+
+    @Test(dataProvider="goodBuffers")
+    public void goodBuffers(ByteBuffer buffer) throws Exception {
+        UNSAFE.invokeCleaner(buffer);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void npe() throws Exception {
+        UNSAFE.invokeCleaner(null);
+    }
+
+    static Unsafe getUnsafe() throws ReflectiveOperationException {
+        Field f = Unsafe.class.getDeclaredField("theUnsafe");
+        f.setAccessible(true);
+        return (Unsafe)f.get(null);
+    }
+
+    @AfterClass
+    public void cleanup() throws Exception {
+        for(Closeable fc : closeables)
+            fc.close();
+    }
+}
--- a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java	Mon Dec 19 16:05:38 2016 +0000
@@ -23,10 +23,12 @@
 
 /*
  * @test
- * @bug 6578647 6829283
+ * @bug 6578647 6829283 8171340
  * @run main/othervm HttpNegotiateServer
- * @summary Undefined requesting URL in java.net.Authenticator.getPasswordAuthentication()
- * @summary HTTP/Negotiate: Authenticator triggered again when user cancels the first one
+ * @summary Undefined requesting URL in java.net.Authenticator
+ *          .getPasswordAuthentication()
+ * @summary HTTP/Negotiate: Authenticator triggered again when
+ *          user cancels the first one
  */
 
 import com.sun.net.httpserver.Headers;
@@ -240,16 +242,15 @@
         java.net.Authenticator.setDefault(new KnowAllAuthenticator());
 
         reader = new BufferedReader(new InputStreamReader(
-                webUrl.openConnection().getInputStream()));
+                webUrl.openConnection(Proxy.NO_PROXY).getInputStream()));
         if (!reader.readLine().equals(CONTENT)) {
             throw new RuntimeException("Bad content");
         }
 
         reader = new BufferedReader(new InputStreamReader(
-                proxyUrl.openConnection(
-                new Proxy(Proxy.Type.HTTP,
-                    new InetSocketAddress(PROXY_HOST, proxyPort)))
-                .getInputStream()));
+                proxyUrl.openConnection(new Proxy(Proxy.Type.HTTP,
+                                new InetSocketAddress(PROXY_HOST, proxyPort)))
+                        .getInputStream()));
         if (!reader.readLine().equals(CONTENT)) {
             throw new RuntimeException("Bad content");
         }
@@ -260,7 +261,7 @@
         java.net.Authenticator.setDefault(new KnowNothingAuthenticator());
         try {
             new BufferedReader(new InputStreamReader(
-                    webUrl.openConnection().getInputStream()));
+                    webUrl.openConnection(Proxy.NO_PROXY).getInputStream()));
         } catch (IOException ioe) {
             // Will fail since no username and password is provided.
         }
@@ -274,7 +275,7 @@
         try {
             URL url = webUrl;
 
-            URLConnection conn = url.openConnection();
+            URLConnection conn = url.openConnection(Proxy.NO_PROXY);
             conn.connect();
             inputStream = conn.getInputStream();
             byte[] b = new byte[inputStream.available()];
@@ -285,7 +286,7 @@
             System.out.println("Length: " + s.length());
             System.out.println(s);
         } catch (Exception ex) {
-              throw new RuntimeException(ex);
+            throw new RuntimeException(ex);
         } finally {
             if (inputStream != null) {
                 try {
@@ -307,7 +308,8 @@
 
         CallbackHandler callback = new CallbackHandler() {
             @Override
-            public void handle(Callback[] pCallbacks) throws IOException, UnsupportedCallbackException {
+            public void handle(Callback[] pCallbacks)
+                    throws IOException, UnsupportedCallbackException {
                 for (Callback cb : pCallbacks) {
                     if (cb instanceof NameCallback) {
                         NameCallback ncb = (NameCallback)cb;
@@ -323,7 +325,8 @@
         };
 
         final String jaasConfigName = "oracle.test.kerberos.login";
-        final String krb5LoginModule = "com.sun.security.auth.module.Krb5LoginModule";
+        final String krb5LoginModule
+                = "com.sun.security.auth.module.Krb5LoginModule";
 
         Configuration loginConfig = new Configuration() {
             @Override
@@ -347,7 +350,8 @@
         // oracle context/subject/login
         LoginContext context = null;
         try {
-            context = new LoginContext("oracle.test.kerberos.login", null, callback, loginConfig);
+            context = new LoginContext(
+                    "oracle.test.kerberos.login", null, callback, loginConfig);
             context.login();
 
         } catch (LoginException ex) {
@@ -358,29 +362,35 @@
 
         Subject subject = context.getSubject();
 
-        final PrivilegedExceptionAction<Object> test_action = new PrivilegedExceptionAction<Object>() {
+        final PrivilegedExceptionAction<Object> test_action
+                = new PrivilegedExceptionAction<Object>() {
             public Object run() throws Exception {
                 testConnect();
                 return null;
             }
         };
 
-        System.err.println("\n\nExpecting to succeed when executing with the the logged in subject.");
+        System.err.println("\n\nExpecting to succeed when executing " +
+                "with the the logged in subject.");
 
         try {
             Subject.doAs(subject, test_action);
-            System.err.println("\n\nConnection succeed when executing with the the logged in subject.");
+            System.err.println("\n\nConnection succeed when executing " +
+                    "with the the logged in subject.");
         } catch (PrivilegedActionException e) {
-            System.err.println("\n\nFailure unexpected when executing with the the logged in subject.");
+            System.err.println("\n\nFailure unexpected when executing " +
+                    "with the the logged in subject.");
             e.printStackTrace();
             throw new RuntimeException("Failed to login as subject");
         }
 
         try {
-            System.err.println("\n\nExpecting to fail when running with the current user's login.");
+            System.err.println("\n\nExpecting to fail when running " +
+                    "with the current user's login.");
             testConnect();
         } catch (Exception ex) {
-            System.err.println("\nConnect failed when running with the current user's login:\n" + ex.getMessage());
+            System.err.println("\nConnect failed when running " +
+                    "with the current user's login:\n" + ex.getMessage());
         }
     }
 
@@ -450,8 +460,9 @@
                     return m.createCredential(
                             null,
                             GSSCredential.INDEFINITE_LIFETIME,
-                            MyServerAuthenticator.this.scheme.equalsIgnoreCase("Negotiate")?
-                                    GSSUtil.GSS_SPNEGO_MECH_OID:
+                            MyServerAuthenticator.this.scheme
+                                        .equalsIgnoreCase("Negotiate") ?
+                                    GSSUtil.GSS_SPNEGO_MECH_OID :
                                     GSSUtil.GSS_KRB5_MECH_OID,
                             GSSCredential.ACCEPT_ONLY);
                 }
@@ -465,7 +476,8 @@
             GSSContext c = null;
             String auth = exch.getRequestHeaders().getFirst(respHdr);
             try {
-                c = (GSSContext)exch.getHttpContext().getAttributes().get("GSSContext");
+                c = (GSSContext)exch.getHttpContext()
+                        .getAttributes().get("GSSContext");
                 if (auth == null) {                 // First request
                     Headers map = exch.getResponseHeaders();
                     map.set (reqHdr, scheme);        // Challenge!
@@ -478,7 +490,8 @@
                     exch.getHttpContext().getAttributes().put("GSSContext", c);
                     return new com.sun.net.httpserver.Authenticator.Retry(err);
                 } else {                            // Later requests
-                    byte[] token = Base64.getMimeDecoder().decode(auth.split(" ")[1]);
+                    byte[] token = Base64.getMimeDecoder()
+                            .decode(auth.split(" ")[1]);
                     token = c.acceptSecContext(token, 0, token.length);
                     Headers map = exch.getResponseHeaders();
                     map.set (reqHdr, scheme + " " + Base64.getMimeEncoder()
--- a/jdk/test/tools/jar/compat/CLICompatibility.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jar/compat/CLICompatibility.java	Mon Dec 19 16:05:38 2016 +0000
@@ -43,6 +43,7 @@
 import static java.lang.String.format;
 import static java.lang.System.out;
 import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
 /*
@@ -428,10 +429,12 @@
 
         jar("--help")
             .assertSuccess()
-            .resultChecker(r ->
+            .resultChecker(r -> {
                 assertTrue(r.output.startsWith("Usage: jar [OPTION...] [ [--release VERSION] [-C dir] files]"),
-                           "Failed, got [" + r.output + "]")
-            );
+                           "Failed, got [" + r.output + "]");
+                assertFalse(r.output.contains("--do-not-resolve-by-default"));
+                assertFalse(r.output.contains("--warn-if-resolved"));
+            });
 
         jar("--help:compat")
             .assertSuccess()
@@ -439,6 +442,15 @@
                 assertTrue(r.output.startsWith("Compatibility Interface:"),
                            "Failed, got [" + r.output + "]")
             );
+
+        jar("--help-extra")
+            .assertSuccess()
+            .resultChecker(r -> {
+                assertTrue(r.output.startsWith("Usage: jar [OPTION...] [ [--release VERSION] [-C dir] files]"),
+                           "Failed, got [" + r.output + "]");
+                assertTrue(r.output.contains("--do-not-resolve-by-default"));
+                assertTrue(r.output.contains("--warn-if-resolved"));
+            });
     }
 
     // -- Infrastructure
--- a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java	Mon Dec 19 16:05:38 2016 +0000
@@ -25,16 +25,18 @@
 
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
-import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Module;
 import java.util.Optional;
 import java.util.StringJoiner;
 import java.util.HashSet;
 import java.util.Set;
-
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleReferenceImpl;
 import jdk.test.bar.internal.Message;
 
 public class Bar {
@@ -71,9 +73,14 @@
         if (!sj.toString().equals(""))
             System.out.println("contains:" + sj.toString());
 
-        ModuleDescriptor foo = jdk.test.foo.Foo.class.getModule().getDescriptor();
-        JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess();
-        Optional<ModuleHashes> oHashes = jlma.hashes(foo);
-        System.out.println("hashes:" + oHashes.get().hashFor("bar"));
+
+        Module foo = jdk.test.foo.Foo.class.getModule();
+        Optional<ResolvedModule> om = foo.getLayer().configuration().findModule(foo.getName());
+        assert om.isPresent();
+        ModuleReference mref = om.get().reference();
+        assert mref instanceof ModuleReferenceImpl;
+        ModuleHashes hashes = ((ModuleReferenceImpl) mref).recordedHashes();
+        assert hashes != null;
+        System.out.println("hashes:" + hashes.hashFor("bar"));
     }
 }
--- a/jdk/test/tools/jimage/VerifyJimage.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jimage/VerifyJimage.java	Mon Dec 19 16:05:38 2016 +0000
@@ -49,7 +49,7 @@
  * @test
  * @summary Verify jimage
  * @modules java.base/jdk.internal.jimage
- * @run main/othervm --add-modules=ALL-SYSTEM VerifyJimage
+ * @run main/othervm --add-modules=ALL-SYSTEM,jdk.incubator.httpclient VerifyJimage
  */
 
 /**
--- a/jdk/test/tools/jlink/IntegrationTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jlink/IntegrationTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -186,7 +186,7 @@
             lst.add(new MyPostProcessor());
         }
         // Image builder
-        DefaultImageBuilder builder = new DefaultImageBuilder(output);
+        DefaultImageBuilder builder = new DefaultImageBuilder(output, Collections.emptyMap());
         PluginsConfiguration plugins
                 = new Jlink.PluginsConfiguration(lst, builder, null);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/ReleaseImplementorTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Properties;
+
+/*
+ * @test
+ * @bug 8171316
+ * @summary Add IMPLEMENTOR property to the release file
+ * @run main ReleaseImplementorTest
+ */
+public class ReleaseImplementorTest {
+    public static void main(String[] args) throws Exception {
+        Properties props = new Properties();
+        Path release = Paths.get(System.getProperty("test.jdk"), "release");
+        try (InputStream in = Files.newInputStream(release)) {
+            props.load(in);
+        }
+
+        if (!props.containsKey("IMPLEMENTOR")) {
+            throw new RuntimeException("IMPLEMENTOR key is missing");
+        }
+
+        String implementor = props.getProperty("IMPLEMENTOR");
+        if (implementor.length() < 3) {
+            throw new RuntimeException("IMPLEMENTOR value is not expected length");
+        }
+
+        if (implementor.charAt(0) != '"' ||
+            implementor.charAt(implementor.length() - 1) != '"') {
+            throw new RuntimeException("IMPLEMENTOR value not quoted property");
+        }
+
+        System.out.println("IMPLEMENTOR is " + implementor);
+    }
+}
--- a/jdk/test/tools/jlink/basic/BasicTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jlink/basic/BasicTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -87,20 +87,29 @@
         JarUtils.createJarFile(jarfile, classes);
 
         Path image = Paths.get("mysmallimage");
-        runJmod(jarfile.toString(), TEST_MODULE);
-        runJlink(image, TEST_MODULE, "--compress", "2");
-        execute(image, TEST_MODULE);
+        runJmod(jarfile.toString(), TEST_MODULE, true);
+        runJlink(image, TEST_MODULE, "--compress", "2", "--launcher", "foo=" + TEST_MODULE);
+        execute(image, "foo");
 
         Files.delete(jmods.resolve(TEST_MODULE + ".jmod"));
 
         image = Paths.get("myimage");
-        runJmod(classes.toString(), TEST_MODULE);
-        runJlink(image, TEST_MODULE);
-        execute(image, TEST_MODULE);
+        runJmod(classes.toString(), TEST_MODULE, true);
+        runJlink(image, TEST_MODULE, "--launcher", "bar=" + TEST_MODULE);
+        execute(image, "bar");
+
+        Files.delete(jmods.resolve(TEST_MODULE + ".jmod"));
+
+        image = Paths.get("myimage2");
+        runJmod(classes.toString(), TEST_MODULE, false /* no ModuleMainClass! */);
+        // specify main class in --launcher command line
+        runJlink(image, TEST_MODULE, "--launcher", "bar2=" + TEST_MODULE + "/jdk.test.Test");
+        execute(image, "bar2");
+
     }
 
-    private void execute(Path image, String moduleName) throws Throwable {
-        String cmd = image.resolve("bin").resolve(moduleName).toString();
+    private void execute(Path image, String scriptName) throws Throwable {
+        String cmd = image.resolve("bin").resolve(scriptName).toString();
         OutputAnalyzer analyzer;
         if (System.getProperty("os.name").startsWith("Windows")) {
             analyzer = ProcessTools.executeProcess("sh.exe", cmd, "1", "2", "3");
@@ -127,14 +136,25 @@
         }
     }
 
-    private void runJmod(String cp, String modName) {
-        int rc = JMOD_TOOL.run(System.out, System.out, new String[] {
+    private void runJmod(String cp, String modName, boolean main) {
+        int rc;
+        if (main) {
+            rc = JMOD_TOOL.run(System.out, System.out, new String[] {
                 "create",
                 "--class-path", cp,
                 "--module-version", "1.0",
                 "--main-class", "jdk.test.Test",
+                jmods.resolve(modName + ".jmod").toString()
+            });
+        } else {
+            rc = JMOD_TOOL.run(System.out, System.out, new String[] {
+                "create",
+                "--class-path", cp,
+                "--module-version", "1.0",
                 jmods.resolve(modName + ".jmod").toString(),
-        });
+            });
+        }
+
         if (rc != 0) {
             throw new AssertionError("Jmod failed: rc = " + rc);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/CompiledVersionTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -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.
+ *
+ * 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.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.FileUtils;
+import static jdk.testlibrary.ProcessTools.*;
+
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @library /lib/testlibrary
+ * @modules jdk.compiler jdk.jlink
+ * @build CompiledVersionTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
+ * @run testng CompiledVersionTest
+ */
+
+public class CompiledVersionTest {
+    private static final String JAVA_HOME = System.getProperty("java.home");
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+    private static final Path MODS_DIR = Paths.get("mods");
+    private static final Path IMAGE = Paths.get("image");
+    private static final Path JMODS = Paths.get(JAVA_HOME, "jmods");
+    private static final String MAIN_MID = "test/jdk.test.Main";
+
+    // the names of the modules in this test
+    private static String[] modules  = new String[] { "m1", "m2", "test"};
+    private static String[] versions = new String[] { "1.0", "2-ea", "3-internal"};
+
+
+    private static boolean hasJmods() {
+        if (!Files.exists(JMODS)) {
+            System.err.println("Test skipped. NO jmods directory");
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Compiles all modules used by the test
+     */
+    @BeforeTest
+    public void compileAll() throws Throwable {
+        if (!hasJmods()) return;
+
+        for (int i=0; i < modules.length; i++) {
+            String mn = modules[i];
+            String version = versions[i];
+            Path msrc = SRC_DIR.resolve(mn);
+            if (version.equals("0")) {
+                assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+                    "--module-source-path", SRC_DIR.toString()));
+            } else {
+                assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
+                    "--module-source-path", SRC_DIR.toString(),
+                    "--module-version", version));
+            }
+        }
+
+        if (Files.exists(IMAGE)) {
+            FileUtils.deleteFileTreeUnchecked(IMAGE);
+        }
+
+        createImage(IMAGE, modules);
+    }
+
+    private void createImage(Path outputDir, String... modules) throws Throwable {
+        Path jlink = Paths.get(JAVA_HOME, "bin", "jlink");
+        String mp = JMODS.toString() + File.pathSeparator + MODS_DIR.toString();
+        assertTrue(executeProcess(jlink.toString(), "--output", outputDir.toString(),
+                        "--add-modules", Arrays.stream(modules).collect(Collectors.joining(",")),
+                        "--module-path", mp)
+                        .outputTo(System.out)
+                        .errorTo(System.out)
+                        .getExitValue() == 0);
+    }
+
+    /*
+     * Test the image created when linking with a module with
+     * no Packages attribute
+     */
+    @Test
+    public void testCompiledVersions() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path java = IMAGE.resolve("bin").resolve("java");
+        Stream<String> options = Stream.concat(
+            Stream.of(java.toString(), "-m", MAIN_MID, String.valueOf(modules.length)),
+            Stream.concat(Arrays.stream(modules), Arrays.stream(versions))
+        );
+
+        assertTrue(executeProcess(options.toArray(String[]::new))
+                        .outputTo(System.out)
+                        .errorTo(System.out)
+                        .getExitValue() == 0);
+    }
+}
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -59,7 +59,7 @@
     private void testModuleDescriptor(ModuleDescriptor md) {
         assertUnmodifiable(md.packages(), "package");
         assertUnmodifiable(md.requires(),
-                           jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require"));
+                           jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require", null));
         for (Requires req : md.requires()) {
             assertUnmodifiable(req.modifiers(), Requires.Modifier.TRANSITIVE);
         }
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -39,7 +39,7 @@
 /**
  * @test
  * @library /lib/testlibrary
- * @modules jdk.compiler
+ * @modules jdk.compiler jdk.jlink
  * @build UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools
  * @run testng UserModuleTest
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/jdk/test/Main.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ *
+ * 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.test;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+
+/*
+ * Main class to verify if ModuleDescriptor carries the correct version
+ */
+public class Main {
+    static final Map<String, String> nameToVersion = new HashMap<>();
+
+    // jdk.test.Main $count $module-name... $version...
+    public static void main(String... args) throws Exception {
+        int count = args.length > 0 ? Integer.valueOf(args[0]) : 0;
+        if (count < 1 || args.length != count*2+1) {
+            throw new IllegalArgumentException(Arrays.toString(args));
+        }
+
+        List<String> modules = List.of(Arrays.copyOfRange(args, 1, 1+count));
+        List<String> versions = List.of(Arrays.copyOfRange(args, 1+count, args.length));
+        for (int i=0; i < modules.size(); i++) {
+            System.out.format("module %s expects %s version%n",
+                              modules.get(i), versions.get(i));
+            nameToVersion.put(modules.get(i), versions.get(i));
+        }
+
+        FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
+                                                  Collections.emptyMap());
+        // check the module descriptor of a system module
+        for (int i=0; i < modules.size(); i++) {
+            String mn = modules.get(i);
+            Module module = Layer.boot().findModule(mn).orElseThrow(
+                () -> new RuntimeException(mn + " not found")
+            );
+
+            // check ModuleDescriptor from the run-time
+            validate(module.getDescriptor());
+
+            // check module-info.class in the image
+            Path path = fs.getPath("/", "modules", modules.get(i), "module-info.class");
+            validate(ModuleDescriptor.read(Files.newInputStream(path)));
+        }
+    }
+
+    static void validate(ModuleDescriptor descriptor) {
+        checkVersion(descriptor.name(), descriptor.version());
+        descriptor.requires()
+            .stream()
+            .filter(r -> !r.name().equals("java.base"))
+            .forEach(r -> checkVersion(r.name(), r.compiledVersion()));
+    }
+
+    static void checkVersion(String mn, Optional<ModuleDescriptor.Version> version) {
+        boolean matched;
+        String v = nameToVersion.get(mn);
+        if (version.isPresent()) {
+            matched = version.get().toString().equals(v);
+        } else {
+            // 0 indicate no version
+            matched = v.equals("0");
+        }
+
+        if (!matched) {
+            throw new RuntimeException(mn + " mismatched version " + version
+                + " expected: " + v);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/test/module-info.java	Mon Dec 19 16:05:38 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+module test {
+    requires m1;
+    requires m2;
+    exports jdk.test;
+}
--- a/jdk/test/tools/jmod/JmodTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jmod/JmodTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -470,9 +470,22 @@
     public void testHelp() {
         jmod("--help")
             .assertSuccess()
-            .resultChecker(r ->
-                assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed")
-            );
+            .resultChecker(r -> {
+                assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed");
+                assertFalse(r.output.contains("--do-not-resolve-by-default"));
+                assertFalse(r.output.contains("--warn-if-resolved"));
+            });
+    }
+
+    @Test
+    public void testHelpExtra() {
+        jmod("--help-extra")
+            .assertSuccess()
+            .resultChecker(r -> {
+                assertTrue(r.output.startsWith("Usage: jmod"), "Extra help not printed");
+                assertContains(r.output, "--do-not-resolve-by-default");
+                assertContains(r.output, "--warn-if-resolved");
+            });
     }
 
     @Test
--- a/jdk/test/tools/jmod/hashes/HashesTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/jmod/hashes/HashesTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -50,14 +50,13 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import java.util.Optional;
 import java.util.Set;
 import java.util.spi.ToolProvider;
 import java.util.stream.Collectors;
 
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModulePath;
 
 import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
@@ -103,54 +102,53 @@
     @Test
     public void test() throws Exception {
         for (String mn : modules) {
-            assertFalse(hashes(mn).isPresent());
+            assertTrue(hashes(mn) == null);
         }
 
         // hash m1 in m2
         jmod("m2", "--module-path", jmods.toString(), "--hash-modules", "m1");
-        checkHashes(hashes("m2").get(), "m1");
+        checkHashes(hashes("m2"), "m1");
 
         // hash m1 in m2
         jmod("m2", "--module-path", jmods.toString(), "--hash-modules", ".*");
-        checkHashes(hashes("m2").get(), "m1");
+        checkHashes(hashes("m2"), "m1");
 
         // create m2.jmod with no hash
         jmod("m2");
         // run jmod hash command to hash m1 in m2 and m3
         runJmod(Arrays.asList("hash", "--module-path", jmods.toString(),
                 "--hash-modules", ".*"));
-        checkHashes(hashes("m2").get(), "m1");
-        checkHashes(hashes("m3").get(), "m1");
+        checkHashes(hashes("m2"), "m1");
+        checkHashes(hashes("m3"), "m1");
 
         jmod("org.bar");
         jmod("org.foo");
 
         jmod("org.bar", "--module-path", jmods.toString(), "--hash-modules", "org.*");
-        checkHashes(hashes("org.bar").get(), "org.foo");
+        checkHashes(hashes("org.bar"), "org.foo");
 
         jmod("m3", "--module-path", jmods.toString(), "--hash-modules", ".*");
-        checkHashes(hashes("m3").get(), "org.foo", "org.bar", "m1");
+        checkHashes(hashes("m3"), "org.foo", "org.bar", "m1");
     }
 
     private void checkHashes(ModuleHashes hashes, String... hashModules) {
         assertTrue(hashes.names().equals(Set.of(hashModules)));
     }
 
-    private Optional<ModuleHashes> hashes(String name) throws Exception {
-        ModuleFinder finder = SharedSecrets.getJavaLangModuleAccess()
-            .newModulePath(Runtime.version(), true, jmods.resolve(name + ".jmod"));
+    private ModuleHashes hashes(String name) throws Exception {
+        ModuleFinder finder = new ModulePath(Runtime.version(),
+                                             true,
+                                             jmods.resolve(name + ".jmod"));
         ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new);
         ModuleReader reader = mref.open();
         try (InputStream in = reader.open("module-info.class").get()) {
-            ModuleDescriptor md = ModuleDescriptor.read(in);
-            JavaLangModuleAccess jmla = SharedSecrets.getJavaLangModuleAccess();
-            Optional<ModuleHashes> hashes = jmla.hashes(md);
+            ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes();
             System.out.format("hashes in module %s %s%n", name,
-                              hashes.isPresent() ? "present" : "absent");
-            if (hashes.isPresent()) {
-                hashes.get().names().stream()
+                    (hashes != null) ? "present" : "absent");
+            if (hashes != null) {
+                hashes.names().stream()
                     .sorted()
-                    .forEach(n -> System.out.format("  %s %s%n", n, hashes.get().hashFor(n)));
+                    .forEach(n -> System.out.format("  %s %s%n", n, hashes.hashFor(n)));
             }
             return hashes;
         } finally {
--- a/jdk/test/tools/launcher/RunpathTest.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/launcher/RunpathTest.java	Mon Dec 19 16:05:38 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -64,7 +64,7 @@
     }
 
     void testRpath() {
-        String expectedRpath = ".*RPATH.*\\$ORIGIN/../lib/" + getJreArch() + ".*";
+        String expectedRpath = ".*RPATH.*\\$ORIGIN/../lib.*";
         elfCheck(javaCmd, expectedRpath);
     }
 
--- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java	Mon Dec 19 16:00:59 2016 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java	Mon Dec 19 16:05:38 2016 +0000
@@ -41,6 +41,8 @@
 import com.sun.tools.classfile.CompilationID_attribute;
 import com.sun.tools.classfile.ConstantPool;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Module_info;
+import com.sun.tools.classfile.ConstantPool.CONSTANT_Package_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info;
@@ -80,9 +82,9 @@
 import com.sun.tools.classfile.ModuleHashes_attribute;
 import com.sun.tools.classfile.ModuleHashes_attribute.Entry;
 import com.sun.tools.classfile.ModuleMainClass_attribute;
+import com.sun.tools.classfile.ModuleResolution_attribute;
 import com.sun.tools.classfile.ModuleTarget_attribute;
 import com.sun.tools.classfile.ModulePackages_attribute;
-import com.sun.tools.classfile.ModuleVersion_attribute;
 import com.sun.tools.classfile.Opcode;
 import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute;
 import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute;
@@ -670,6 +672,40 @@
     }
 
     @Override
+    public String visitModule(CONSTANT_Module_info info, Integer p) {
+        String value = slist.get(p);
+        if (value == null) {
+            try {
+                value = visit(cfpool.get(info.name_index), info.name_index);
+                slist.set(p, value);
+                xpool.add(new Element("CONSTANT_Module",
+                        new String[]{"id", p.toString()},
+                        value));
+            } catch (ConstantPoolException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return value;
+    }
+
+    @Override
+    public String visitPackage(CONSTANT_Package_info info, Integer p) {
+        String value = slist.get(p);
+        if (value == null) {
+            try {
+                value = visit(cfpool.get(info.name_index), info.name_index);
+                slist.set(p, value);
+                xpool.add(new Element("CONSTANT_Package",
+                        new String[]{"id", p.toString()},
+                        value));
+            } catch (ConstantPoolException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return value;
+    }
+
+    @Override
     public String visitDouble(CONSTANT_Double_info c, Integer p) {
         String value = slist.get(p);
         if (value == null) {
@@ -1495,20 +1531,20 @@
     }
 
     @Override
-    public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) {
-        Element e = new Element(x.getCpString(attr.attribute_name_index));
-        e.add(x.getCpString(attr.os_name_index));
-        e.add(x.getCpString(attr.os_arch_index));
-        e.add(x.getCpString(attr.os_version_index));
+    public Element visitModuleResolution(ModuleResolution_attribute attr, Element p) {
+        Element e = new Element("ModuleResolution");
+        e.setAttr("flags", Integer.toString(attr.resolution_flags));
         e.trimToSize();
         p.add(e);
         return null;
     }
 
     @Override
-    public Element visitModuleVersion(ModuleVersion_attribute attr, Element p) {
+    public Element visitModuleTarget(ModuleTarget_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
-        e.add(x.getCpString(attr.version_index));
+        e.add(x.getCpString(attr.os_name_index));
+        e.add(x.getCpString(attr.os_arch_index));
+        e.add(x.getCpString(attr.os_version_index));
         e.trimToSize();
         p.add(e);
         return null;