Merge
authorlana
Thu, 01 Dec 2016 21:39:49 +0000
changeset 42344 a2378998a8fd
parent 42312 e10f33144189 (current diff)
parent 42343 58076b66ffdb (diff)
child 42345 cead5ce4ca27
Merge
jdk/src/java.base/share/classes/java/lang/module/Dependence.java
jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java
jdk/test/java/awt/Focus/DisposedWindow/DisposeDialogNotActivateOwnerTest/DisposeDialogNotActivateOwnerTest.html
jdk/test/java/lang/Class/getResource/src/m3/module-info.java
jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java
jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java
jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java
jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java
jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java
jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java
jdk/test/java/net/Authenticator/B4933582.sh
jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java
jdk/test/java/util/ServiceLoader/Basic.java
jdk/test/java/util/ServiceLoader/FooProvider1.java
jdk/test/java/util/ServiceLoader/FooProvider2.java
jdk/test/java/util/ServiceLoader/FooProvider3.java
jdk/test/java/util/ServiceLoader/FooService.java
jdk/test/java/util/ServiceLoader/Load.java
jdk/test/java/util/ServiceLoader/basic.sh
jdk/test/java/util/ServiceLoader/modules/MiscTests.java
jdk/test/java/util/ServiceLoader/modules/ServicesTest.java
jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java
jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java
jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java
jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java
jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java
--- a/jdk/.hgignore	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/.hgignore	Thu Dec 01 21:39:49 2016 +0000
@@ -5,7 +5,6 @@
 /nbproject/private/
 ^make/netbeans/.*/build/
 ^make/netbeans/.*/dist/
-^.hgtip
 .DS_Store
 .*/JTreport/.*
 .*/JTwork/.*
--- a/jdk/make/data/jdwp/jdwp.spec	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/make/data/jdwp/jdwp.spec	Thu Dec 01 21:39:49 2016 +0000
@@ -2709,22 +2709,6 @@
             (Error VM_DEAD)
         )
     )
-    (Command CanRead=3
-        "Returns true if this module can read the source module; false otherwise."
-        "<p>Since JDWP version 9."
-        (Out
-            (moduleID module "This module.")
-            (moduleID sourceModule "The source module.")
-        )
-        (Reply
-            (boolean canRead  "true if this module can read the source module; false otherwise.")
-        )
-        (ErrorSet
-            (Error INVALID_MODULE  "This module or sourceModule is not the ID of a module.")
-            (Error NOT_IMPLEMENTED)
-            (Error VM_DEAD)
-        )
-    )
 )
 (CommandSet Event=64
     (Command Composite=100
--- a/jdk/make/launcher/Launcher-jdk.jconsole.gmk	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/make/launcher/Launcher-jdk.jconsole.gmk	Thu Dec 01 21:39:49 2016 +0000
@@ -27,7 +27,8 @@
 
 $(eval $(call SetupBuildLauncher, jconsole, \
     MAIN_CLASS := sun.tools.jconsole.JConsole, \
-    JAVA_ARGS := -Djconsole.showOutputViewer, \
+    JAVA_ARGS := --add-opens java.base/java.io=jdk.jconsole \
+		 -Djconsole.showOutputViewer, \
     CFLAGS_windows := -DJAVAW, \
     LIBS_windows := user32.lib, \
 ))
--- a/jdk/make/lib/Awt2dLibraries.gmk	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/make/lib/Awt2dLibraries.gmk	Thu Dec 01 21:39:49 2016 +0000
@@ -287,9 +287,8 @@
         $(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
         $(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/utility \
         $(JDK_TOPDIR)/src/java.desktop/share/native/common/font \
-        $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
-        $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/opengl \
-        $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/x11 \
+        $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d \
+        $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d \
         $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \
         #
 
@@ -516,24 +515,25 @@
 
   LIBAWT_HEADLESS_DIRS := $(JDK_TOPDIR)/src/java.desktop/unix/native/libawt_headless/awt \
       $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \
-      $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/opengl \
-      $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/x11 \
-      $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
+      $(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d \
+      $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d \
       $(JDK_TOPDIR)/src/java.desktop/share/native/common/font \
       #
 
   LIBAWT_HEADLESS_EXCLUDES := medialib
   LIBAWT_HEADLESS_CFLAGS := -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \
       $(addprefix -I, $(LIBAWT_HEADLESS_DIRS)) \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d \
+      -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libawt/java2d \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/loops \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/pipe \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image \
-      -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libawt/java2d \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/font \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
       -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/font \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
+      -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/java2d/opengl \
       -I$(JDK_TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/libsunwjdga/ \
       $(LIBJAVA_HEADER_FLAGS) \
       #
@@ -862,7 +862,7 @@
 
   ifeq ($(OPENJDK_TARGET_OS), windows)
     LIBSPLASHSCREEN_DIRS += $(JDK_TOPDIR)/src/java.desktop/windows/native/common/awt/systemscale
-  endif	
+  endif
   LIBSPLASHSCREEN_CFLAGS += -DSPLASHSCREEN -DPNG_NO_MMX_CODE -DPNG_ARM_NEON_OPT=0 \
       $(addprefix -I, $(LIBSPLASHSCREEN_DIRS)) \
       $(LIBJAVA_HEADER_FLAGS) \
@@ -952,26 +952,27 @@
       $(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt \
       $(JDK_TOPDIR)/src/java.desktop/unix/native/common/awt \
       $(JDK_TOPDIR)/src/java.desktop/share/native/common/font \
-      $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
+      $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d \
       #
 
   LIBAWT_LWAWT_CFLAGS := \
       $(addprefix -I, $(LIBAWT_LWAWT_DIRS)) \
       -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \
-      -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/include \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/include \
-      -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl \
       -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/awt \
       -I$(JDK_TOPDIR)/src/java.desktop/unix/native/libawt_xawt/awt \
       -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/font \
+      -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libawt_lwawt/java2d/opengl \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \
+      -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/include \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/include \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d \
       -I$(JDK_TOPDIR)/src/java.desktop/unix/native/libawt/java2d \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libmlib_image/ \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/loops \
       -I$(JDK_TOPDIR)/src/java.desktop/share/native/libawt/java2d/pipe \
-      -I$(JDK_TOPDIR)/src/java.desktop/share/native/common/awt/debug \
+      -I$(JDK_TOPDIR)/src/java.desktop/share/native/libmlib_image/ \
       -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libosxapp \
       $(LIBJAVA_HEADER_FLAGS) \
       #
--- a/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java	Thu Dec 01 21:39:49 2016 +0000
@@ -65,7 +65,7 @@
                     String mn = entry.getFileName().toString();
                     Optional<ModuleReference> omref = finder.find(mn);
                     if (omref.isPresent()) {
-                        Set<String> packages = omref.get().descriptor().conceals();
+                        Set<String> packages = omref.get().descriptor().packages();
                         addPackagesAttribute(mi, packages);
                     }
                 }
@@ -77,7 +77,7 @@
         byte[] bytes;
         try (InputStream in = Files.newInputStream(mi)) {
             ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in);
-            extender.conceals(packages);
+            extender.packages(packages);
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             extender.write(baos);
             bytes = baos.toByteArray();
--- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java	Thu Dec 01 21:39:49 2016 +0000
@@ -43,7 +43,7 @@
 import java.util.TreeSet;
 import java.util.function.Function;
 import java.util.stream.Collectors;
-import static java.lang.module.ModuleDescriptor.Requires.Modifier.PUBLIC;
+import static java.lang.module.ModuleDescriptor.Requires.Modifier.TRANSITIVE;
 
 /**
  * Generate the DOT file for a module graph for each module in the JDK
@@ -172,14 +172,14 @@
             Graph<String> graph = gengraph(cf);
             descriptors.forEach(md -> {
                 String mn = md.name();
-                Set<String> requiresPublic = md.requires().stream()
-                        .filter(d -> d.modifiers().contains(PUBLIC))
+                Set<String> requiresTransitive = md.requires().stream()
+                        .filter(d -> d.modifiers().contains(TRANSITIVE))
                         .map(d -> d.name())
                         .collect(Collectors.toSet());
 
                 graph.adjacentNodes(mn).forEach(dn -> {
                     String attr = dn.equals("java.base") ? REQUIRES_BASE
-                            : (requiresPublic.contains(dn) ? REEXPORTS : REQUIRES);
+                            : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES);
                     int w = weightOf(mn, dn);
                     if (w > 1)
                         attr += "weight=" + w;
@@ -194,8 +194,8 @@
     /**
      * Returns a Graph of the given Configuration after transitive reduction.
      *
-     * Transitive reduction of requires public edge and requires edge have
-     * to be applied separately to prevent the requires public edges
+     * Transitive reduction of requires transitive edge and requires edge have
+     * to be applied separately to prevent the requires transitive edges
      * (e.g. U -> V) from being reduced by a path (U -> X -> Y -> V)
      * in which  V would not be re-exported from U.
      */
@@ -208,21 +208,21 @@
                     .map(ResolvedModule::name)
                     .forEach(target -> builder.addEdge(mn, target));
         }
-        Graph<String> rpg = requiresPublicGraph(cf);
+        Graph<String> rpg = requiresTransitiveGraph(cf);
         return builder.build().reduce(rpg);
     }
 
     /**
-     * Returns a Graph containing only requires public edges
+     * Returns a Graph containing only requires transitive edges
      * with transitive reduction.
      */
-    private Graph<String> requiresPublicGraph(Configuration cf) {
+    private Graph<String> requiresTransitiveGraph(Configuration cf) {
         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(PUBLIC))
+                    .filter(d -> d.modifiers().contains(TRANSITIVE))
                     .map(d -> d.name())
                     .forEach(d -> builder.addEdge(mn, d));
         }
--- a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java	Thu Dec 01 21:39:49 2016 +0000
@@ -299,7 +299,7 @@
     static class HtmlDocument {
         final String title;
         final Map<String, ModuleSummary> modules;
-        boolean requiresPublicNote = false;
+        boolean requiresTransitiveNote = false;
         boolean aggregatorNote = false;
         boolean totalBytesNote = false;
         HtmlDocument(String title, Map<String, ModuleSummary> modules) {
@@ -510,16 +510,16 @@
             public String requiresColumn() {
                 StringBuilder sb = new StringBuilder();
                 sb.append(String.format("<td>"));
-                boolean footnote = requiresPublicNote;
+                boolean footnote = requiresTransitiveNote;
                 ms.descriptor().requires().stream()
                         .sorted(Comparator.comparing(Requires::name))
                         .forEach(r -> {
-                            boolean requiresPublic = r.modifiers().contains(Requires.Modifier.PUBLIC);
-                            Selector sel = requiresPublic ? REQUIRES_PUBLIC : REQUIRES;
+                            boolean requiresTransitive = r.modifiers().contains(Requires.Modifier.TRANSITIVE);
+                            Selector sel = requiresTransitive ? REQUIRES_PUBLIC : REQUIRES;
                             String req = String.format("<a class=\"%s\" href=\"#%s\">%s</a>",
                                                        sel, r.name(), r.name());
-                            if (!requiresPublicNote && requiresPublic) {
-                                requiresPublicNote = true;
+                            if (!requiresTransitiveNote && requiresTransitive) {
+                                requiresTransitiveNote = true;
                                 req += "<sup>*</sup>";
                             }
                             sb.append(req).append("\n").append("<br>");
@@ -534,8 +534,8 @@
                     sb.append("<br>");
                     sb.append("<i>+").append(indirectDeps).append(" transitive dependencies</i>");
                 }
-                if (footnote != requiresPublicNote) {
-                    sb.append("<br><br>").append("<i>* bold denotes requires public</i>");
+                if (footnote != requiresTransitiveNote) {
+                    sb.append("<br><br>").append("<i>* bold denotes requires transitive</i>");
                 }
                 sb.append("</td>");
                 return sb.toString();
@@ -558,11 +558,10 @@
                 ms.descriptor().uses().stream()
                         .sorted()
                         .forEach(s -> sb.append("uses ").append(s).append("<br>").append("\n"));
-                ms.descriptor().provides().entrySet().stream()
-                        .sorted(Map.Entry.comparingByKey())
-                        .flatMap(e -> e.getValue().providers().stream()
-                                .map(p -> String.format("provides %s<br>&nbsp;&nbsp;&nbsp;&nbsp;with %s",
-                                                        e.getKey(), p)))
+                ms.descriptor().provides().stream()
+                        .sorted(Comparator.comparing(Provides::service))
+                        .map(p -> String.format("provides %s<br>&nbsp;&nbsp;&nbsp;&nbsp;with %s",
+                                                p.service(), p.providers()))
                         .forEach(p -> sb.append(p).append("<br>").append("\n"));
                 sb.append("</td>");
                 return sb.toString();
--- a/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,219 +30,593 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import static java.util.stream.Collectors.*;
 
 /**
  * A build tool to extend the module-info.java in the source tree for
- * platform-specific exports, uses, and provides and write to the specified
- * output file. Injecting platform-specific requires is not supported.
+ * platform-specific exports, opens, uses, and provides and write to
+ * the specified output file.
+ *
+ * GenModuleInfoSource will be invoked for each module that has
+ * module-info.java.extra in the source directory.
  *
- * The extra exports, uses, provides can be specified in module-info.java.extra
- * files and GenModuleInfoSource will be invoked for each module that has
- * module-info.java.extra in the source directory.
+ * The extra exports, opens, uses, provides can be specified
+ * in module-info.java.extra.
+ * Injecting platform-specific requires is not supported.
+ *
+ * @see build.tools.module.ModuleInfoExtraTest for basic testing
  */
 public class GenModuleInfoSource {
     private final static String USAGE =
-        "Usage: GenModuleInfoSource [option] -o <output file> <module-info-java>\n" +
-        "Options are:\n" +
-        "  -exports  <package-name>\n" +
-        "  -exports  <package-name>[/<module-name>]\n" +
-        "  -uses     <service>\n" +
-        "  -provides <service>/<provider-impl-classname>\n";
+        "Usage: GenModuleInfoSource -o <output file> \n" +
+        "  --source-file <module-info-java>\n" +
+        "  --modules <module-name>[,<module-name>...]\n" +
+        "  <module-info.java.extra> ...\n";
 
+    static boolean verbose = false;
     public static void main(String... args) throws Exception {
         Path outfile = null;
         Path moduleInfoJava = null;
-        GenModuleInfoSource genModuleInfo = new GenModuleInfoSource();
-
+        Set<String> modules = Collections.emptySet();
+        List<Path> extras = new ArrayList<>();
         // validate input arguments
         for (int i = 0; i < args.length; i++){
             String option = args[i];
-            if (option.startsWith("-")) {
-                String arg = args[++i];
-                if (option.equals("-exports")) {
-                    int index = arg.indexOf('/');
-                        if (index > 0) {
-                            String pn = arg.substring(0, index);
-                            String mn = arg.substring(index + 1, arg.length());
-                            genModuleInfo.exportTo(pn, mn);
-                        } else {
-                            genModuleInfo.export(arg);
-                        }
-                } else if (option.equals("-uses")) {
-                    genModuleInfo.use(arg);
-                } else if (option.equals("-provides")) {
-                        int index = arg.indexOf('/');
-                        if (index <= 0) {
-                            throw new IllegalArgumentException("invalid -provide argument: " + arg);
-                        }
-                        String service = arg.substring(0, index);
-                        String impl = arg.substring(index + 1, arg.length());
-                        genModuleInfo.provide(service, impl);
-                } else if (option.equals("-o")) {
+            String arg = i+1 < args.length ? args[i+1] : null;
+            switch (option) {
+                case "-o":
                     outfile = Paths.get(arg);
-                } else {
-                    throw new IllegalArgumentException("invalid option: " + option);
-                }
-            } else if (moduleInfoJava != null) {
-                throw new IllegalArgumentException("more than one module-info.java");
-            } else {
-                moduleInfoJava = Paths.get(option);
-                if (Files.notExists(moduleInfoJava)) {
-                    throw new IllegalArgumentException(option + " not exist");
-                }
+                    i++;
+                    break;
+                case "--source-file":
+                    moduleInfoJava = Paths.get(arg);
+                    if (Files.notExists(moduleInfoJava)) {
+                        throw new IllegalArgumentException(moduleInfoJava + " not exist");
+                    }
+                    i++;
+                    break;
+                case "--modules":
+                    modules = Arrays.stream(arg.split(","))
+                                    .collect(toSet());
+                    i++;
+                    break;
+                case "-v":
+                    verbose = true;
+                    break;
+                default:
+                    Path file = Paths.get(option);
+                    if (Files.notExists(file)) {
+                        throw new IllegalArgumentException(file + " not exist");
+                    }
+                    extras.add(file);
             }
         }
 
-        if (moduleInfoJava == null || outfile == null) {
+        if (moduleInfoJava == null || outfile == null ||
+                modules.isEmpty() || extras.isEmpty()) {
             System.err.println(USAGE);
             System.exit(-1);
         }
 
-        // generate new module-info.java
-        genModuleInfo.generate(moduleInfoJava, outfile);
-    }
+        GenModuleInfoSource genModuleInfo =
+            new GenModuleInfoSource(moduleInfoJava, extras, modules);
 
-    private final Set<String> exports = new HashSet<>();
-    private final Map<String, Set<String>> exportsTo = new HashMap<>();
-    private final Set<String> uses = new HashSet<>();
-    private final Map<String, Set<String>> provides = new HashMap<>();
-    GenModuleInfoSource() {
+        // generate new module-info.java
+        genModuleInfo.generate(outfile);
     }
 
-    private void export(String p) {
-        Objects.requireNonNull(p);
-        if (exports.contains(p) || exportsTo.containsKey(p)) {
-            throw new RuntimeException("duplicated exports: " + p);
+    final Path sourceFile;
+    final List<Path> extraFiles;
+    final ModuleInfo extras;
+    final Set<String> modules;
+    final ModuleInfo moduleInfo;
+    GenModuleInfoSource(Path sourceFile, List<Path> extraFiles, Set<String> modules)
+        throws IOException
+    {
+        this.sourceFile = sourceFile;
+        this.extraFiles = extraFiles;
+        this.modules = modules;
+        this.moduleInfo = new ModuleInfo();
+        this.moduleInfo.parse(sourceFile);
+
+        // parse module-info.java.extra
+        this.extras = new ModuleInfo();
+        for (Path file : extraFiles) {
+            extras.parse(file);
         }
-        exports.add(p);
-    }
-    private void exportTo(String p, String mn) {
-        Objects.requireNonNull(p);
-        Objects.requireNonNull(mn);
-        if (exports.contains(p)) {
-            throw new RuntimeException("unqualified exports already exists: " + p);
-        }
-        exportsTo.computeIfAbsent(p, _k -> new HashSet<>()).add(mn);
+
+        // merge with module-info.java.extra
+        moduleInfo.augmentModuleInfo(extras, modules);
     }
 
-    private void use(String service) {
-        uses.add(service);
-    }
+    void generate(Path output) throws IOException {
+        List<String> lines = Files.readAllLines(sourceFile);
+        try (BufferedWriter bw = Files.newBufferedWriter(output);
+             PrintWriter writer = new PrintWriter(bw)) {
+            // write the copyright header and lines up to module declaration
+            for (String l : lines) {
+                writer.println(l);
+                if (l.trim().startsWith("module ")) {
+                    writer.format("    // source file: %s%n", sourceFile);
+                    for (Path file: extraFiles) {
+                        writer.format("    //              %s%n", file);
+                    }
+                    break;
+                }
+            }
 
-    private void provide(String s, String impl) {
-        provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl);
+            // requires
+            for (String l : lines) {
+                if (l.trim().startsWith("requires"))
+                    writer.println(l);
+            }
+
+            // write exports, opens, uses, and provides
+            moduleInfo.print(writer);
+
+            // close
+            writer.println("}");
+        }
     }
 
-    private void generate(Path sourcefile, Path outfile) throws IOException {
-        Path parent = outfile.getParent();
-        if (parent != null)
-            Files.createDirectories(parent);
+
+    class ModuleInfo {
+        final Map<String, Statement> exports = new HashMap<>();
+        final Map<String, Statement> opens = new HashMap<>();
+        final Map<String, Statement> uses = new HashMap<>();
+        final Map<String, Statement> provides = new HashMap<>();
+
+        Statement getStatement(String directive, String name) {
+            switch (directive) {
+                case "exports":
+                    if (moduleInfo.exports.containsKey(name) &&
+                        moduleInfo.exports.get(name).isUnqualified()) {
+                        throw new IllegalArgumentException(sourceFile +
+                            " already has " + directive + " " + name);
+                    }
+                    return exports.computeIfAbsent(name,
+                        _n -> new Statement("exports", "to", name));
+
+                case "opens":
+                    if (moduleInfo.opens.containsKey(name) &&
+                        moduleInfo.opens.get(name).isUnqualified()) {
+                        throw new IllegalArgumentException(sourceFile +
+                            " already has " + directive + " " + name);
+                    }
+
+                    if (moduleInfo.opens.containsKey(name)) {
+                        throw new IllegalArgumentException(sourceFile +
+                            " already has " + directive + " " + name);
+                    }
+                    return opens.computeIfAbsent(name,
+                        _n -> new Statement("opens", "to", name));
+
+                case "uses":
+                    return uses.computeIfAbsent(name,
+                        _n -> new Statement("uses", "", name));
+
+                case "provides":
+                    return provides.computeIfAbsent(name,
+                        _n -> new Statement("provides", "with", name, true));
+
+                default:
+                    throw new IllegalArgumentException(directive);
+            }
+
+        }
+
+        /*
+         * Augment this ModuleInfo with module-info.java.extra
+         */
+        void augmentModuleInfo(ModuleInfo extraFiles, Set<String> modules) {
+            // API package exported in the original module-info.java
+            extraFiles.exports.entrySet()
+                .stream()
+                .filter(e -> exports.containsKey(e.getKey()) &&
+                                e.getValue().filter(modules))
+                .forEach(e -> mergeExportsOrOpens(exports.get(e.getKey()),
+                                                  e.getValue(),
+                                                  modules));
+
+            // add exports that are not defined in the original module-info.java
+            extraFiles.exports.entrySet()
+                .stream()
+                .filter(e -> !exports.containsKey(e.getKey()) &&
+                                e.getValue().filter(modules))
+                .forEach(e -> addTargets(getStatement("exports", e.getKey()),
+                                         e.getValue(),
+                                         modules));
+
+            // API package opened in the original module-info.java
+            extraFiles.opens.entrySet()
+                .stream()
+                .filter(e -> opens.containsKey(e.getKey()) &&
+                                e.getValue().filter(modules))
+                .forEach(e -> mergeExportsOrOpens(opens.get(e.getKey()),
+                                                  e.getValue(),
+                                                  modules));
+
+            // add opens that are not defined in the original module-info.java
+            extraFiles.opens.entrySet()
+                .stream()
+                .filter(e -> !opens.containsKey(e.getKey()) &&
+                                e.getValue().filter(modules))
+                .forEach(e -> addTargets(getStatement("opens", e.getKey()),
+                                         e.getValue(),
+                                         modules));
+
+            // provides
+            extraFiles.provides.keySet()
+                .stream()
+                .filter(service -> provides.containsKey(service))
+                .forEach(service -> mergeProvides(service,
+                                                  extraFiles.provides.get(service)));
+            extraFiles.provides.keySet()
+                .stream()
+                .filter(service -> !provides.containsKey(service))
+                .forEach(service -> provides.put(service,
+                                                 extraFiles.provides.get(service)));
+
+            // uses
+            extraFiles.uses.keySet()
+                .stream()
+                .filter(service -> !uses.containsKey(service))
+                .forEach(service -> uses.put(service, extraFiles.uses.get(service)));
+        }
+
+        // add qualified exports or opens to known modules only
+        private void addTargets(Statement statement,
+                                Statement extra,
+                                Set<String> modules)
+        {
+            extra.targets.stream()
+                 .filter(mn -> modules.contains(mn))
+                 .forEach(mn -> statement.addTarget(mn));
+        }
+
+        private void mergeExportsOrOpens(Statement statement,
+                                         Statement extra,
+                                         Set<String> modules)
+        {
+            String pn = statement.name;
+            if (statement.isUnqualified() && extra.isQualified()) {
+                throw new RuntimeException("can't add qualified exports to " +
+                    "unqualified exports " + pn);
+            }
+
+            Set<String> mods = extra.targets.stream()
+                .filter(mn -> statement.targets.contains(mn))
+                .collect(toSet());
+            if (mods.size() > 0) {
+                throw new RuntimeException("qualified exports " + pn + " to " +
+                    mods.toString() + " already declared in " + sourceFile);
+            }
+
+            // add qualified exports or opens to known modules only
+            addTargets(statement, extra, modules);
+        }
+
+        private void mergeProvides(String service, Statement extra) {
+            Statement statement = provides.get(service);
 
-        List<String> lines = Files.readAllLines(sourcefile);
-        try (BufferedWriter bw = Files.newBufferedWriter(outfile);
-             PrintWriter writer = new PrintWriter(bw)) {
-            int lineNumber = 0;
-            for (String l : lines) {
-                lineNumber++;
-                String[] s = l.trim().split("\\s+");
-                String keyword = s[0].trim();
-                int nextIndex = keyword.length();
-                String exp = null;
-                int n = l.length();
-                switch (keyword) {
-                    case "exports":
-                        boolean inExportsTo = false;
-                        // assume package name immediately after exports
-                        exp = s[1].trim();
-                        if (s.length >= 3) {
-                            nextIndex = l.indexOf(exp, nextIndex) + exp.length();
-                            if (s[2].trim().equals("to")) {
-                                inExportsTo = true;
-                                n = l.indexOf("to", nextIndex) + "to".length();
-                            } else {
+            Set<String> mods = extra.targets.stream()
+                .filter(mn -> statement.targets.contains(mn))
+                .collect(toSet());
+
+            if (mods.size() > 0) {
+                throw new RuntimeException("qualified exports " + service + " to " +
+                    mods.toString() + " already declared in " + sourceFile);
+            }
+
+            extra.targets.stream()
+                 .forEach(mn -> statement.addTarget(mn));
+        }
+
+
+        void print(PrintWriter writer) {
+            // print unqualified exports
+            exports.entrySet().stream()
+                .filter(e -> e.getValue().targets.isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+
+            // print qualified exports
+            exports.entrySet().stream()
+                .filter(e -> !e.getValue().targets.isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+
+            // print unqualified opens
+            opens.entrySet().stream()
+                .filter(e -> e.getValue().targets.isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+
+            // print qualified opens
+            opens.entrySet().stream()
+                .filter(e -> !e.getValue().targets.isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+
+            // uses and provides
+            writer.println();
+            uses.entrySet().stream()
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+            provides.entrySet().stream()
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(e -> writer.println(e.getValue()));
+        }
+
+        private void parse(Path sourcefile) throws IOException {
+            List<String> lines = Files.readAllLines(sourcefile);
+            Statement statement = null;
+            boolean hasTargets = false;
+
+            for (int lineNumber = 1; lineNumber <= lines.size(); ) {
+                String l = lines.get(lineNumber-1).trim();
+                int index = 0;
+
+                if (l.isEmpty()) {
+                    lineNumber++;
+                    continue;
+                }
+
+                // comment block starts
+                if (l.startsWith("/*")) {
+                    while (l.indexOf("*/") == -1) { // end comment block
+                        l = lines.get(lineNumber++).trim();
+                    }
+                    index = l.indexOf("*/") + 2;
+                    if (index >= l.length()) {
+                        lineNumber++;
+                        continue;
+                    } else {
+                        // rest of the line
+                        l = l.substring(index, l.length()).trim();
+                        index = 0;
+                    }
+                }
+
+                // skip comment and annotations
+                if (l.startsWith("//") || l.startsWith("@")) {
+                    lineNumber++;
+                    continue;
+                }
+
+                int current = lineNumber;
+                int count = 0;
+                while (index < l.length()) {
+                    if (current == lineNumber && ++count > 20)
+                        throw new Error("Fail to parse line " + lineNumber + " " + sourcefile);
+
+                    int end = l.indexOf(';');
+                    if (end == -1)
+                        end = l.length();
+                    String content = l.substring(0, end).trim();
+                    if (content.isEmpty()) {
+                        index = end+1;
+                        if (index < l.length()) {
+                            // rest of the line
+                            l = l.substring(index, l.length()).trim();
+                            index = 0;
+                        }
+                        continue;
+                    }
+
+                    String[] s = content.split("\\s+");
+                    String keyword = s[0].trim();
+
+                    String name = s.length > 1 ? s[1].trim() : null;
+                    trace("%d: %s index=%d len=%d%n", lineNumber, l, index, l.length());
+                    switch (keyword) {
+                        case "module":
+                        case "requires":
+                        case "}":
+                            index = l.length();  // skip to the end
+                            continue;
+
+                        case "exports":
+                        case "opens":
+                        case "provides":
+                        case "uses":
+                            // assume name immediately after exports, opens, provides, uses
+                            statement = getStatement(keyword, name);
+                            hasTargets = false;
+
+                            int i = l.indexOf(name, keyword.length()+1) + name.length() + 1;
+                            l = i < l.length() ? l.substring(i, l.length()).trim() : "";
+                            index = 0;
+
+                            if (s.length >= 3) {
+                                if (!s[2].trim().equals(statement.qualifier)) {
+                                    throw new RuntimeException(sourcefile + ", line " +
+                                        lineNumber + ", is malformed: " + s[2]);
+                                }
+                            }
+
+                            break;
+
+                        case "to":
+                        case "with":
+                            if (statement == null) {
                                 throw new RuntimeException(sourcefile + ", line " +
-                                    lineNumber + ", is malformed: " + s[2]);
+                                    lineNumber + ", is malformed");
                             }
-                        }
+
+                            hasTargets = true;
+                            String qualifier = statement.qualifier;
+                            i = l.indexOf(qualifier, index) + qualifier.length() + 1;
+                            l = i < l.length() ? l.substring(i, l.length()).trim() : "";
+                            index = 0;
+                            break;
+                    }
 
-                        // inject the extra targets after "to"
-                        if (inExportsTo) {
-                            writer.println(injectExportTargets(exp, l, n));
+                    if (index >= l.length()) {
+                        // skip to next line
+                        continue;
+                    }
+
+                        // comment block starts
+                    if (l.startsWith("/*")) {
+                        while (l.indexOf("*/") == -1) { // end comment block
+                            l = lines.get(lineNumber++).trim();
+                        }
+                        index = l.indexOf("*/") + 2;
+                        if (index >= l.length()) {
+                            continue;
                         } else {
-                            writer.println(l);
+                            // rest of the line
+                            l = l.substring(index, l.length()).trim();
+                            index = 0;
                         }
-                        break;
-                    case "to":
-                        if (exp == null) {
-                            throw new RuntimeException(sourcefile + ", line " +
-                                lineNumber + ", is malformed");
-                        }
-                        n = l.indexOf("to", nextIndex) + "to".length();
-                        writer.println(injectExportTargets(exp, l, n));
-                        break;
-                    case "}":
-                        doAugments(writer);
-                        // fall through
-                    default:
-                        writer.println(l);
-                        // reset exports
-                        exp = null;
+                    }
+
+                    if (l.startsWith("//")) {
+                        index = l.length();
+                        continue;
+                    }
+
+                    if (statement == null) {
+                        throw new RuntimeException(sourcefile + ", line " +
+                            lineNumber + ": missing keyword?");
+                    }
+
+                    if (!hasTargets) {
+                        continue;
+                    }
+
+                    if (index >= l.length()) {
+                        throw new RuntimeException(sourcefile + ", line " +
+                            lineNumber + ": " + l);
+                    }
+
+                    // parse the target module of exports, opens, or provides
+                    Statement stmt = statement;
+
+                    int terminal = l.indexOf(';', index);
+                    // determine up to which position to parse
+                    int pos = terminal != -1 ? terminal : l.length();
+                    // parse up to comments
+                    int pos1 = l.indexOf("//", index);
+                    if (pos1 != -1 && pos1 < pos) {
+                        pos = pos1;
+                    }
+                    int pos2 = l.indexOf("/*", index);
+                    if (pos2 != -1 && pos2 < pos) {
+                        pos = pos2;
+                    }
+                    // target module(s) for qualitifed exports or opens
+                    // or provider implementation class(es)
+                    String rhs = l.substring(index, pos).trim();
+                    index += rhs.length();
+                    trace("rhs: index=%d [%s] [line: %s]%n", index, rhs, l);
+
+                    String[] targets = rhs.split(",");
+                    for (String t : targets) {
+                        String n = t.trim();
+                        if (n.length() > 0)
+                            stmt.addTarget(n);
+                    }
+
+                    // start next statement
+                    if (pos == terminal) {
+                        statement = null;
+                        hasTargets = false;
+                        index = terminal + 1;
+                    }
+                    l = index < l.length() ? l.substring(index, l.length()).trim() : "";
+                    index = 0;
                 }
+
+                lineNumber++;
             }
         }
     }
 
-    private String injectExportTargets(String pn, String exp, int pos) {
-        Set<String> targets = exportsTo.remove(pn);
-        if (targets != null) {
-            StringBuilder sb = new StringBuilder();
-            // inject the extra targets after the given pos
-            sb.append(exp.substring(0, pos))
-              .append("\n\t")
-              .append(targets.stream()
-                             .collect(Collectors.joining(",", "", ",")))
-              .append(" /* injected */");
-            if (pos < exp.length()) {
-                // print the remaining statement followed "to"
-                sb.append("\n\t")
-                  .append(exp.substring(pos+1, exp.length()));
+    static class Statement {
+        final String directive;
+        final String qualifier;
+        final String name;
+        final Set<String> targets = new LinkedHashSet<>();
+        final boolean ordered;
+
+        Statement(String directive, String qualifier, String name) {
+            this(directive, qualifier, name, false);
+        }
+
+        Statement(String directive, String qualifier, String name, boolean ordered) {
+            this.directive = directive;
+            this.qualifier = qualifier;
+            this.name = name;
+            this.ordered = ordered;
+        }
+
+        Statement addTarget(String mn) {
+            if (mn.isEmpty())
+                throw new IllegalArgumentException("empty module name");
+            targets.add(mn);
+            return this;
+        }
+
+        boolean isQualified() {
+            return targets.size() > 0;
+        }
+
+        boolean isUnqualified() {
+            return targets.isEmpty();
+        }
+
+        /**
+         * Returns true if this statement is unqualified or it has
+         * at least one target in the given names.
+         */
+        boolean filter(Set<String> names) {
+            if (isUnqualified()) {
+                return true;
+            } else {
+                return targets.stream()
+                    .filter(mn -> names.contains(mn))
+                    .findAny().isPresent();
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("    ");
+            sb.append(directive).append(" ").append(name);
+            if (targets.isEmpty()) {
+                sb.append(";");
+            } else if (targets.size() == 1) {
+                sb.append(" ").append(qualifier)
+                  .append(orderedTargets().collect(joining(",", " ", ";")));
+            } else {
+                sb.append(" ").append(qualifier)
+                  .append(orderedTargets()
+                      .map(target -> String.format("        %s", target))
+                      .collect(joining(",\n", "\n", ";")));
             }
             return sb.toString();
-        } else {
-            return exp;
+        }
+
+        public Stream<String> orderedTargets() {
+            return ordered ? targets.stream()
+                           : targets.stream().sorted();
         }
     }
 
-    private void doAugments(PrintWriter writer) {
-        if ((exports.size() + exportsTo.size() + uses.size() + provides.size()) == 0)
-            return;
-
-        writer.println("    // augmented from module-info.java.extra");
-        exports.stream()
-            .sorted()
-            .forEach(e -> writer.format("    exports %s;%n", e));
-        // remaining injected qualified exports
-        exportsTo.entrySet().stream()
-            .sorted(Map.Entry.comparingByKey())
-            .map(e -> String.format("    exports %s to%n%s;", e.getKey(),
-                                    e.getValue().stream().sorted()
-                                        .map(mn -> String.format("        %s", mn))
-                                        .collect(Collectors.joining(",\n"))))
-            .forEach(writer::println);
-        uses.stream().sorted()
-            .forEach(s -> writer.format("    uses %s;%n", s));
-        provides.entrySet().stream()
-            .sorted(Map.Entry.comparingByKey())
-            .flatMap(e -> e.getValue().stream().sorted()
-                           .map(impl -> String.format("    provides %s with %s;",
-                                                      e.getKey(), impl)))
-            .forEach(writer::println);
+    static void trace(String fmt, Object... params) {
+        if (verbose) {
+            System.out.format(fmt, params);
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/src/classes/build/tools/module/ModuleInfoExtraTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,243 @@
+/*
+ * 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 build.tools.module;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import build.tools.module.GenModuleInfoSource.Statement;
+
+/**
+ * Sanity test for GenModuleInfoSource tool
+ */
+public class ModuleInfoExtraTest {
+    private static final Path DIR = Paths.get("test");
+    public static void main(String... args) throws Exception {
+        if (args.length != 0)
+            GenModuleInfoSource.verbose = true;
+
+        ModuleInfoExtraTest test = new ModuleInfoExtraTest("m", "m1", "m2", "m3");
+        test.run();
+    }
+
+    String[] moduleInfo = new String[] {
+        "exports p",
+        "to",
+        "   // comment",
+        "   /* comment */ m1",
+        ",",
+        "m2,m3",
+        "   ;",
+        "exports q to m1;",
+        "provides s with /* ",
+        "  comment */ impl     ;    // comment",
+        "provides s1",
+        "    with  ",
+        "    impl1, impl2;"
+    };
+
+    String[] moduleInfoExtra = new String[] {
+        "exports q",
+        "to",
+        "   m2 // comment",
+        "   /* comment */;",
+        "   ;",
+        "opens p.q ",
+        "   to /* comment */ m3",
+        "   , // m1",
+        "   /* comment */, m4;",
+        "provides s1 with impl3;"
+    };
+
+    String[] test1 = new String[] {
+        "exports p1 to m1;",
+        "exports p2"
+    };
+
+    String[] test2 = new String[] {
+        "exports to m1;"
+    };
+
+    String[] test3 = new String[]{
+        "exports p3 to m1;",
+        "    m2, m3;"
+    };
+
+    String[] test4 = new String[]{
+        "provides s with impl1;",   // typo ; should be ,
+        "   impl2, impl3;"
+    };
+
+    String[] test5 = new String[]{
+        "uses s3",
+        "provides s3 with impl1,",
+        "   impl2, impl3;"
+    };
+
+    final Builder builder;
+    ModuleInfoExtraTest(String name, String... modules) {
+        this.builder = new Builder(name).modules(modules);
+    }
+
+    void run() throws IOException {
+        testModuleInfo();
+        errorCases();
+    }
+
+
+    void testModuleInfo() throws IOException {
+        GenModuleInfoSource source = builder.sourceFile(moduleInfo).build();
+        Set<String> targetsP = new HashSet<>();
+        targetsP.add("m1");
+        targetsP.add("m2");
+        targetsP.add("m3");
+
+        Set<String> targetsQ = new HashSet<>();
+        targetsQ.add("m1");
+
+        Set<String> providerS = new HashSet<>();
+        providerS.add("impl");
+
+        Set<String> providerS1 = new HashSet<>();
+        providerS1.add("impl1");
+        providerS1.add("impl2");
+
+        Set<String> opensPQ = new HashSet<>();
+
+        check(source, targetsP, targetsQ, opensPQ, providerS, providerS1);
+
+        // augment with extra
+        Path file = DIR.resolve("extra");
+        Files.write(file, Arrays.asList(moduleInfoExtra));
+        source = builder.build(file);
+
+        targetsQ.add("m2");
+        providerS1.add("impl3");
+
+        opensPQ.add("m3");
+        check(source, targetsP, targetsQ, opensPQ, providerS, providerS1);
+    }
+
+    void check(GenModuleInfoSource source,
+               Set<String> targetsP,
+               Set<String> targetsQ,
+               Set<String> opensPQ,
+               Set<String> providerS,
+               Set<String> providerS1) {
+        source.moduleInfo.print(new PrintWriter(System.out, true));
+        Statement export = source.moduleInfo.exports.get("p");
+        if (!export.targets.equals(targetsP)) {
+            throw new Error("unexpected: " + export);
+        }
+
+        export = source.moduleInfo.exports.get("q");
+        if (!export.targets.equals(targetsQ)) {
+            throw new Error("unexpected: " + export);
+        }
+
+        Statement provides = source.moduleInfo.provides.get("s");
+        if (!provides.targets.equals(providerS)) {
+            throw new Error("unexpected: " + provides);
+        }
+
+        provides = source.moduleInfo.provides.get("s1");
+        if (!provides.targets.equals(providerS1)) {
+            throw new Error("unexpected: " + provides);
+        }
+    }
+
+
+
+    void errorCases() throws IOException {
+        fail(test1);
+        fail(test2);
+        fail(test3);
+        fail(test4);
+        fail(test5);
+    }
+
+    void fail(String... extras) throws IOException {
+        Path file = DIR.resolve("test1");
+        Files.write(file, Arrays.asList(extras));
+        try {
+            builder.build(file);
+        } catch (RuntimeException e) {
+            if (!e.getMessage().matches("test/test1, line .* is malformed.*") &&
+                !e.getMessage().matches("test/test1, line .* missing keyword.*")) {
+                throw e;
+            }
+        }
+    }
+
+    static class Builder {
+        final String moduleName;
+        final Path sourceFile;
+        final Set<String> modules = new HashSet<>();
+        public Builder(String name) {
+            this.moduleName = name;
+            this.sourceFile = DIR.resolve(name).resolve("module-info.java");
+        }
+
+        public Builder modules(String... names) {
+            Arrays.stream(names).forEach(modules::add);
+            return this;
+        }
+
+        public Builder sourceFile(String... lines) throws IOException {
+            Files.createDirectories(sourceFile.getParent());
+            try (BufferedWriter bw = Files.newBufferedWriter(sourceFile);
+                 PrintWriter writer = new PrintWriter(bw)) {
+                writer.format("module %s {%n", moduleName);
+                for (String l : lines) {
+                    writer.println(l);
+                }
+                writer.println("}");
+            }
+            return this;
+        }
+
+        public GenModuleInfoSource build() throws IOException {
+            return build(Collections.emptyList());
+        }
+
+        public GenModuleInfoSource build(Path extraFile) throws IOException {
+            return build(Collections.singletonList(extraFile));
+        }
+
+        public GenModuleInfoSource build(List<Path> extraFiles) throws IOException {
+            return new GenModuleInfoSource(sourceFile, extraFiles, modules);
+        }
+    }
+
+}
--- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -15,12 +15,12 @@
 pack.class.attribute.CompilationID = RUH
 
 # Module attributes, supported by the tool and not JSR-200
-pack.class.attribute.Module = NH[RUHFH]NH[RUHNH[RUH]]NH[RCH]NH[RCHRCH]
-pack.class.attribute.ConcealedPackages = NH[RUH]
-pack.class.attribute.Version = RUH
-pack.class.attribute.MainClass = RCH
-pack.class.attribute.TargetPlatform = RUHRUHRUH
-pack.class.attribute.Hashes = RUHNH[RUHRUH]
+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.
--- a/jdk/src/java.base/share/classes/java/io/FilePermission.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/io/FilePermission.java	Thu Dec 01 21:39:49 2016 +0000
@@ -216,19 +216,28 @@
             GetPropertyAction.privilegedGetProperty("user.dir"));
 
     /**
-     * A private constructor like a clone, only npath2 is not touched.
+     * A private constructor that clones some and updates some,
+     * always with a different name.
      * @param input
      */
-    private FilePermission(String name, FilePermission input) {
+    private FilePermission(String name,
+                           FilePermission input,
+                           Path npath,
+                           Path npath2,
+                           int mask,
+                           String actions) {
         super(name);
-        this.npath = input.npath;
-        this.actions = input.actions;
+        // Customizables
+        this.npath = npath;
+        this.npath2 = npath2;
+        this.actions = actions;
+        this.mask = mask;
+        // Cloneds
         this.allFiles = input.allFiles;
         this.invalid = input.invalid;
         this.recursive = input.recursive;
         this.directory = input.directory;
         this.cpath = input.cpath;
-        this.mask = input.mask;
     }
 
     /**
@@ -261,10 +270,12 @@
                             // different than the original so that when one is
                             // added to a FilePermissionCollection it will not
                             // be merged with the original one.
-                            FilePermission np = new FilePermission(
-                                    input.getName()+"#plus", input);
-                            np.npath2 = npath2;
-                            return np;
+                            return new FilePermission(input.getName() + "#plus",
+                                    input,
+                                    input.npath,
+                                    npath2,
+                                    input.mask,
+                                    input.actions);
                         }
                     }
                     return input;
@@ -274,10 +285,12 @@
                         Path npath2 = altPath(input.npath);
                         if (npath2 != null) {
                             // New name, see above.
-                            FilePermission np = new FilePermission(
-                                    input.getName()+"#using", input);
-                            np.npath = npath2;
-                            return np;
+                            return new FilePermission(input.getName() + "#using",
+                                    input,
+                                    npath2,
+                                    null,
+                                    input.mask,
+                                    input.actions);
                         }
                     }
                     return null;
@@ -981,6 +994,20 @@
         s.defaultReadObject();
         init(getMask(actions));
     }
+
+    /**
+     * Create a cloned FilePermission with a different actions.
+     * @param effective the new actions
+     * @return a new object
+     */
+    FilePermission withNewActions(int effective) {
+        return new FilePermission(this.getName(),
+                this,
+                this.npath,
+                this.npath2,
+                effective,
+                null);
+    }
 }
 
 /**
@@ -1048,8 +1075,7 @@
         FilePermission fp = (FilePermission)permission;
 
         // Add permission to map if it is absent, or replace with new
-        // permission if applicable. NOTE: cannot use lambda for
-        // remappingFunction parameter until JDK-8076596 is fixed.
+        // permission if applicable.
         perms.merge(fp.getName(), fp,
             new java.util.function.BiFunction<>() {
                 @Override
@@ -1063,7 +1089,8 @@
                             return newVal;
                         }
                         if (effective != oldMask) {
-                            return new FilePermission(fp.getName(), effective);
+                            return ((FilePermission)newVal)
+                                    .withNewActions(effective);
                         }
                     }
                     return existingVal;
--- a/jdk/src/java.base/share/classes/java/lang/Class.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,46 +26,55 @@
 package java.lang;
 
 import java.lang.annotation.Annotation;
+import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReader;
-import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Array;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.GenericDeclaration;
-import java.lang.reflect.Member;
-import java.lang.reflect.Field;
-import java.lang.reflect.Executable;
-import java.lang.reflect.Method;
-import java.lang.reflect.Module;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.AnnotatedType;
-import java.lang.reflect.Proxy;
 import java.lang.ref.SoftReference;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.ObjectStreamField;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.AnnotatedType;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Objects;
 import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
 import jdk.internal.HotSpotIntrinsicCandidate;
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;
+import jdk.internal.loader.ResourceHelper;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.Unsafe;
 import jdk.internal.misc.VM;
+import jdk.internal.module.ModuleHashes;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.ConstantPool;
 import jdk.internal.reflect.Reflection;
@@ -442,21 +451,10 @@
 
         PrivilegedAction<ClassLoader> pa = module::getClassLoader;
         ClassLoader cl = AccessController.doPrivileged(pa);
-        if (module.isNamed() && cl != null) {
-            return cl.loadLocalClass(module, name);
-        }
-
-        final Class<?> c;
         if (cl != null) {
-            c = cl.loadLocalClass(name);
+            return cl.loadClass(module, name);
         } else {
-            c = BootLoader.loadClassOrNull(name);
-        }
-
-        if (c != null && c.getModule() == module) {
-            return c;
-        } else {
-            return null;
+            return BootLoader.loadClass(module, name);
         }
     }
 
@@ -979,7 +977,7 @@
     }
 
     // cached package name
-    private String packageName;
+    private transient String packageName;
 
     /**
      * Returns the interfaces directly implemented by the class or interface
@@ -1976,6 +1974,22 @@
         return method;
     }
 
+    /**
+     * Returns a {@code Method} object that reflects the specified public
+     * member method of the class or interface represented by this
+     * {@code Class} object.
+     *
+     * @param name the name of the method
+     * @param parameterTypes the list of parameters
+     * @return the {@code Method} object that matches the specified
+     *         {@code name} and {@code parameterTypes}; {@code null}
+     *         if the method is not found or the name is
+     *         "&lt;init&gt;"or "&lt;clinit&gt;".
+     */
+    Method getMethodOrNull(String name, Class<?>... parameterTypes) {
+        return getMethod0(name, parameterTypes, true);
+    }
+
 
     /**
      * Returns a {@code Constructor} object that reflects the specified
@@ -2367,12 +2381,17 @@
     }
 
     /**
-     * Finds a resource with a given name. If this class is in a named {@link
-     * Module Module}, and the caller of this method is in the same module,
-     * then this method will attempt to find the resource in that module.
-     * Otherwise, the rules for searching resources
-     * associated with a given class are implemented by the defining
-     * {@linkplain ClassLoader class loader} of the class.  This method
+     * Finds a resource with a given name.
+     *
+     * <p> If this class is in a named {@link Module Module} then this method
+     * will attempt to find the resource in the module by means of the absolute
+     * resource name, subject to the rules for encapsulation specified in the
+     * {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
+     * method.
+     *
+     * <p> Otherwise, if this class is not in a named module then the rules for
+     * searching resources associated with a given class are implemented by the
+     * defining {@linkplain ClassLoader class loader} of the class.  This method
      * delegates to this object's class loader.  If this object was loaded by
      * the bootstrap class loader, the method delegates to {@link
      * ClassLoader#getSystemResourceAsStream}.
@@ -2400,8 +2419,11 @@
      * </ul>
      *
      * @param  name name of the desired resource
-     * @return  A {@link java.io.InputStream} object or {@code null} if
-     *          no resource with this name is found
+     * @return  A {@link java.io.InputStream} object; {@code null} if no
+     *          resource with this name is found, the resource is in a package
+     *          that is not {@link Module#isOpen(String, Module) open} to at
+     *          least the caller module, or access to the resource is denied
+     *          by the security manager.
      * @throws  NullPointerException If {@code name} is {@code null}
      * @since  1.1
      */
@@ -2409,35 +2431,41 @@
     public InputStream getResourceAsStream(String name) {
         name = resolveName(name);
 
-        // if this Class and the caller are in the same named module
-        // then attempt to get an input stream to the resource in the
-        // module
         Module module = getModule();
         if (module.isNamed()) {
-            Class<?> caller = Reflection.getCallerClass();
-            if (caller != null && caller.getModule() == module) {
-                ClassLoader cl = getClassLoader0();
-                String mn = module.getName();
-                try {
-
-                    // special-case built-in class loaders to avoid the
-                    // need for a URL connection
-                    if (cl == null) {
-                        return BootLoader.findResourceAsStream(mn, name);
-                    } else if (cl instanceof BuiltinClassLoader) {
-                        return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name);
-                    } else {
-                        URL url = cl.findResource(mn, name);
-                        return (url != null) ? url.openStream() : null;
+            if (!ResourceHelper.isSimpleResource(name)) {
+                Module caller = Reflection.getCallerClass().getModule();
+                if (caller != module) {
+                    Set<String> packages = module.getDescriptor().packages();
+                    String pn = ResourceHelper.getPackageName(name);
+                    if (packages.contains(pn) && !module.isOpen(pn, caller)) {
+                        // resource is in package not open to caller
+                        return null;
                     }
-
-                } catch (IOException | SecurityException e) {
-                    return null;
                 }
             }
+
+            String mn = module.getName();
+            ClassLoader cl = getClassLoader0();
+            try {
+
+                // special-case built-in class loaders to avoid the
+                // need for a URL connection
+                if (cl == null) {
+                    return BootLoader.findResourceAsStream(mn, name);
+                } else if (cl instanceof BuiltinClassLoader) {
+                    return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name);
+                } else {
+                    URL url = cl.findResource(mn, name);
+                    return (url != null) ? url.openStream() : null;
+                }
+
+            } catch (IOException | SecurityException e) {
+                return null;
+            }
         }
 
-        // this Class and caller not in the same named module
+        // unnamed module
         ClassLoader cl = getClassLoader0();
         if (cl == null) {
             return ClassLoader.getSystemResourceAsStream(name);
@@ -2447,12 +2475,17 @@
     }
 
     /**
-     * Finds a resource with a given name. If this class is in a named {@link
-     * Module Module}, and the caller of this method is in the same module,
-     * then this method will attempt to find the resource in that module.
-     * Otherwise, the rules for searching resources
-     * associated with a given class are implemented by the defining
-     * {@linkplain ClassLoader class loader} of the class.  This method
+     * Finds a resource with a given name.
+     *
+     * <p> If this class is in a named {@link Module Module} then this method
+     * will attempt to find the resource in the module by means of the absolute
+     * resource name, subject to the rules for encapsulation specified in the
+     * {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
+     * method.
+     *
+     * <p> Otherwise, if this class is not in a named module then the rules for
+     * searching resources associated with a given class are implemented by the
+     * defining {@linkplain ClassLoader class loader} of the class.  This method
      * delegates to this object's class loader. If this object was loaded by
      * the bootstrap class loader, the method delegates to {@link
      * ClassLoader#getSystemResource}.
@@ -2479,35 +2512,46 @@
      * </ul>
      *
      * @param  name name of the desired resource
-     * @return A {@link java.net.URL} object; {@code null} if no
-     *         resource with this name is found or the resource cannot
-     *         be located by a URL.
+     * @return A {@link java.net.URL} object; {@code null} if no resource with
+     *         this name is found, the resource cannot be located by a URL, the
+     *         resource is in a package that is not
+     *         {@link Module#isOpen(String, Module) open} to at least the caller
+     *         module, or access to the resource is denied by the security
+     *         manager.
+     * @throws NullPointerException If {@code name} is {@code null}
      * @since  1.1
      */
     @CallerSensitive
     public URL getResource(String name) {
         name = resolveName(name);
 
-        // if this Class and the caller are in the same named module
-        // then attempt to get URL to the resource in the module
         Module module = getModule();
         if (module.isNamed()) {
-            Class<?> caller = Reflection.getCallerClass();
-            if (caller != null && caller.getModule() == module) {
-                String mn = getModule().getName();
-                ClassLoader cl = getClassLoader0();
-                try {
-                    if (cl == null) {
-                        return BootLoader.findResource(mn, name);
-                    } else {
-                        return cl.findResource(mn, name);
+            if (!ResourceHelper.isSimpleResource(name)) {
+                Module caller = Reflection.getCallerClass().getModule();
+                if (caller != module) {
+                    Set<String> packages = module.getDescriptor().packages();
+                    String pn = ResourceHelper.getPackageName(name);
+                    if (packages.contains(pn) && !module.isOpen(pn, caller)) {
+                        // resource is in package not open to caller
+                        return null;
                     }
-                } catch (IOException ioe) {
-                    return null;
                 }
             }
+            String mn = getModule().getName();
+            ClassLoader cl = getClassLoader0();
+            try {
+                if (cl == null) {
+                    return BootLoader.findResource(mn, name);
+                } else {
+                    return cl.findResource(mn, name);
+                }
+            } catch (IOException ioe) {
+                return null;
+            }
         }
 
+        // unnamed module
         ClassLoader cl = getClassLoader0();
         if (cl == null) {
             return ClassLoader.getSystemResource(name);
@@ -2632,9 +2676,6 @@
      * if name is absolute
      */
     private String resolveName(String name) {
-        if (name == null) {
-            return name;
-        }
         if (!name.startsWith("/")) {
             Class<?> c = this;
             while (c.isArray()) {
--- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java	Thu Dec 01 21:39:49 2016 +0000
@@ -42,15 +42,14 @@
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Set;
 import java.util.Spliterator;
 import java.util.Spliterators;
 import java.util.Stack;
-import java.util.NoSuchElementException;
 import java.util.Vector;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
@@ -59,7 +58,6 @@
 import java.util.stream.StreamSupport;
 
 import jdk.internal.perf.PerfCounter;
-import jdk.internal.module.ServicesCatalog;
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.ClassLoaders;
 import jdk.internal.misc.SharedSecrets;
@@ -411,7 +409,6 @@
         this(checkCreateClassLoader(), null, parent);
     }
 
-
     /**
      * Creates a new class loader using the <tt>ClassLoader</tt> returned by
      * the method {@link #getSystemClassLoader()
@@ -431,7 +428,6 @@
         this(checkCreateClassLoader(), null, getSystemClassLoader());
     }
 
-
     /**
      * Returns the name of this class loader or {@code null} if
      * this class loader is not named.
@@ -581,7 +577,7 @@
      * @return The resulting {@code Class} object in a module defined by
      *         this class loader, or {@code null} if the class could not be found.
      */
-    final Class<?> loadLocalClass(Module module, String name) {
+    final Class<?> loadClass(Module module, String name) {
         synchronized (getClassLoadingLock(name)) {
             // First, check if the class has already been loaded
             Class<?> c = findLoadedClass(name);
@@ -597,34 +593,6 @@
     }
 
     /**
-     * Loads the class with the specified <a href="#name">binary name</a>
-     * defined by this class loader.  This method returns {@code null}
-     * if the class could not be found.
-     *
-     * @apiNote This method does not delegate to the parent class loader.
-     *
-     * @param  name
-     *         The <a href="#name">binary name</a> of the class
-     *
-     * @return The resulting {@code Class} object in a module defined by
-     *         this class loader, or {@code null} if the class could not be found.
-     */
-    final Class<?> loadLocalClass(String name) {
-        synchronized (getClassLoadingLock(name)) {
-            // First, check if the class has already been loaded
-            Class<?> c = findLoadedClass(name);
-            if (c == null) {
-                try {
-                    return findClass(name);
-                } catch (ClassNotFoundException e) {
-                    // ignore
-                }
-            }
-            return c;
-        }
-    }
-
-    /**
      * Returns the lock object for class loading operations.
      * For backward compatibility, the default implementation of this method
      * behaves as follows. If this ClassLoader object is registered as
@@ -724,12 +692,17 @@
      * should override this method.
      *
      * @apiNote This method returns {@code null} rather than throwing
-     *          {@code ClassNotFoundException} if the class could not be found
+     *          {@code ClassNotFoundException} if the class could not be found.
      *
-     * @implSpec The default implementation returns {@code null}.
+     * @implSpec The default implementation attempts to find the class by
+     * invoking {@link #findClass(String)} when the {@code moduleName} is
+     * {@code null}. It otherwise returns {@code null}.
      *
      * @param  moduleName
-     *         The module name
+     *         The module name; or {@code null} to find the class in the
+     *         {@linkplain #getUnnamedModule() unnamed module} for this
+     *         class loader
+
      * @param  name
      *         The <a href="#name">binary name</a> of the class
      *
@@ -739,6 +712,11 @@
      * @since 9
      */
     protected Class<?> findClass(String moduleName, String name) {
+        if (moduleName == null) {
+            try {
+                return findClass(name);
+            } catch (ClassNotFoundException ignore) { }
+        }
         return null;
     }
 
@@ -1286,10 +1264,20 @@
      * Class loader implementations that support the loading from modules
      * should override this method.
      *
-     * @implSpec The default implementation returns {@code null}.
+     * @apiNote This method is the basis for the {@code Class} {@link
+     * Class#getResource getResource} and {@link Class#getResourceAsStream
+     * getResourceAsStream} methods. It is not subject to the rules for
+     * encapsulation specified by {@code Module} {@link
+     * Module#getResourceAsStream getResourceAsStream}.
+     *
+     * @implSpec The default implementation attempts to find the resource by
+     * invoking {@link #findResource(String)} when the {@code moduleName} is
+     * {@code null}. It otherwise returns {@code null}.
      *
      * @param  moduleName
-     *         The module name
+     *         The module name; or {@code null} to find a resource in the
+     *         {@linkplain #getUnnamedModule() unnamed module} for this
+     *         class loader
      * @param  name
      *         The resource name
      *
@@ -1306,7 +1294,11 @@
      * @since 9
      */
     protected URL findResource(String moduleName, String name) throws IOException {
-        return null;
+        if (moduleName == null) {
+            return findResource(name);
+        } else {
+            return null;
+        }
     }
 
     /**
@@ -1314,9 +1306,6 @@
      * (images, audio, text, etc) that can be accessed by class code in a way
      * that is independent of the location of the code.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resource in named modules.
-     *
      * <p> The name of a resource is a '<tt>/</tt>'-separated path name that
      * identifies the resource.
      *
@@ -1325,16 +1314,31 @@
      * built-in to the virtual machine is searched.  That failing, this method
      * will invoke {@link #findResource(String)} to find the resource.  </p>
      *
-     * @apiNote When overriding this method it is recommended that an
-     * implementation ensures that any delegation is consistent with the {@link
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally (even if the caller of this method is in the
+     * same module as the resource). </p>
+     *
+     * @apiNote Where several modules are defined to the same class loader,
+     * and where more than one module contains a resource with the given name,
+     * then the ordering that modules are searched is not specified and may be
+     * very unpredictable.
+     * When overriding this method it is recommended that an implementation
+     * ensures that any delegation is consistent with the {@link
      * #getResources(java.lang.String) getResources(String)} method.
      *
      * @param  name
      *         The resource name
      *
-     * @return  A <tt>URL</tt> object for reading the resource, or
-     *          <tt>null</tt> if the resource could not be found or the invoker
-     *          doesn't have adequate  privileges to get the resource.
+     * @return  {@code URL} object for reading the resource; {@code null} if
+     *          the resource could not be found, a {@code URL} could not be
+     *          constructed to locate the resource, the resource is in a package
+     *          that is not opened unconditionally, or access to the resource is
+     *          denied by the security manager.
+     *
      * @throws  NullPointerException If {@code name} is {@code null}
      *
      * @since  1.1
@@ -1358,16 +1362,24 @@
      * (images, audio, text, etc) that can be accessed by class code in a way
      * that is independent of the location of the code.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
-     *
-     * <p>The name of a resource is a <tt>/</tt>-separated path name that
+     * <p> The name of a resource is a <tt>/</tt>-separated path name that
      * identifies the resource.
      *
-     * <p> The search order is described in the documentation for {@link
-     * #getResource(String)}.  </p>
+     * <p> The delegation order for searching is described in the documentation
+     * for {@link #getResource(String)}.  </p>
      *
-     * @apiNote When overriding this method it is recommended that an
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally (even if the caller of this method is in the
+     * same module as the resource).</p>
+     *
+     * @apiNote Where several modules are defined to the same class loader,
+     * and where more than one module contains a resource with the given name,
+     * then the ordering is not specified and may be very unpredictable.
+     * When overriding this method it is recommended that an
      * implementation ensures that any delegation is consistent with the {@link
      * #getResource(java.lang.String) getResource(String)} method. This should
      * ensure that the first element returned by the Enumeration's
@@ -1378,9 +1390,11 @@
      *         The resource name
      *
      * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
-     *          the resource.  If no resources could  be found, the enumeration
-     *          will be empty.  Resources that the class loader doesn't have
-     *          access to will not be in the enumeration.
+     *          the resource. If no resources could  be found, the enumeration
+     *          will be empty. Resources for which a {@code URL} cannot be
+     *          constructed, are in package that is not opened unconditionally,
+     *          or access to the resource is denied by the security manager,
+     *          are not returned in the enumeration.
      *
      * @throws  IOException
      *          If I/O errors occur
@@ -1410,9 +1424,6 @@
      * can be accessed by class code in a way that is independent of the
      * location of the code.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
-     *
      * <p> The name of a resource is a {@code /}-separated path name that
      * identifies the resource.
      *
@@ -1424,6 +1435,14 @@
      * exception is wrapped in an {@link UncheckedIOException} that is then
      * thrown.
      *
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally (even if the caller of this method is in the
+     * same module as the resource). </p>
+     *
      * @apiNote When overriding this method it is recommended that an
      * implementation ensures that any delegation is consistent with the {@link
      * #getResource(java.lang.String) getResource(String)} method. This should
@@ -1434,9 +1453,10 @@
      *         The resource name
      *
      * @return  A stream of resource {@link java.net.URL URL} objects. If no
-     *          resources could  be found, the stream will be empty.  Resources
-     *          that the class loader doesn't have access to will not be in the
-     *          stream.
+     *          resources could  be found, the stream will be empty. Resources
+     *          for which a {@code URL} cannot be constructed, are in a package
+     *          that is not opened unconditionally, or access to the resource
+     *          is denied by the security manager, will not be in the stream.
      *
      * @throws  NullPointerException If {@code name} is {@code null}
      *
@@ -1462,14 +1482,21 @@
      * Finds the resource with the given name. Class loader implementations
      * should override this method to specify where to find resources.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules defined to this class loader.
+     * <p> For resources in named modules then the method must implement the
+     * rules for encapsulation specified in the {@code Module} {@link
+     * Module#getResourceAsStream getResourceAsStream} method. Additionally,
+     * it must not find non-"{@code .class}" resources in packages of named
+     * modules unless the package is {@link Module#isOpen(String) opened}
+     * unconditionally. </p>
      *
      * @param  name
      *         The resource name
      *
-     * @return  A <tt>URL</tt> object for reading the resource, or
-     *          <tt>null</tt> if the resource could not be found
+     * @return  {@code URL} object for reading the resource; {@code null} if
+     *          the resource could not be found, a {@code URL} could not be
+     *          constructed to locate the resource, the resource is in a package
+     *          that is not opened unconditionally, or access to the resource is
+     *          denied by the security manager.
      *
      * @since  1.2
      */
@@ -1483,14 +1510,22 @@
      * implementations should override this method to specify where to load
      * resources from.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules defined to this class loader.
+     * <p> For resources in named modules then the method must implement the
+     * rules for encapsulation specified in the {@code Module} {@link
+     * Module#getResourceAsStream getResourceAsStream} method. Additionally,
+     * it must not find non-"{@code .class}" resources in packages of named
+     * modules unless the package is {@link Module#isOpen(String) opened}
+     * unconditionally. </p>
      *
      * @param  name
      *         The resource name
      *
      * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
-     *          the resources
+     *          the resource. If no resources could  be found, the enumeration
+     *          will be empty. Resources for which a {@code URL} cannot be
+     *          constructed, are in a package that is not opened unconditionally,
+     *          or access to the resource is denied by the security manager,
+     *          are not returned in the enumeration.
      *
      * @throws  IOException
      *          If I/O errors occur
@@ -1498,7 +1533,7 @@
      * @since  1.2
      */
     protected Enumeration<URL> findResources(String name) throws IOException {
-        return java.util.Collections.emptyEnumeration();
+        return Collections.emptyEnumeration();
     }
 
     /**
@@ -1549,14 +1584,21 @@
      * classes.  This method locates the resource through the system class
      * loader (see {@link #getSystemClassLoader()}).
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally. </p>
      *
      * @param  name
      *         The resource name
      *
-     * @return  A {@link java.net.URL <tt>URL</tt>} object for reading the
-     *          resource, or <tt>null</tt> if the resource could not be found
+     * @return  A {@link java.net.URL <tt>URL</tt>} to the resource; {@code
+     *          null} if the resource could not be found, a URL could not be
+     *          constructed to locate the resource, the resource is in a package
+     *          that is not opened unconditionally or access to the resource is
+     *          denied by the security manager.
      *
      * @since  1.1
      */
@@ -1570,17 +1612,25 @@
      * {@link java.util.Enumeration <tt>Enumeration</tt>} of {@link
      * java.net.URL <tt>URL</tt>} objects.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
-     *
      * <p> The search order is described in the documentation for {@link
      * #getSystemResource(String)}.  </p>
      *
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally. </p>
+     *
      * @param  name
      *         The resource name
      *
-     * @return  An enumeration of resource {@link java.net.URL <tt>URL</tt>}
-     *          objects
+     * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
+     *          the resource. If no resources could  be found, the enumeration
+     *          will be empty. Resources for which a {@code URL} cannot be
+     *          constructed, are in a package that is not opened unconditionally,
+     *          or access to the resource is denied by the security manager,
+     *          are not returned in the enumeration.
      *
      * @throws  IOException
      *          If I/O errors occur
@@ -1596,17 +1646,24 @@
     /**
      * Returns an input stream for reading the specified resource.
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
-     *
      * <p> The search order is described in the documentation for {@link
      * #getResource(String)}.  </p>
      *
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally. </p>
+     *
      * @param  name
      *         The resource name
      *
-     * @return  An input stream for reading the resource, or <tt>null</tt>
-     *          if the resource could not be found
+     * @return  An input stream for reading the resource; {@code null} if the
+     *          resource could not be found, the resource is in a package that
+     *          is not opened unconditionally, or access to the resource is
+     *          denied by the security manager.
+     *
      * @throws  NullPointerException If {@code name} is {@code null}
      *
      * @since  1.1
@@ -1626,14 +1683,20 @@
      * used to load classes.  This method locates the resource through the
      * system class loader (see {@link #getSystemClassLoader()}).
      *
-     * Resources in a named module are private to that module. This method does
-     * not find resources in named modules.
+     * <p> Resources in named modules are subject to the encapsulation rules
+     * specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     * Additionally, and except for the special case where the resource has a
+     * name ending with "{@code .class}", this method will only find resources in
+     * packages of named modules when the package is {@link Module#isOpen(String)
+     * opened} unconditionally. </p>
      *
      * @param  name
      *         The resource name
      *
-     * @return  An input stream for reading the resource, or <tt>null</tt>
-     *          if the resource could not be found
+     * @return  An input stream for reading the resource; {@code null} if the
+     *          resource could not be found, the resource is in a package that
+     *          is not opened unconditionally, or access to the resource is
+     *          denied by the security manager.
      *
      * @since  1.1
      */
@@ -2719,33 +2782,7 @@
     private static native AssertionStatusDirectives retrieveDirectives();
 
 
-    /**
-     * Returns the ServiceCatalog for modules defined to this class loader
-     * or {@code null} if this class loader does not have a services catalog.
-     */
-    ServicesCatalog getServicesCatalog() {
-        return servicesCatalog;
-    }
-
-    /**
-     * Returns the ServiceCatalog for modules defined to this class loader,
-     * creating it if it doesn't already exist.
-     */
-    ServicesCatalog createOrGetServicesCatalog() {
-        ServicesCatalog catalog = servicesCatalog;
-        if (catalog == null) {
-            catalog = ServicesCatalog.create();
-            boolean set = trySetObjectField("servicesCatalog", catalog);
-            if (!set) {
-                // beaten by someone else
-                catalog = servicesCatalog;
-            }
-        }
-        return catalog;
-    }
-
-    // the ServiceCatalog for modules associated with this class loader.
-    private volatile ServicesCatalog servicesCatalog;
+    // -- Misc --
 
     /**
      * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s)
--- a/jdk/src/java.base/share/classes/java/lang/Deprecated.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/Deprecated.java	Thu Dec 01 21:39:49 2016 +0000
@@ -40,6 +40,11 @@
  * annotation on a local variable declaration or on a parameter declaration
  * or a package declaration has no effect on the warnings issued by a compiler.
  *
+ * <p>When a module is deprecated, the use of that module in {@code
+ * requires}, but not in {@code exports} or {@code opens} clauses causes
+ * a warning to be issued. A module being deprecated does <em>not</em> cause
+ * warnings to be issued for uses of types within the module.
+ *
  * <p>This annotation type has a string-valued element {@code since}. The value
  * of this element indicates the version in which the annotated program element
  * was first deprecated.
@@ -74,7 +79,7 @@
  */
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
+@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
 public @interface Deprecated {
     /**
      * Returns the version in which the annotated element became deprecated.
--- a/jdk/src/java.base/share/classes/java/lang/Iterable.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/Iterable.java	Thu Dec 01 21:39:49 2016 +0000
@@ -53,10 +53,13 @@
     /**
      * Performs the given action for each element of the {@code Iterable}
      * until all elements have been processed or the action throws an
-     * exception.  Unless otherwise specified by the implementing class,
-     * actions are performed in the order of iteration (if an iteration order
-     * is specified).  Exceptions thrown by the action are relayed to the
+     * exception.  Actions are performed in the order of iteration, if that
+     * order is specified.  Exceptions thrown by the action are relayed to the
      * caller.
+     * <p>
+     * The behavior of this method is unspecified if the action performs
+     * side-effects that modify the underlying source of elements, unless an
+     * overriding class has specified a concurrent modification policy.
      *
      * @implSpec
      * <p>The default implementation behaves as if:
--- a/jdk/src/java.base/share/classes/java/lang/Package.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/Package.java	Thu Dec 01 21:39:49 2016 +0000
@@ -398,10 +398,16 @@
         if (packageInfo == null) {
             // find package-info.class defined by loader
             String cn = packageName() + ".package-info";
-            PrivilegedAction<ClassLoader> pa = module()::getClassLoader;
+            Module module = module();
+            PrivilegedAction<ClassLoader> pa = module::getClassLoader;
             ClassLoader loader = AccessController.doPrivileged(pa);
-            Class<?> c = loader != null ? loader.loadLocalClass(cn)
-                                        : BootLoader.loadClassOrNull(cn);
+            Class<?> c;
+            if (loader != null) {
+                c = loader.loadClass(module, cn);
+            } else {
+                c = BootLoader.loadClass(module, cn);
+            }
+
             if (c != null) {
                 packageInfo = c;
             } else {
--- a/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/SuppressWarnings.java	Thu Dec 01 21:39:49 2016 +0000
@@ -35,6 +35,9 @@
  * a superset of the warnings suppressed in all containing elements.  For
  * example, if you annotate a class to suppress one warning and annotate a
  * method to suppress another, both warnings will be suppressed in the method.
+ * However, note that if a warning is suppressed in a {@code
+ * module-info} file, the suppression applies to elements within the
+ * file and <em>not</em> to types contained within the module.
  *
  * <p>As a matter of style, programmers should always use this annotation
  * on the most deeply nested element where it is effective.  If you want to
@@ -49,7 +52,7 @@
  * @jls 5.5.2 Checked Casts and Unchecked Casts
  * @jls 9.6.4.5 @SuppressWarnings
  */
-@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
 @Retention(RetentionPolicy.SOURCE)
 public @interface SuppressWarnings {
     /**
--- a/jdk/src/java.base/share/classes/java/lang/System.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/System.java	Thu Dec 01 21:39:49 2016 +0000
@@ -38,6 +38,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Executable;
 import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Module;
 import java.net.URL;
@@ -69,7 +70,6 @@
 import jdk.internal.logger.LocalizedLoggerWrapper;
 
 import jdk.internal.module.ModuleBootstrap;
-import jdk.internal.module.ServicesCatalog;
 
 /**
  * The <code>System</code> class contains several useful class fields
@@ -1987,7 +1987,10 @@
 
     private static void setJavaLangAccess() {
         // Allow privileged classes outside of java.lang
-        SharedSecrets.setJavaLangAccess(new JavaLangAccess(){
+        SharedSecrets.setJavaLangAccess(new JavaLangAccess() {
+            public Method getMethodOrNull(Class<?> klass, String name, Class<?>... parameterTypes) {
+                return klass.getMethodOrNull(name, parameterTypes);
+            }
             public jdk.internal.reflect.ConstantPool getConstantPool(Class<?> klass) {
                 return klass.getConstantPool();
             }
@@ -2031,12 +2034,6 @@
             public Layer getBootLayer() {
                 return bootLayer;
             }
-            public ServicesCatalog getServicesCatalog(ClassLoader cl) {
-                return cl.getServicesCatalog();
-            }
-            public ServicesCatalog createOrGetServicesCatalog(ClassLoader cl) {
-                return cl.createOrGetServicesCatalog();
-            }
             public ConcurrentHashMap<?, ?> createOrGetClassLoaderValueMap(ClassLoader cl) {
                 return cl.createOrGetClassLoaderValueMap();
             }
--- a/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template	Thu Dec 01 21:39:49 2016 +0000
@@ -123,27 +123,25 @@
 
     /**
      * In case you were wondering this method is called by java -version.
-     * Sad that it prints to stderr; would be nicer if default printed on
-     * stdout.
      */
-    public static void print() {
-        print(System.err);
+    public static void print(boolean err) {
+        print(err, false);
     }
 
     /**
      * This is the same as print except that it adds an extra line-feed
      * at the end, typically used by the -showversion in the launcher
      */
-    public static void println() {
-        print(System.err);
-        System.err.println();
+    public static void println(boolean err) {
+        print(err, true);
     }
 
     /**
-     * Give a stream, it will print version info on it.
+     * Print version info.
      */
-    public static void print(PrintStream ps) {
+    private static void print(boolean err, boolean newln) {
         boolean isHeadless = false;
+        PrintStream ps = err ? System.err : System.out;
 
         /* Report that we're running headless if the property is true */
         String headless = System.getProperty("java.awt.headless");
@@ -152,10 +150,14 @@
         }
 
         /* First line: platform version. */
-        ps.println(launcher_name + " version \"" + java_version + "\"");
+        if (err) {
+            ps.println(launcher_name + " version \"" + java_version + "\"");
+        } else {
+            /* Use a format more in line with GNU conventions */
+            ps.println(launcher_name + " " + java_version);
+        }
 
         /* Second line: runtime version (ie, libraries). */
-
         String jdk_debug_level = System.getProperty("jdk.debug", "release");
         /* Debug level is not printed for "release" builds */
         if ("release".equals(jdk_debug_level)) {
--- a/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/annotation/ElementType.java	Thu Dec 01 21:39:49 2016 +0000
@@ -37,10 +37,10 @@
  * <em>type contexts</em> , where annotations apply to types used in
  * declarations and expressions.
  *
- * <p>The constants {@link #ANNOTATION_TYPE} , {@link #CONSTRUCTOR} , {@link
- * #FIELD} , {@link #LOCAL_VARIABLE} , {@link #METHOD} , {@link #PACKAGE} ,
- * {@link #PARAMETER} , {@link #TYPE} , and {@link #TYPE_PARAMETER} correspond
- * to the declaration contexts in JLS 9.6.4.1.
+ * <p>The constants {@link #ANNOTATION_TYPE}, {@link #CONSTRUCTOR}, {@link
+ * #FIELD}, {@link #LOCAL_VARIABLE}, {@link #METHOD}, {@link #PACKAGE}, {@link
+ * #MODULE}, {@link #PARAMETER}, {@link #TYPE}, and {@link #TYPE_PARAMETER}
+ * correspond to the declaration contexts in JLS 9.6.4.1.
  *
  * <p>For example, an annotation whose type is meta-annotated with
  * {@code @Target(ElementType.FIELD)} may only be written as a modifier for a
@@ -107,5 +107,12 @@
      *
      * @since 1.8
      */
-    TYPE_USE
+    TYPE_USE,
+
+    /**
+     * Module declaration.
+     *
+     * @since 9
+     */
+    MODULE
 }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1147,12 +1147,14 @@
 
         static
         MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) {
-            // Do not use this function to inject calls into system classes.
+            // Code in the the boot layer should now be careful while creating method handles or
+            // functional interface instances created from method references to @CallerSensitive  methods,
+            // it needs to be ensured the handles or interface instances are kept safe and are not passed
+            // from the boot layer to untrusted code.
             if (hostClass == null
                 ||    (hostClass.isArray() ||
                        hostClass.isPrimitive() ||
-                       hostClass.getName().startsWith("java.") ||
-                       hostClass.getName().startsWith("sun."))) {
+                       hostClass.getName().startsWith("java.lang.invoke."))) {
                 throw new InternalError();  // does not happen, and should not anyway
             }
             // For simplicity, convert mh to a varargs-like method.
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Dec 01 21:39:49 2016 +0000
@@ -42,6 +42,7 @@
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
 import java.lang.reflect.ReflectPermission;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
@@ -142,6 +143,59 @@
     }
 
     /**
+     * Returns a {@link Lookup lookup object} with full capabilities to emulate all
+     * supported bytecode behaviors, including <a href="MethodHandles.Lookup.html#privacc">
+     * private access</a>, on a target class.
+     * This method checks that a caller, specified as a {@code Lookup} object, is allowed to
+     * do <em>deep reflection</em> on the target class. If {@code m1} is the module containing
+     * the {@link Lookup#lookupClass() lookup class}, and {@code m2} is the module containing
+     * the target class, then this check ensures that
+     * <ul>
+     *     <li>{@code m1} {@link Module#canRead reads} {@code m2}.</li>
+     *     <li>{@code m2} {@link Module#isOpen(String,Module) opens} the package containing
+     *     the target class to at least {@code m1}.</li>
+     *     <li>The lookup has the {@link Lookup#MODULE MODULE} lookup mode.</li>
+     * </ul>
+     * <p>
+     * If there is a security manager, its {@code checkPermission} method is called to
+     * check {@code ReflectPermission("suppressAccessChecks")}.
+     * @apiNote The {@code MODULE} lookup mode serves to authenticate that the lookup object
+     * was created by code in the caller module (or derived from a lookup object originally
+     * created by the caller). A lookup object with the {@code MODULE} lookup mode can be
+     * shared with trusted parties without giving away {@code PRIVATE} and {@code PACKAGE}
+     * access to the caller.
+     * @param targetClass the target class
+     * @param lookup the caller lookup object
+     * @return a lookup object for the target class, with private access
+     * @throws IllegalArgumentException if {@code targetClass} is a primitve type or array class
+     * @throws NullPointerException if {@code targetClass} or {@code caller} is {@code null}
+     * @throws IllegalAccessException if the access check specified above fails
+     * @throws SecurityException if denied by the security manager
+     * @since 9
+     */
+    public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+        if (targetClass.isPrimitive())
+            throw new IllegalArgumentException(targetClass + " is a primitive class");
+        if (targetClass.isArray())
+            throw new IllegalArgumentException(targetClass + " is an array class");
+        Module targetModule = targetClass.getModule();
+        Module callerModule = lookup.lookupClass().getModule();
+        if (callerModule != targetModule && targetModule.isNamed()) {
+            if (!callerModule.canRead(targetModule))
+                throw new IllegalAccessException(callerModule + " does not read " + targetModule);
+            String pn = targetClass.getPackageName();
+            assert pn != null && pn.length() > 0 : "unnamed package cannot be in named module";
+            if (!targetModule.isOpen(pn, callerModule))
+                throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule);
+        }
+        if ((lookup.lookupModes() & Lookup.MODULE) == 0)
+            throw new IllegalAccessException("lookup does not have MODULE lookup mode");
+        return new Lookup(targetClass);
+    }
+
+    /**
      * Performs an unchecked "crack" of a
      * <a href="MethodHandleInfo.html#directmh">direct method handle</a>.
      * The result is as if the user had obtained a lookup object capable enough
@@ -1807,7 +1861,12 @@
             return callerClass;
         }
 
-        private boolean hasPrivateAccess() {
+        /**
+         * Returns {@code true} if this lookup has {@code PRIVATE} access.
+         * @return {@code true} if this lookup has {@code PRIVATE} acesss.
+         * @since 9
+         */
+        public boolean hasPrivateAccess() {
             return (allowedModes & PRIVATE) != 0;
         }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,14 +26,20 @@
 package java.lang.module;
 
 import java.io.PrintStream;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * The configuration that is the result of resolution or resolution with
@@ -46,14 +52,14 @@
  * dependences expressed by {@code requires} clauses.
  *
  * The <em>dependence graph</em> is augmented with edges that take account of
- * implicitly declared dependences ({@code requires public}) to create a
+ * implicitly declared dependences ({@code requires transitive}) to create a
  * <em>readability graph</em>. A {@code Configuration} encapsulates the
  * resulting graph of {@link ResolvedModule resolved modules}.
  *
  * <p> Suppose we have the following observable modules: </p>
  * <pre> {@code
  *     module m1 { requires m2; }
- *     module m2 { requires public m3; }
+ *     module m2 { requires transitive m3; }
  *     module m3 { }
  *     module m4 { }
  * } </pre>
@@ -70,8 +76,10 @@
  * <p> Resolution is an additive process. When computing the transitive closure
  * then the dependence relation may include dependences on modules in parent
  * configurations. The result is a <em>relative configuration</em> that is
- * relative to a parent configuration and where the readability graph may have
- * edges from modules in the configuration to modules in a parent configuration.
+ * relative to one or more parent configurations and where the readability graph
+ * may have edges from modules in the configuration to modules in parent
+ * configurations.
+ *
  * </p>
  *
  * <p> Suppose we have the following observable modules: </p>
@@ -96,9 +104,9 @@
  * <p> {@link ModuleDescriptor#isAutomatic() Automatic} modules receive special
  * treatment during resolution. Each automatic module is resolved so that it
  * reads all other modules in the configuration and all parent configurations.
- * Each automatic module is also resolved as if it {@code requires public} all
- * other automatic modules in the configuration (and all automatic modules in
- * parent configurations). </p>
+ * Each automatic module is also resolved as if it {@code requires transitive}
+ * all other automatic modules in the configuration (and all automatic modules
+ * in parent configurations). </p>
 
  * <h2><a name="servicebinding">Service binding</a></h2>
  *
@@ -171,54 +179,157 @@
     // @see Configuration#empty()
     private static final Configuration EMPTY_CONFIGURATION = new Configuration();
 
-    private final Configuration parent;
+    // parent configurations, in search order
+    private final List<Configuration> parents;
 
     private final Map<ResolvedModule, Set<ResolvedModule>> graph;
     private final Set<ResolvedModule> modules;
     private final Map<String, ResolvedModule> nameToModule;
 
     private Configuration() {
-        this.parent = null;
+        this.parents = Collections.emptyList();
         this.graph = Collections.emptyMap();
         this.modules = Collections.emptySet();
         this.nameToModule = Collections.emptyMap();
     }
 
-    private Configuration(Configuration parent,
+    private Configuration(List<Configuration> parents,
                           Resolver resolver,
                           boolean check)
     {
         Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check);
 
-        Map<String, ResolvedModule> nameToModule = new HashMap<>();
+        @SuppressWarnings(value = {"rawtypes", "unchecked"})
+        Entry<String, ResolvedModule>[] nameEntries
+            = (Entry<String, ResolvedModule>[])new Entry[g.size()];
+        ResolvedModule[] moduleArray = new ResolvedModule[g.size()];
+        int i = 0;
         for (ResolvedModule resolvedModule : g.keySet()) {
-            nameToModule.put(resolvedModule.name(), resolvedModule);
+            moduleArray[i] = resolvedModule;
+            nameEntries[i] = Map.entry(resolvedModule.name(), resolvedModule);
+            i++;
         }
 
-        this.parent = parent;
+        this.parents = Collections.unmodifiableList(parents);
         this.graph = g;
-        this.modules = Collections.unmodifiableSet(g.keySet());
-        this.nameToModule = Collections.unmodifiableMap(nameToModule);
+        this.modules = Set.of(moduleArray);
+        this.nameToModule = Map.ofEntries(nameEntries);
     }
 
 
     /**
      * Resolves a collection of root modules, with this configuration as its
-     * parent, to create a new configuration.
+     * parent, to create a new configuration. This method works exactly as
+     * specified by the static {@link
+     * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires}
+     * method when invoked with this configuration as the parent. In other words,
+     * if this configuration is {@code cf} then this method is equivalent to
+     * invoking:
+     * <pre> {@code
+     *     Configuration.resolveRequires(before, List.of(cf), after, roots);
+     * }</pre>
+     *
+     * @param  before
+     *         The <em>before</em> module finder to find modules
+     * @param  after
+     *         The <em>after</em> module finder to locate modules when a
+     *         module cannot be located by the {@code before} module finder
+     *         and the module is not in this configuration
+     * @param  roots
+     *         The possibly-empty collection of module names of the modules
+     *         to resolve
+     *
+     * @return The configuration that is the result of resolving the given
+     *         root modules
+     *
+     * @throws ResolutionException
+     *         If resolution or the post-resolution checks fail
+     * @throws SecurityException
+     *         If locating a module is denied by the security manager
+     */
+    public Configuration resolveRequires(ModuleFinder before,
+                                         ModuleFinder after,
+                                         Collection<String> roots)
+    {
+        return resolveRequires(before, List.of(this), after, roots);
+    }
+
+
+    /**
+     * Resolves a collection of root modules, with service binding, and with
+     * this configuration as its parent, to create a new configuration.
+     * This method works exactly as specified by the static {@link
+     * #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection)
+     * resolveRequiresAndUses} method when invoked with this configuration
+     * as the parent. In other words, if this configuration is {@code cf} then
+     * this method is equivalent to invoking:
+     * <pre> {@code
+     *     Configuration.resolveRequiresAndUses(before, List.of(cf), after, roots);
+     * }</pre>
+     *
+     *
+     * @param  before
+     *         The <em>before</em> module finder to find modules
+     * @param  after
+     *         The <em>after</em> module finder to locate modules when not
+     *         located by the {@code before} module finder and this
+     *         configuration
+     * @param  roots
+     *         The possibly-empty collection of module names of the modules
+     *         to resolve
+     *
+     * @return The configuration that is the result of resolving the given
+     *         root modules
+     *
+     * @throws ResolutionException
+     *         If resolution or the post-resolution checks fail
+     * @throws SecurityException
+     *         If locating a module is denied by the security manager
+     */
+    public Configuration resolveRequiresAndUses(ModuleFinder before,
+                                                ModuleFinder after,
+                                                Collection<String> roots)
+    {
+        return resolveRequiresAndUses(before, List.of(this), after, roots);
+    }
+
+
+    /**
+     * Resolves a collection of root modules, with service binding, and with
+     * the empty configuration as its parent. The post resolution checks
+     * are optionally run.
+     *
+     * This method is used to create the configuration for the boot layer.
+     */
+    static Configuration resolveRequiresAndUses(ModuleFinder finder,
+                                                Collection<String> roots,
+                                                boolean check,
+                                                PrintStream traceOutput)
+    {
+        List<Configuration> parents = List.of(empty());
+        Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
+        resolver.resolveRequires(roots).resolveUses();
+
+        return new Configuration(parents, resolver, check);
+    }
+
+
+    /**
+     * Resolves a collection of root modules to create a configuration.
      *
      * <p> Each root module is located using the given {@code before} module
      * finder. If a module is not found then it is located in the parent
      * configuration as if by invoking the {@link #findModule(String)
-     * findModule} method. If not found then the module is located using the
-     * given {@code after} module finder. The same search order is used to
-     * locate transitive dependences. Root modules or dependences that are
-     * located in a parent configuration are resolved no further and are not
-     * included in the resulting configuration. </p>
+     * findModule} method on each parent in iteration order. If not found then
+     * the module is located using the given {@code after} module finder. The
+     * same search order is used to locate transitive dependences. Root modules
+     * or dependences that are located in a parent configuration are resolved
+     * no further and are not included in the resulting configuration. </p>
      *
      * <p> When all modules have been resolved then the resulting dependency
      * graph is checked to ensure that it does not contain cycles. A
-     * readability graph is constructed and then, in conjunction with the
-     * module exports and service use, checked for consistency. </p>
+     * readability graph is constructed and in conjunction with the module
+     * exports and service use, checked for consistency. </p>
      *
      * <p> Resolution and the (post-resolution) consistency checks may fail for
      * following reasons: </p>
@@ -262,6 +373,8 @@
      *
      * @param  before
      *         The <em>before</em> module finder to find modules
+     * @param  parents
+     *         The list parent configurations in search order
      * @param  after
      *         The <em>after</em> module finder to locate modules when not
      *         located by the {@code before} module finder or in parent
@@ -274,31 +387,37 @@
      *         root modules
      *
      * @throws ResolutionException
-     *         If resolution or the post-resolution checks fail for any of the
-     *         reasons listed
+     *         If resolution or the post-resolution checks fail
+     * @throws IllegalArgumentException
+     *         If the list of parents is empty
      * @throws SecurityException
      *         If locating a module is denied by the security manager
      */
-    public Configuration resolveRequires(ModuleFinder before,
-                                         ModuleFinder after,
-                                         Collection<String> roots)
+    public static Configuration resolveRequires(ModuleFinder before,
+                                                List<Configuration> parents,
+                                                ModuleFinder after,
+                                                Collection<String> roots)
     {
         Objects.requireNonNull(before);
         Objects.requireNonNull(after);
         Objects.requireNonNull(roots);
 
-        Resolver resolver = new Resolver(before, this, after, null);
+        List<Configuration> parentList = new ArrayList<>(parents);
+        if (parentList.isEmpty())
+            throw new IllegalArgumentException("'parents' is empty");
+
+        Resolver resolver = new Resolver(before, parentList, after, null);
         resolver.resolveRequires(roots);
 
-        return new Configuration(this, resolver, true);
+        return new Configuration(parentList, resolver, true);
     }
 
-
     /**
-     * Resolves a collection of root modules, with service binding, and with
-     * this configuration as its parent, to create a new configuration.
+     * Resolves a collection of root modules, with service binding, to create
+     * configuration.
      *
-     * <p> This method works exactly as specified by {@link #resolveRequires
+     * <p> This method works exactly as specified by {@link
+     * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection)
      * resolveRequires} except that the graph of resolved modules is augmented
      * with modules induced by the service-use dependence relation. </p>
      *
@@ -319,6 +438,8 @@
      *
      * @param  before
      *         The <em>before</em> module finder to find modules
+     * @param  parents
+     *         The list parent configurations in search order
      * @param  after
      *         The <em>after</em> module finder to locate modules when not
      *         located by the {@code before} module finder or in parent
@@ -331,51 +452,35 @@
      *         root modules
      *
      * @throws ResolutionException
-     *         If resolution or the post-resolution checks fail for any of the
-     *         reasons listed
+     *         If resolution or the post-resolution checks fail
+     * @throws IllegalArgumentException
+     *         If the list of parents is empty
      * @throws SecurityException
      *         If locating a module is denied by the security manager
      */
-    public Configuration resolveRequiresAndUses(ModuleFinder before,
-                                                ModuleFinder after,
-                                                Collection<String> roots)
+    public static Configuration resolveRequiresAndUses(ModuleFinder before,
+                                                       List<Configuration> parents,
+                                                       ModuleFinder after,
+                                                       Collection<String> roots)
     {
         Objects.requireNonNull(before);
         Objects.requireNonNull(after);
         Objects.requireNonNull(roots);
 
-        Resolver resolver = new Resolver(before, this, after, null);
+        List<Configuration> parentList = new ArrayList<>(parents);
+        if (parentList.isEmpty())
+            throw new IllegalArgumentException("'parents' is empty");
+
+        Resolver resolver = new Resolver(before, parentList, after, null);
         resolver.resolveRequires(roots).resolveUses();
 
-        return new Configuration(this, resolver, true);
+        return new Configuration(parentList, resolver, true);
     }
 
 
     /**
-     * Resolves a collection of root modules, with service binding, and with
-     * the empty configuration as its parent. The post resolution checks
-     * are optionally run.
-     *
-     * This method is used to create the configuration for the boot layer.
-     */
-    static Configuration resolveRequiresAndUses(ModuleFinder finder,
-                                                Collection<String> roots,
-                                                boolean check,
-                                                PrintStream traceOutput)
-    {
-        Configuration parent = empty();
-
-        Resolver resolver
-            = new Resolver(finder, parent, ModuleFinder.of(), traceOutput);
-        resolver.resolveRequires(roots).resolveUses();
-
-        return new Configuration(parent, resolver, check);
-    }
-
-
-    /**
-     * Returns the <em>empty</em> configuration. The empty configuration does
-     * not contain any modules and does not have a parent.
+     * Returns the <em>empty</em> configuration. There are no modules in the
+     * empty configuration. It has no parents.
      *
      * @return The empty configuration
      */
@@ -385,13 +490,14 @@
 
 
     /**
-     * Returns this configuration's parent unless this is the {@linkplain #empty
-     * empty configuration}, which has no parent.
+     * Returns an unmodifiable list of this configuration's parents, in search
+     * order. If this is the {@linkplain #empty empty configuration} then an
+     * empty list is returned.
      *
-     * @return This configuration's parent
+     * @return A possibly-empty unmodifiable list of this parent configurations
      */
-    public Optional<Configuration> parent() {
-        return Optional.ofNullable(parent);
+    public List<Configuration> parents() {
+        return parents;
     }
 
 
@@ -408,23 +514,35 @@
 
     /**
      * Finds a resolved module in this configuration, or if not in this
-     * configuration, the {@linkplain #parent parent} configurations.
+     * configuration, the {@linkplain #parents parent} configurations.
+     * Finding a module in parent configurations is equivalent to invoking
+     * {@code findModule} on each parent, in search order, until the module
+     * is found or all parents have been searched. In a <em>tree of
+     * configurations</em> then this is equivalent to a depth-first search.
      *
      * @param  name
      *         The module name of the resolved module to find
      *
      * @return The resolved module with the given name or an empty {@code
      *         Optional} if there isn't a module with this name in this
-     *         configuration or any parent configuration
+     *         configuration or any parent configurations
      */
     public Optional<ResolvedModule> findModule(String name) {
         Objects.requireNonNull(name);
-        if (parent == null)
-            return Optional.empty();
         ResolvedModule m = nameToModule.get(name);
         if (m != null)
             return Optional.of(m);
-        return parent().flatMap(x -> x.findModule(name));
+
+        if (!parents.isEmpty()) {
+            return configurations()
+                    .skip(1)  // skip this configuration
+                    .map(cf -> cf.nameToModule)
+                    .filter(map -> map.containsKey(name))
+                    .map(map -> map.get(name))
+                    .findFirst();
+        }
+
+        return Optional.empty();
     }
 
 
@@ -444,9 +562,46 @@
     }
 
     /**
+     * Returns an ordered stream of configurations. The first element is this
+     * configuration, the remaining elements are the parent configurations
+     * in DFS order.
+     *
+     * @implNote For now, the assumption is that the number of elements will
+     * be very low and so this method does not use a specialized spliterator.
+     */
+    Stream<Configuration> configurations() {
+        List<Configuration> allConfigurations = this.allConfigurations;
+        if (allConfigurations == null) {
+            allConfigurations = new ArrayList<>();
+            Set<Configuration> visited = new HashSet<>();
+            Deque<Configuration> stack = new ArrayDeque<>();
+            visited.add(this);
+            stack.push(this);
+            while (!stack.isEmpty()) {
+                Configuration layer = stack.pop();
+                allConfigurations.add(layer);
+
+                // push in reverse order
+                for (int i = layer.parents.size() - 1; i >= 0; i--) {
+                    Configuration parent = layer.parents.get(i);
+                    if (!visited.contains(parent)) {
+                        visited.add(parent);
+                        stack.push(parent);
+                    }
+                }
+            }
+            this.allConfigurations = Collections.unmodifiableList(allConfigurations);
+        }
+        return allConfigurations.stream();
+    }
+
+    private volatile List<Configuration> allConfigurations;
+
+
+    /**
      * Returns a string describing this configuration.
      *
-     * @return A string describing this configuration
+     * @return A possibly empty string describing this configuration
      */
     @Override
     public String toString() {
--- a/jdk/src/java.base/share/classes/java/lang/module/Dependence.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.util.*;
-import java.util.stream.*;
-
-
-class Dependence {
-
-    private Dependence() { }
-
-    static <T> Stream<String> toStringStream(Set<T> s) {
-        return s.stream().map(e -> e.toString().toLowerCase());
-    }
-
-    static <M> String toString(Set<M> mods, String what) {
-        return (Stream.concat(toStringStream(mods), Stream.of(what)))
-                      .collect(Collectors.joining(" "));
-    }
-
-}
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Thu Dec 01 21:39:49 2016 +0000
@@ -45,6 +45,8 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static jdk.internal.module.Checks.*;
 import static java.util.Objects.*;
@@ -57,9 +59,11 @@
  * A module descriptor.
  *
  * <p> A {@code ModuleDescriptor} is typically created from the binary form
- * of a module declaration. The associated {@link ModuleDescriptor.Builder}
- * class can also be used to create a {@code ModuleDescriptor} from its
- * components. </p>
+ * of a module declaration. Alternatively, the {@link ModuleDescriptor.Builder}
+ * class can be used to create a {@code ModuleDescriptor} from its components.
+ * The {@link #module module}, {@link #openModule openModule}, and {@link
+ * #automaticModule automaticModule} methods create builders for building
+ * different kinds of modules. </p>
  *
  * <p> {@code ModuleDescriptor} objects are immutable and safe for use by
  * multiple concurrent threads.</p>
@@ -95,7 +99,13 @@
              * module</i> to have an implicitly declared dependence on the module
              * named by the {@code Requires}.
              */
-            PUBLIC,
+            TRANSITIVE,
+
+            /**
+             * The dependence is mandatory in the static phase, during compilation,
+             * but is optional in the dynamic phase, during execution.
+             */
+            STATIC,
 
             /**
              * The dependence was not explicitly or implicitly declared in the
@@ -115,16 +125,18 @@
         private final String name;
 
         private Requires(Set<Modifier> ms, String mn) {
-            this(ms, mn, true);
+            if (ms.isEmpty()) {
+                ms = Collections.emptySet();
+            } else {
+                ms = Collections.unmodifiableSet(EnumSet.copyOf(ms));
+            }
+            this.mods = ms;
+            this.name = mn;
         }
-        private Requires(Set<Modifier> ms, String mn, boolean check) {
-            if (ms == null || ms.isEmpty()) {
-                mods = Collections.emptySet();
-            } else {
-                mods = check ? Collections.unmodifiableSet(EnumSet.copyOf(ms))
-                             : ms;
-            }
-            this.name = check ? requireModuleName(mn) : mn;
+
+        private Requires(Set<Modifier> ms, String mn, boolean unused) {
+            this.mods = ms;
+            this.name = mn;
         }
 
         /**
@@ -223,9 +235,8 @@
          */
         @Override
         public String toString() {
-            return Dependence.toString(mods, name);
+            return ModuleDescriptor.toString(mods, name);
         }
-
     }
 
 
@@ -239,36 +250,61 @@
 
     public final static class Exports {
 
+        /**
+         * A modifier on a module export.
+         *
+         * @since 9
+         */
+        public static enum Modifier {
+
+            /**
+             * The export was not explicitly or implicitly declared in the
+             * source of the module declaration.
+             */
+            SYNTHETIC,
+
+            /**
+             * The export was implicitly declared in the source of the module
+             * declaration.
+             */
+            MANDATED;
+
+        }
+
+        private final Set<Modifier> mods;
         private final String source;
         private final Set<String> targets;  // empty if unqualified export
 
         /**
-         * Constructs a qualified export.
+         * Constructs an export
          */
-        private Exports(String source, Set<String> targets) {
-            this(source, targets, true);
+        private Exports(Set<Modifier> ms, String source, Set<String> targets) {
+            if (ms.isEmpty()) {
+                ms = Collections.emptySet();
+            } else {
+                ms = Collections.unmodifiableSet(EnumSet.copyOf(ms));
+            }
+            this.mods = ms;
+            this.source = source;
+            this.targets = emptyOrUnmodifiableSet(targets);
         }
 
-        private Exports(String source, Set<String> targets, boolean check) {
-            this.source = check ? requirePackageName(source) : source;
-            targets = check ? Collections.unmodifiableSet(new HashSet<>(targets))
-                            : Collections.unmodifiableSet(targets);
-            if (targets.isEmpty())
-                throw new IllegalArgumentException("Empty target set");
-            if (check)
-                targets.stream().forEach(Checks::requireModuleName);
+        private Exports(Set<Modifier> ms,
+                        String source,
+                        Set<String> targets,
+                        boolean unused) {
+            this.mods = ms;
+            this.source = source;
             this.targets = targets;
         }
 
         /**
-         * Constructs an unqualified export.
+         * Returns the set of modifiers.
+         *
+         * @return A possibly-empty unmodifiable set of modifiers
          */
-        private Exports(String source) {
-            this(source, true);
-        }
-        private Exports(String source, boolean check) {
-            this.source = check ? requirePackageName(source) : source;
-            this.targets = Collections.emptySet();
+        public Set<Modifier> modifiers() {
+            return mods;
         }
 
         /**
@@ -304,25 +340,27 @@
         /**
          * Computes a hash code for this module export.
          *
-         * <p> The hash code is based upon the package name, and for a
-         * qualified export, the set of modules names to which the package
-         * is exported. It satisfies the general contract of the {@link
-         * Object#hashCode Object.hashCode} method.
+         * <p> The hash code is based upon the modifiers, the package name,
+         * and for a qualified export, the set of modules names to which the
+         * package is exported. It satisfies the general contract of the
+         * {@link Object#hashCode Object.hashCode} method.
          *
          * @return The hash-code value for this module export
          */
         @Override
         public int hashCode() {
-            return hash(source, targets);
+            int hash = mods.hashCode();
+            hash = hash * 43 + source.hashCode();
+            return hash * 43 + targets.hashCode();
         }
 
         /**
          * Tests this module export for equality with the given object.
          *
          * <p> If the given object is not an {@code Exports} then this method
-         * returns {@code false}. Two module exports objects are equal if the
-         * package names are equal and the set of target module names is equal.
-         * </p>
+         * returns {@code false}. Two module exports objects are equal if their
+         * set of modifiers is equal, the package names are equal and the set
+         * of target module names is equal. </p>
          *
          * <p> This method satisfies the general contract of the {@link
          * java.lang.Object#equals(Object) Object.equals} method. </p>
@@ -338,8 +376,9 @@
             if (!(ob instanceof Exports))
                 return false;
             Exports other = (Exports)ob;
-            return Objects.equals(this.source, other.source) &&
-                Objects.equals(this.targets, other.targets);
+            return Objects.equals(this.mods, other.mods)
+                    && Objects.equals(this.source, other.source)
+                    && Objects.equals(this.targets, other.targets);
         }
 
         /**
@@ -349,15 +388,177 @@
          */
         @Override
         public String toString() {
+            String s = ModuleDescriptor.toString(mods, source);
             if (targets.isEmpty())
-                return source;
+                return s;
             else
-                return source + " to " + targets;
+                return s + " to " + targets;
+        }
+    }
+
+
+    /**
+     * <p> Represents a module <em>opens</em> directive, may be qualified or
+     * unqualified. </p>
+     *
+     * <p> The <em>opens</em> directive in a module declaration declares a
+     * package to be open to allow all types in the package, and all their
+     * members, not just public types and their public members to be reflected
+     * on by APIs that support private access or a way to bypass or suppress
+     * default Java language access control checks. </p>
+     *
+     * @see ModuleDescriptor#opens()
+     * @since 9
+     */
+
+    public final static class Opens {
+
+        /**
+         * A modifier on a module <em>opens</em> directive.
+         *
+         * @since 9
+         */
+        public static enum Modifier {
+
+            /**
+             * The opens was not explicitly or implicitly declared in the
+             * source of the module declaration.
+             */
+            SYNTHETIC,
+
+            /**
+             * The opens was implicitly declared in the source of the module
+             * declaration.
+             */
+            MANDATED;
+
+        }
+
+        private final Set<Modifier> mods;
+        private final String source;
+        private final Set<String> targets;  // empty if unqualified export
+
+        /**
+         * Constructs an Opens
+         */
+        private Opens(Set<Modifier> ms, String source, Set<String> targets) {
+            if (ms.isEmpty()) {
+                ms = Collections.emptySet();
+            } else {
+                ms = Collections.unmodifiableSet(EnumSet.copyOf(ms));
+            }
+            this.mods = ms;
+            this.source = source;
+            this.targets = emptyOrUnmodifiableSet(targets);
+        }
+
+        private Opens(Set<Modifier> ms,
+                      String source,
+                      Set<String> targets,
+                      boolean unused) {
+            this.mods = ms;
+            this.source = source;
+            this.targets = targets;
+        }
+
+        /**
+         * Returns the set of modifiers.
+         *
+         * @return A possibly-empty unmodifiable set of modifiers
+         */
+        public Set<Modifier> modifiers() {
+            return mods;
         }
 
+        /**
+         * Returns {@code true} if this is a qualified opens.
+         *
+         * @return {@code true} if this is a qualified opens
+         */
+        public boolean isQualified() {
+            return !targets.isEmpty();
+        }
+
+        /**
+         * Returns the package name.
+         *
+         * @return The package name
+         */
+        public String source() {
+            return source;
+        }
+
+        /**
+         * For a qualified opens, returns the non-empty and immutable set
+         * of the module names to which the package is open. For an
+         * unqualified opens, returns an empty set.
+         *
+         * @return The set of target module names or for an unqualified
+         *         opens, an empty set
+         */
+        public Set<String> targets() {
+            return targets;
+        }
+
+        /**
+         * Computes a hash code for this module opens.
+         *
+         * <p> The hash code is based upon the modifiers, the package name,
+         * and for a qualified opens, the set of modules names to which the
+         * package is opened. It satisfies the general contract of the
+         * {@link Object#hashCode Object.hashCode} method.
+         *
+         * @return The hash-code value for this module opens
+         */
+        @Override
+        public int hashCode() {
+            int hash = mods.hashCode();
+            hash = hash * 43 + source.hashCode();
+            return hash * 43 + targets.hashCode();
+        }
+
+        /**
+         * Tests this module opens for equality with the given object.
+         *
+         * <p> If the given object is not an {@code Opens} then this method
+         * returns {@code false}. Two {@code Opens} objects are equal if their
+         * set of modifiers is equal, the package names are equal and the set
+         * of target module names is equal. </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
+         *          dependence that is equal to this module dependence
+         */
+        @Override
+        public boolean equals(Object ob) {
+            if (!(ob instanceof Opens))
+                return false;
+            Opens other = (Opens)ob;
+            return Objects.equals(this.mods, other.mods)
+                    && Objects.equals(this.source, other.source)
+                    && Objects.equals(this.targets, other.targets);
+        }
+
+        /**
+         * Returns a string describing module opens.
+         *
+         * @return A string describing module opens
+         */
+        @Override
+        public String toString() {
+            String s = ModuleDescriptor.toString(mods, source);
+            if (targets.isEmpty())
+                return s;
+            else
+                return s + " to " + targets;
+        }
     }
 
-
 
     /**
      * <p> A service that a module provides one or more implementations of. </p>
@@ -369,21 +570,15 @@
     public final static class Provides {
 
         private final String service;
-        private final Set<String> providers;
+        private final List<String> providers;
 
-        private Provides(String service, Set<String> providers) {
-            this(service, providers, true);
+        private Provides(String service, List<String> providers) {
+            this.service = service;
+            this.providers = Collections.unmodifiableList(providers);
         }
 
-        private Provides(String service, Set<String> providers, boolean check) {
-            this.service = check ? requireServiceTypeName(service) : service;
-            providers = check
-                ? Collections.unmodifiableSet(new LinkedHashSet<>(providers))
-                : Collections.unmodifiableSet(providers);
-            if (providers.isEmpty())
-                throw new IllegalArgumentException("Empty providers set");
-            if (check)
-                providers.forEach(Checks::requireServiceProviderName);
+        private Provides(String service, List<String> providers, boolean unused) {
+            this.service = service;
             this.providers = providers;
         }
 
@@ -395,12 +590,13 @@
         public String service() { return service; }
 
         /**
-         * Returns the set of the fully qualified class names of the providers.
+         * Returns the list of the fully qualified class names of the providers
+         * or provider factories.
          *
-         * @return A non-empty and unmodifiable set of the fully qualified class
-         *         names of the providers.
+         * @return A non-empty and unmodifiable list of the fully qualified class
+         *         names of the providers or provider factories
          */
-        public Set<String> providers() { return providers; }
+        public List<String> providers() { return providers; }
 
         /**
          * Computes a hash code for this provides.
@@ -413,7 +609,7 @@
          */
         @Override
         public int hashCode() {
-            return hash(service, providers);
+            return service.hashCode() * 43 + providers.hashCode();
         }
 
         /**
@@ -421,7 +617,7 @@
          *
          * <p> If the given object is not a {@code Provides} then this method
          * returns {@code false}. Two {@code Provides} objects are equal if the
-         * service type is equal and the set of providers is equal. </p>
+         * service type is equal and the list of providers is equal. </p>
          *
          * <p> This method satisfies the general contract of the {@link
          * java.lang.Object#equals(Object) Object.equals} method. </p>
@@ -774,10 +970,7 @@
 
     // From module declarations
     private final String name;
-    private final Set<Requires> requires;
-    private final Set<Exports> exports;
-    private final Set<String> uses;
-    private final Map<String, Provides> provides;
+    private final boolean open;
 
     // Indicates if synthesised for a JAR file found on the module path
     private final boolean automatic;
@@ -785,6 +978,12 @@
     // Not generated from a module-info.java
     private final boolean synthetic;
 
+    private final Set<Requires> requires;
+    private final Set<Exports> exports;
+    private final Set<Opens> opens;
+    private final Set<String> uses;
+    private final Set<Provides> provides;
+
     // "Extended" information, added post-compilation by tools
     private final Version version;
     private final String mainClass;
@@ -796,12 +995,14 @@
 
 
     private ModuleDescriptor(String name,
+                             boolean open,
                              boolean automatic,
                              boolean synthetic,
-                             Map<String, Requires> requires,
+                             Set<Requires> requires,
+                             Set<Exports> exports,
+                             Set<Opens> opens,
                              Set<String> uses,
-                             Map<String, Exports> exports,
-                             Map<String, Provides> provides,
+                             Set<Provides> provides,
                              Version version,
                              String mainClass,
                              String osName,
@@ -812,31 +1013,24 @@
     {
 
         this.name = name;
+        this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
 
-        Set<Requires> rqs = new HashSet<>(requires.values());
-        assert (rqs.stream().map(Requires::name).sorted().distinct().count()
-                == rqs.size())
-            : "Module " + name + " has duplicate requires";
-        this.requires = emptyOrUnmodifiableSet(rqs);
+        assert (requires.stream().map(Requires::name).distinct().count()
+                == requires.size());
+        this.requires = emptyOrUnmodifiableSet(requires);
 
-        Set<Exports> exs = new HashSet<>(exports.values());
-        assert (exs.stream().map(Exports::source).sorted().distinct().count()
-                == exs.size())
-            : "Module " + name + " has duplicate exports";
-        this.exports = emptyOrUnmodifiableSet(exs);
-
+        this.exports = emptyOrUnmodifiableSet(exports);
+        this.opens = emptyOrUnmodifiableSet(opens);
         this.uses = emptyOrUnmodifiableSet(uses);
-        this.provides = emptyOrUnmodifiableMap(provides);
-
+        this.provides = emptyOrUnmodifiableSet(provides);
         this.version = version;
         this.mainClass = mainClass;
         this.osName = osName;
         this.osArch = osArch;
         this.osVersion = osVersion;
         this.hashes = hashes;
-
         this.packages = emptyOrUnmodifiableSet(packages);
     }
 
@@ -845,11 +1039,13 @@
      */
     ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
         this.name = md.name;
+        this.open = md.open;
         this.automatic = md.automatic;
         this.synthetic = md.synthetic;
 
         this.requires = md.requires;
         this.exports = md.exports;
+        this.opens = md.opens;
         this.uses = md.uses;
         this.provides = md.provides;
 
@@ -866,38 +1062,44 @@
     }
 
     /**
-     * Creates a module descriptor from its components. This method is intended
-     * for use by the jlink plugin.
+     * Creates a module descriptor from its components.
+     * The arguments are pre-validated and sets are unmodifiable sets.
      */
     ModuleDescriptor(String name,
+                     boolean open,
                      boolean automatic,
                      boolean synthetic,
                      Set<Requires> requires,
+                     Set<Exports> exports,
+                     Set<Opens> opens,
                      Set<String> uses,
-                     Set<Exports> exports,
-                     Map<String, Provides> provides,
+                     Set<Provides> provides,
                      Version version,
                      String mainClass,
                      String osName,
                      String osArch,
                      String osVersion,
                      Set<String> packages,
-                     ModuleHashes hashes) {
+                     ModuleHashes hashes,
+                     int hashCode,
+                     boolean unused) {
         this.name = name;
+        this.open = open;
         this.automatic = automatic;
         this.synthetic = synthetic;
-        this.requires = Collections.unmodifiableSet(requires);
-        this.exports = Collections.unmodifiableSet(exports);
-        this.uses = Collections.unmodifiableSet(uses);
-        this.provides = Collections.unmodifiableMap(provides);
-        this.packages = Collections.unmodifiableSet(packages);
-
+        this.requires = requires;
+        this.exports = exports;
+        this.opens = opens;
+        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;
     }
 
     /**
@@ -910,6 +1112,19 @@
     }
 
     /**
+     * <p> Returns {@code true} if this is an open module. </p>
+     *
+     * <p> An open module does not declare any open packages (the {@link #opens()
+     * opens} method returns an empty set) but the resulting module is treated
+     * as if all packages are open. </p>
+     *
+     * @return  {@code true} if this is an open module
+     */
+    public boolean isOpen() {
+        return open;
+    }
+
+    /**
      * <p> Returns {@code true} if this is an automatic module. </p>
      *
      * <p> An automatic module is defined implicitly rather than explicitly
@@ -933,8 +1148,6 @@
      *
      * @return  {@code true} if this module descriptor was not generated by
      *          an explicit or implicit module declaration
-     *
-     * @jvms 4.7.8 The {@code Synthetic} Attribute
      */
     public boolean isSynthetic() {
         return synthetic;
@@ -950,6 +1163,33 @@
     }
 
     /**
+     * <p> The module exports. </p>
+     *
+     * @return  A possibly-empty unmodifiable set of exported packages
+     */
+    public Set<Exports> exports() {
+        return exports;
+    }
+
+    /**
+     * <p> The module <em>opens</em> directives. </p>
+     *
+     * <p> Each {@code Opens} object in the set represents a package (and
+     * the set of target module names when qualified) where all types in the
+     * package, and all their members, not just public types and their public
+     * members, can be reflected on when using APIs that bypass or suppress
+     * default Java language access control checks. </p>
+     *
+     * <p> This method returns an empty set when invoked on {@link #isOpen()
+     * open} module. </p>
+     *
+     * @return  A possibly-empty unmodifiable set of open packages
+     */
+    public Set<Opens> opens() {
+        return opens;
+    }
+
+    /**
      * <p> The service dependences of this module. </p>
      *
      * @return  A possibly-empty unmodifiable set of the fully qualified class
@@ -962,24 +1202,14 @@
     /**
      * <p> The services that this module provides. </p>
      *
-     * @return The possibly-empty unmodifiable map of the services that this
-     *         module provides. The map key is fully qualified class name of
-     *         the service type.
+     * @return The possibly-empty unmodifiable set of the services that this
+     *         module provides
      */
-    public Map<String, Provides> provides() {
+    public Set<Provides> provides() {
         return provides;
     }
 
     /**
-     * <p> The module exports. </p>
-     *
-     * @return  A possibly-empty unmodifiable set of exported packages
-     */
-    public Set<Exports> exports() {
-        return exports;
-    }
-
-    /**
      * Returns this module's version.
      *
      * @return This module's version
@@ -1046,22 +1276,9 @@
     }
 
     /**
-     * Returns the names of the packages defined in, but not exported by, this
-     * module.
+     * Returns the names of all packages in this module.
      *
-     * @return A possibly-empty unmodifiable set of the concealed packages
-     */
-    public Set<String> conceals() {
-        Set<String> conceals = new HashSet<>(packages);
-        exports.stream().map(Exports::source).forEach(conceals::remove);
-        return emptyOrUnmodifiableSet(conceals);
-    }
-
-    /**
-     * Returns the names of all the packages defined in this module, whether
-     * exported or concealed.
-     *
-     * @return A possibly-empty unmodifiable set of the all packages
+     * @return A possibly-empty unmodifiable set of all packages in the module
      */
     public Set<String> packages() {
         return packages;
@@ -1078,31 +1295,39 @@
     /**
      * A builder used for building {@link ModuleDescriptor} objects.
      *
-     * <p> Example usage: </p>
+     * <p> {@code ModuleDescriptor} defines the {@link #module module}, {@link
+     * #openModule openModule}, and {@link #automaticModule automaticModule}
+     * methods to create builders for building different kinds of modules. </p>
      *
-     * <pre>{@code
-     *     ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1")
+     * <p> Example usage: </p>
+     * <pre>{@code    ModuleDescriptor descriptor = ModuleDescriptor.module("m1")
+     *         .exports("p")
      *         .requires("m2")
-     *         .exports("p")
      *         .build();
      * }</pre>
      *
-     * @apiNote A {@code Builder} cannot be used to create an {@link
-     * ModuleDescriptor#isAutomatic() automatic} or a {@link
-     * ModuleDescriptor#isSynthetic() synthetic} module.
+     * @apiNote A {@code Builder} checks the components and invariants as
+     * components are added to the builder. The rational for this is to detect
+     * errors as early as possible and not defer all validation to the
+     * {@link #build build} method. A {@code Builder} cannot be used to create
+     * a {@link ModuleDescriptor#isSynthetic() synthetic} module.
      *
      * @since 9
      */
     public static final class Builder {
-
         final String name;
+        final boolean strict; // true if module names are checked
+        boolean open;
         boolean automatic;
         boolean synthetic;
         final Map<String, Requires> requires = new HashMap<>();
-        final Set<String> uses = new HashSet<>();
+
         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<>();
-        Set<String> conceals = Collections.emptySet();
         Version version;
         String osName;
         String osArch;
@@ -1113,29 +1338,30 @@
         /**
          * Initializes a new builder with the given module name.
          *
-         * @param  name
-         *         The module name
-         *
-         * @throws IllegalArgumentException
-         *         If the module name is {@code null} or is not a legal Java
-         *         identifier
+         * @param strict
+         *        Indicates whether module names are checked or not
          */
-        public Builder(String name) {
-            this.name = requireModuleName(name);
+        Builder(String name, boolean strict) {
+            this.strict = strict;
+            this.name = (strict) ? requireModuleName(name) : name;
         }
 
-        /**
-         * Updates the builder so that it builds an automatic module.
-         *
-         * @return This builder
-         *
-         * @see ModuleDescriptor#isAutomatic()
-         */
-        /* package */ Builder automatic() {
-            this.automatic = true;
+        /* package */ Builder open(boolean open) {
+            this.open = open;
             return this;
         }
 
+        /* package */ Builder automatic(boolean automatic) {
+            this.automatic = automatic;
+            return this;
+        }
+
+        /* package */ boolean isOpen() { return open; }
+
+        /* package */ boolean isAutomatic() {
+            return automatic;
+        }
+
         /**
          * Adds a dependence on a module.
          *
@@ -1165,7 +1391,7 @@
          * Adds a dependence on a module with the given (and possibly empty)
          * set of modifiers.
          *
-         * @param  mods
+         * @param  ms
          *         The set of modifiers
          * @param  mn
          *         The module name
@@ -1179,14 +1405,10 @@
          * @throws IllegalStateException
          *         If the dependence on the module has already been declared
          */
-        public Builder requires(Set<Requires.Modifier> mods, String mn) {
-            if (name.equals(mn))
-                throw new IllegalArgumentException("Dependence on self");
-            if (requires.containsKey(mn))
-                throw new IllegalStateException("Dependence upon " + mn
-                                                + " already declared");
-            requires.put(mn, new Requires(mods, mn)); // checks mn
-            return this;
+        public Builder requires(Set<Requires.Modifier> ms, String mn) {
+            if (strict)
+                mn = requireModuleName(mn);
+            return requires(new Requires(ms, mn));
         }
 
         /**
@@ -1209,62 +1431,6 @@
         }
 
         /**
-         * Adds a dependence on a module with the given modifier.
-         *
-         * @param  mod
-         *         The modifier
-         * @param  mn
-         *         The module name
-         *
-         * @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(Requires.Modifier mod, String mn) {
-            return requires(EnumSet.of(mod), mn);
-        }
-
-        /**
-         * Adds a service dependence.
-         *
-         * @param  st
-         *         The service type
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If the service type is {@code null} or is not a legal Java
-         *         identifier
-         * @throws IllegalStateException
-         *         If a dependency on the service type has already been declared
-         */
-        public Builder uses(String st) {
-            if (uses.contains(requireServiceTypeName(st)))
-                throw new IllegalStateException("Dependence upon service "
-                                                + st + " already declared");
-            uses.add(st);
-            return this;
-        }
-
-        /**
-         * Ensures that the given package name has not been declared as an
-         * exported or concealed package.
-         */
-        private void ensureNotExportedOrConcealed(String pn) {
-            if (exports.containsKey(pn))
-                throw new IllegalStateException("Export of package "
-                                                + pn + " already declared");
-            if (conceals.contains(pn))
-                throw new IllegalStateException("Concealed package "
-                                                + pn + " already declared");
-        }
-
-        /**
          * Adds an export.
          *
          * @param  e
@@ -1273,18 +1439,90 @@
          * @return This builder
          *
          * @throws IllegalStateException
-         *         If the package is already declared as an exported or
-         *         concealed package
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
          */
         public Builder exports(Exports e) {
-            String pn = e.source();
-            ensureNotExportedOrConcealed(pn);
-            exports.put(pn, e);
+            // can't be exported and concealed
+            String source = e.source();
+            if (concealedPackages.contains(source)) {
+                throw new IllegalStateException("Package " + source
+                                                 + " already declared");
+            }
+            if (exports.containsKey(source)) {
+                throw new IllegalStateException("Exported package " + source
+                                                 + " already declared");
+            }
+
+            exports.put(source, e);
             return this;
         }
 
         /**
-         * Adds an export to a set of target modules.
+         * Adds an export, with the given (and possibly empty) set of modifiers,
+         * to export a package to a set of target modules.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  pn
+         *         The package name
+         * @param  targets
+         *         The set of target modules names
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name or any of the target modules is {@code
+         *         null} or is not a legal Java identifier, or the set of
+         *         targets is empty
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
+         */
+        public Builder exports(Set<Exports.Modifier> ms,
+                               String pn,
+                               Set<String> targets)
+        {
+            Exports e = new Exports(ms, requirePackageName(pn), targets);
+
+            // check targets
+            targets = e.targets();
+            if (targets.isEmpty())
+                throw new IllegalArgumentException("Empty target set");
+            if (strict)
+                targets.stream().forEach(Checks::requireModuleName);
+
+            return exports(e);
+        }
+
+        /**
+         * Adds an unqualified export with the given (and possibly empty) set
+         * of modifiers.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  pn
+         *         The package name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
+         */
+        public Builder exports(Set<Exports.Modifier> ms, String pn) {
+            Exports e = new Exports(ms, requirePackageName(pn), Collections.emptySet());
+            return exports(e);
+        }
+
+        /**
+         * Adds an export to export a package to a set of target modules.
          *
          * @param  pn
          *         The package name
@@ -1298,38 +1536,16 @@
          *         null} or is not a legal Java identifier, or the set of
          *         targets is empty
          * @throws IllegalStateException
-         *         If the package is already declared as an exported or
-         *         concealed package
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
          */
         public Builder exports(String pn, Set<String> targets) {
-            ensureNotExportedOrConcealed(pn);
-            exports.put(pn, new Exports(pn, targets)); // checks pn and targets
-            return this;
+            return exports(Collections.emptySet(), pn, targets);
         }
 
         /**
-         * Adds an export to a target module.
-         *
-         * @param  pn
-         *         The package name
-         * @param  target
-         *         The target module name
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If the package name or target module is {@code null} or is
-         *         not a legal Java identifier
-         * @throws IllegalStateException
-         *         If the package is already declared as an exported or
-         *         concealed package
-         */
-        public Builder exports(String pn, String target) {
-            return exports(pn, Collections.singleton(target));
-        }
-
-        /**
-         * Adds an export.
+         * Adds an unqualified export.
          *
          * @param  pn
          *         The package name
@@ -1340,18 +1556,186 @@
          *         If the package name is {@code null} or is not a legal Java
          *         identifier
          * @throws IllegalStateException
-         *         If the package is already declared as an exported or
-         *         concealed package
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method or the package is already
+         *         declared as exported
          */
         public Builder exports(String pn) {
-            ensureNotExportedOrConcealed(pn);
-            exports.put(pn, new Exports(pn)); // checks pn
+            return exports(Collections.emptySet(), pn);
+        }
+
+        /**
+         * Adds an <em>opens</em> directive.
+         *
+         * @param  obj
+         *         The {@code Opens} object
+         *
+         * @return This builder
+         *
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(Opens obj) {
+            if (open) {
+                throw new IllegalStateException("open modules cannot declare"
+                                                + " open packages");
+            }
+
+            // can't be open and concealed
+            String source = obj.source();
+            if (concealedPackages.contains(source)) {
+                throw new IllegalStateException("Package " + source
+                                                + " already declared");
+            }
+            if (opens.containsKey(source)) {
+                throw new IllegalStateException("Open package " + source
+                                                + " already declared");
+            }
+
+            opens.put(source, obj);
             return this;
         }
 
+
+        /**
+         * Adds an <em>opens</em> directive, with the given (and possibly empty)
+         * set of modifiers, to open a package to a set of target modules.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  pn
+         *         The package name
+         * @param  targets
+         *         The set of target modules names
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name or any of the target modules is {@code
+         *         null} or is not a legal Java identifier, or the set of
+         *         targets is empty
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(Set<Opens.Modifier> ms,
+                             String pn,
+                             Set<String> targets)
+        {
+            Opens e = new Opens(ms, requirePackageName(pn), targets);
+
+            // check targets
+            targets = e.targets();
+            if (targets.isEmpty())
+                throw new IllegalArgumentException("Empty target set");
+            if (strict)
+                targets.stream().forEach(Checks::requireModuleName);
+
+            return opens(e);
+        }
+
+        /**
+         * Adds an <em>opens</em> directive to open a package with the given (and
+         * possibly empty) set of modifiers.
+         *
+         * @param  ms
+         *         The set of modifiers
+         * @param  pn
+         *         The package name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(Set<Opens.Modifier> ms, String pn) {
+            Opens e = new Opens(ms, requirePackageName(pn), Collections.emptySet());
+            return opens(e);
+        }
+
+        /**
+         * Adds an <em>opens</em> directive to open a package to a set of target
+         * modules.
+         *
+         * @param  pn
+         *         The package name
+         * @param  targets
+         *         The set of target modules names
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name or any of the target modules is {@code
+         *         null} or is not a legal Java identifier, or the set of
+         *         targets is empty
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(String pn, Set<String> targets) {
+            return opens(Collections.emptySet(), pn, targets);
+        }
+
+        /**
+         * Adds an <em>opens</em> directive to open a package.
+         *
+         * @param  pn
+         *         The package name
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the package name is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If the package is already declared as a package with the
+         *         {@link #contains contains} method, the package is already
+         *         declared as open, or this is a builder for an open module
+         */
+        public Builder opens(String pn) {
+            return opens(Collections.emptySet(), pn);
+        }
+
+
         // Used by ModuleInfo, after a packageFinder is invoked
-        /* package */ Set<String> exportedPackages() {
-            return exports.keySet();
+        /* 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.
+         *
+         * @param  service
+         *         The service type
+         *
+         * @return This builder
+         *
+         * @throws IllegalArgumentException
+         *         If the service type is {@code null} or is not a legal Java
+         *         identifier
+         * @throws IllegalStateException
+         *         If a dependency on the service type has already been declared
+         */
+        public Builder uses(String service) {
+            if (uses.contains(requireServiceTypeName(service)))
+                throw new IllegalStateException("Dependence upon service "
+                                                + service + " already declared");
+            uses.add(service);
+            return this;
         }
 
         /**
@@ -1376,38 +1760,47 @@
         }
 
         /**
-         * Provides service {@code st} with implementations {@code pcs}.
+         * Provides implementations of a service.
          *
-         * @param  st
+         * @param  service
          *         The service type
-         * @param  pcs
-         *         The set of provider class names
+         * @param  providers
+         *         The list of provider or provider factory class names
          *
          * @return This builder
          *
          * @throws IllegalArgumentException
          *         If the service type or any of the provider class names is
-         *         {@code null} or is not a legal Java identifier, or the set
+         *         {@code null} or is not a legal Java identifier, or the list
          *         of provider class names is empty
          * @throws IllegalStateException
          *         If the providers for the service type have already been
          *         declared
          */
-        public Builder provides(String st, Set<String> pcs) {
-            if (provides.containsKey(st))
+        public Builder provides(String service, List<String> providers) {
+            if (provides.containsKey(service))
                 throw new IllegalStateException("Providers of service "
-                                                + st + " already declared");
-            provides.put(st, new Provides(st, pcs)); // checks st and pcs
+                                                + service + " already declared by " + name);
+
+            Provides p = new Provides(requireServiceTypeName(service), providers);
+
+            // check providers after the set has been copied.
+            List<String> providerNames = p.providers();
+            if (providerNames.isEmpty())
+                throw new IllegalArgumentException("Empty providers set");
+            providerNames.forEach(Checks::requireServiceProviderName);
+
+            provides.put(service, p);
             return this;
         }
 
         /**
-         * Provides service {@code st} with implementation {@code pc}.
+         * Provides an implementation of a service.
          *
-         * @param  st
+         * @param  service
          *         The service type
-         * @param  pc
-         *         The provider class name
+         * @param  provider
+         *         The provider or provider factory class name
          *
          * @return This builder
          *
@@ -1418,15 +1811,17 @@
          *         If the providers for the service type have already been
          *         declared
          */
-        public Builder provides(String st, String pc) {
-            return provides(st, Collections.singleton(pc));
+        public Builder provides(String service, String provider) {
+            if (provider == null)
+                throw new IllegalArgumentException("'provider' is null");
+            return provides(service, List.of(provider));
         }
 
         /**
-         * Adds a set of (possible empty) concealed packages.
+         * Adds a (possible empty) set of packages to the module
          *
          * @param  pns
-         *         The set of package names of the concealed packages
+         *         The set of package names
          *
          * @return This builder
          *
@@ -1434,16 +1829,17 @@
          *         If any of the package names is {@code null} or is not a
          *         legal Java identifier
          * @throws IllegalStateException
-         *         If any of packages are already declared as a concealed or
-         *         exported package
+         *         If any of packages are already declared as packages in
+         *         the module. This includes packages that are already
+         *         declared as exported or open packages.
          */
-        public Builder conceals(Set<String> pns) {
-            pns.forEach(this::conceals);
+        public Builder contains(Set<String> pns) {
+            pns.forEach(this::contains);
             return this;
         }
 
         /**
-         * Adds a concealed package.
+         * Adds a package to the module.
          *
          * @param  pn
          *         The package name
@@ -1454,15 +1850,25 @@
          *         If the package name is {@code null}, or is not a legal Java
          *         identifier
          * @throws IllegalStateException
-         *         If the package is already declared as a concealed or exported
-         *         package
+         *         If the package is already declared as a package in the
+         *         module. This includes the package already declared as an
+         *         exported or open package.
          */
-        public Builder conceals(String pn) {
+        public Builder contains(String pn) {
             Checks.requirePackageName(pn);
-            ensureNotExportedOrConcealed(pn);
-            if (conceals.isEmpty())
-                conceals = new HashSet<>();
-            conceals.add(pn);
+            if (concealedPackages.contains(pn)) {
+                throw new IllegalStateException("Package " + pn
+                                                + " already declared");
+            }
+            if (exports.containsKey(pn)) {
+                throw new IllegalStateException("Exported package "
+                                                + pn + " already declared");
+            }
+            if (opens.containsKey(pn)) {
+                throw new IllegalStateException("Open package "
+                                                 + pn + " already declared");
+            }
+            concealedPackages.add(pn);
             return this;
         }
 
@@ -1473,13 +1879,8 @@
          *         The version
          *
          * @return This builder
-         *
-         * @throws IllegalStateException
-         *         If the module version is already set
          */
         public Builder version(Version v) {
-            if (version != null)
-                throw new IllegalStateException("module version already set");
             version = requireNonNull(v);
             return this;
         }
@@ -1494,16 +1895,11 @@
          *
          * @throws IllegalArgumentException
          *         If {@code v} is null or cannot be parsed as a version string
-         * @throws IllegalStateException
-         *         If the module version is already set
          *
          * @see Version#parse(String)
          */
         public Builder version(String v) {
-            if (version != null)
-                throw new IllegalStateException("module version already set");
-            version = Version.parse(v);
-            return this;
+            return version(Version.parse(v));
         }
 
         /**
@@ -1516,12 +1912,8 @@
          *
          * @throws IllegalArgumentException
          *         If {@code mainClass} is null or is not a legal Java identifier
-         * @throws IllegalStateException
-         *         If the module main class is already set
          */
         public Builder mainClass(String mc) {
-            if (mainClass != null)
-                throw new IllegalStateException("main class already set");
             mainClass = requireJavaIdentifier("main class name", mc);
             return this;
         }
@@ -1536,12 +1928,8 @@
          *
          * @throws IllegalArgumentException
          *         If {@code name} is null or the empty String
-         * @throws IllegalStateException
-         *         If the operating system name is already set
          */
         public Builder osName(String name) {
-            if (osName != null)
-                throw new IllegalStateException("OS name already set");
             if (name == null || name.isEmpty())
                 throw new IllegalArgumentException("OS name is null or empty");
             osName = name;
@@ -1558,12 +1946,8 @@
          *
          * @throws IllegalArgumentException
          *         If {@code name} is null or the empty String
-         * @throws IllegalStateException
-         *         If the operating system architecture is already set
          */
         public Builder osArch(String arch) {
-            if (osArch != null)
-                throw new IllegalStateException("OS arch already set");
             if (arch == null || arch.isEmpty())
                 throw new IllegalArgumentException("OS arch is null or empty");
             osArch = arch;
@@ -1580,12 +1964,8 @@
          *
          * @throws IllegalArgumentException
          *         If {@code name} is null or the empty String
-         * @throws IllegalStateException
-         *         If the operating system version is already set
          */
         public Builder osVersion(String version) {
-            if (osVersion != null)
-                throw new IllegalStateException("OS version already set");
             if (version == null || version.isEmpty())
                 throw new IllegalArgumentException("OS version is null or empty");
             osVersion = version;
@@ -1597,7 +1977,6 @@
             return this;
         }
 
-
         /* package */ Builder synthetic(boolean v) {
             this.synthetic = v;
             return this;
@@ -1609,16 +1988,24 @@
          * @return The module descriptor
          */
         public ModuleDescriptor build() {
-            assert name != null;
+            Set<Requires> requires = new HashSet<>(this.requires.values());
+
+            Set<String> packages = new HashSet<>(exportedAndOpenPackages());
+            packages.addAll(concealedPackages);
 
-            Set<String> packages = new HashSet<>(conceals);
-            packages.addAll(exportedPackages());
+            Set<Exports> exports = new HashSet<>(this.exports.values());
+            Set<Opens> opens = new HashSet<>(this.opens.values());
+
+            Set<Provides> provides = new HashSet<>(this.provides.values());
+
             return new ModuleDescriptor(name,
+                                        open,
                                         automatic,
                                         synthetic,
                                         requires,
+                                        exports,
+                                        opens,
                                         uses,
-                                        exports,
                                         provides,
                                         version,
                                         mainClass,
@@ -1631,7 +2018,6 @@
 
     }
 
-
     /**
      * Compares this module descriptor to another.
      *
@@ -1689,11 +2075,13 @@
             return false;
         ModuleDescriptor that = (ModuleDescriptor)ob;
         return (name.equals(that.name)
+                && open == that.open
                 && automatic == that.automatic
                 && synthetic == that.synthetic
                 && requires.equals(that.requires)
+                && exports.equals(that.exports)
+                && opens.equals(that.opens)
                 && uses.equals(that.uses)
-                && exports.equals(that.exports)
                 && provides.equals(that.provides)
                 && Objects.equals(version, that.version)
                 && Objects.equals(mainClass, that.mainClass)
@@ -1720,11 +2108,13 @@
         int hc = hash;
         if (hc == 0) {
             hc = name.hashCode();
+            hc = hc * 43 + Boolean.hashCode(open);
             hc = hc * 43 + Boolean.hashCode(automatic);
             hc = hc * 43 + Boolean.hashCode(synthetic);
             hc = hc * 43 + requires.hashCode();
+            hc = hc * 43 + exports.hashCode();
+            hc = hc * 43 + opens.hashCode();
             hc = hc * 43 + uses.hashCode();
-            hc = hc * 43 + exports.hashCode();
             hc = hc * 43 + provides.hashCode();
             hc = hc * 43 + Objects.hashCode(version);
             hc = hc * 43 + Objects.hashCode(mainClass);
@@ -1748,36 +2138,101 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("Module { name: ").append(toNameAndVersion());
+
+        if (isOpen())
+            sb.append("open ");
+        sb.append("module { name: ").append(toNameAndVersion());
         if (!requires.isEmpty())
             sb.append(", ").append(requires);
         if (!uses.isEmpty())
             sb.append(", ").append(uses);
         if (!exports.isEmpty())
             sb.append(", exports: ").append(exports);
+        if (!opens.isEmpty())
+            sb.append(", opens: ").append(opens);
         if (!provides.isEmpty()) {
-            sb.append(", provides: [");
-            for (Map.Entry<String, Provides> entry : provides.entrySet()) {
-                sb.append(entry.getKey())
-                   .append(" with ")
-                   .append(entry.getValue());
-            }
-            sb.append("]");
+            sb.append(", provides: ").append(provides);
         }
         sb.append(" }");
         return sb.toString();
     }
 
+
+    /**
+     * Instantiates a builder to build a module descriptor.
+     *
+     * @param  name
+     *         The module name
+     *
+     * @return A new builder
+     *
+     * @throws IllegalArgumentException
+     *         If the module name is {@code null} or is not a legal Java
+     *         identifier
+     */
+    public static Builder module(String name) {
+        return new Builder(name, true);
+    }
+
+    /**
+     * Instantiates a builder to build a module descriptor for an open module.
+     * An open module does not declare any open packages but the resulting
+     * module is treated as if all packages are open.
+     *
+     * <p> As an example, the following creates a module descriptor for an open
+     * name "{@code m}" containing two packages, one of which is exported. </p>
+     * <pre>{@code
+     *     ModuleDescriptor descriptor = ModuleDescriptor.openModule("m")
+     *         .requires("java.base")
+     *         .exports("p")
+     *         .contains("q")
+     *         .build();
+     * }</pre>
+     *
+     * @param  name
+     *         The module name
+     *
+     * @return A new builder that builds an open module
+     *
+     * @throws IllegalArgumentException
+     *         If the module name is {@code null} or is not a legal Java
+     *         identifier
+     */
+    public static Builder openModule(String name) {
+        return new Builder(name, true).open(true);
+    }
+
+    /**
+     * Instantiates a builder to build a module descriptor for an automatic
+     * module. Automatic modules receive special treatment during resolution
+     * (see {@link Configuration}) so that they read all other modules. When
+     * Instantiated in the Java virtual machine as a {@link java.lang.reflect.Module}
+     * then the Module reads every unnamed module in the Java virtual machine.
+     *
+     * @param  name
+     *         The module name
+     *
+     * @return A new builder that builds an automatic module
+     *
+     * @throws IllegalArgumentException
+     *         If the module name is {@code null} or is not a legal Java
+     *         identifier
+     *
+     * @see ModuleFinder#of(Path[])
+     */
+    public static Builder automaticModule(String name) {
+        return new Builder(name, true).automatic(true);
+    }
+
+
     /**
      * Reads the binary form of a module declaration from an input stream
      * as a module descriptor.
      *
      * <p> If the descriptor encoded in the input stream does not indicate a
-     * set of concealed packages then the {@code packageFinder} will be
-     * invoked.  The packages it returns, except for those indicated as
-     * exported in the encoded descriptor, will be considered to be concealed.
-     * If the {@code packageFinder} throws an {@link UncheckedIOException} then
-     * {@link IOException} cause will be re-thrown. </p>
+     * set of packages in the module then the {@code packageFinder} will be
+     * invoked. If the {@code packageFinder} throws an {@link UncheckedIOException}
+     * then {@link IOException} cause will be re-thrown. </p>
      *
      * <p> If there are bytes following the module descriptor then it is
      * implementation specific as to whether those bytes are read, ignored,
@@ -1789,12 +2244,12 @@
      *
      * @apiNote The {@code packageFinder} parameter is for use when reading
      * module descriptors from legacy module-artifact formats that do not
-     * record the set of concealed packages in the descriptor itself.
+     * record the set of packages in the descriptor itself.
      *
      * @param  in
      *         The input stream
      * @param  packageFinder
-     *         A supplier that can produce a set of package names
+     *         A supplier that can produce the set of packages
      *
      * @return The module descriptor
      *
@@ -1834,10 +2289,7 @@
      * as a module descriptor.
      *
      * <p> If the descriptor encoded in the byte buffer does not indicate a
-     * set of concealed packages then the {@code packageFinder} will be
-     * invoked.  The packages it returns, except for those indicated as
-     * exported in the encoded descriptor, will be considered to be
-     * concealed. </p>
+     * set of packages then the {@code packageFinder} will be invoked. </p>
      *
      * <p> The module descriptor is read from the buffer stating at index
      * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position()
@@ -1853,12 +2305,12 @@
      *
      * @apiNote The {@code packageFinder} parameter is for use when reading
      * module descriptors from legacy module-artifact formats that do not
-     * record the set of concealed packages in the descriptor itself.
+     * record the set of packages in the descriptor itself.
      *
      * @param  bb
      *         The byte buffer
      * @param  packageFinder
-     *         A supplier that can produce a set of package names
+     *         A supplier that can produce the set of packages
      *
      * @return The module descriptor
      *
@@ -1908,6 +2360,15 @@
         }
     }
 
+    /**
+     * Returns a string containing the given set of modifiers and label.
+     */
+    private static <M> String toString(Set<M> mods, String what) {
+        return (Stream.concat(mods.stream().map(e -> e.toString().toLowerCase()),
+                              Stream.of(what)))
+                .collect(Collectors.joining(" "));
+    }
+
     static {
         /**
          * Setup the shared secret to allow code in other packages access
@@ -1915,25 +2376,48 @@
          */
         jdk.internal.misc.SharedSecrets
             .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
+                @Override
+                public Builder newModuleBuilder(String mn, boolean strict) {
+                    return new Builder(mn, strict);
+                }
+
+                @Override
+                public Builder newOpenModuleBuilder(String mn, boolean strict) {
+                    return new Builder(mn, strict).open(true);
+                }
 
                 @Override
                 public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
-                    return new Requires(ms, mn, false);
+                    return new Requires(ms, mn, true);
+                }
+
+                @Override
+                public Exports newExports(Set<Exports.Modifier> ms, String source) {
+                    return new Exports(ms, source, Collections.emptySet(), true);
                 }
 
                 @Override
-                public Exports newExports(String source, Set<String> targets) {
-                    return new Exports(source, targets, false);
+                public Exports newExports(Set<Exports.Modifier> ms,
+                                          String source,
+                                          Set<String> targets) {
+                    return new Exports(ms, source, targets, true);
                 }
 
                 @Override
-                public Exports newExports(String source) {
-                    return new Exports(source, false);
+                public Opens newOpens(Set<Opens.Modifier> ms,
+                                      String source,
+                                      Set<String> targets) {
+                    return new Opens(ms, source, targets, true);
                 }
 
                 @Override
-                public Provides newProvides(String service, Set<String> providers) {
-                    return new Provides(service, providers, false);
+                public Opens newOpens(Set<Opens.Modifier> ms, String source) {
+                    return new Opens(ms, source, Collections.emptySet(), true);
+                }
+
+                @Override
+                public Provides newProvides(String service, List<String> providers) {
+                    return new Provides(service, providers, true);
                 }
 
                 @Override
@@ -1949,25 +2433,30 @@
 
                 @Override
                 public ModuleDescriptor newModuleDescriptor(String name,
+                                                            boolean open,
                                                             boolean automatic,
                                                             boolean synthetic,
                                                             Set<Requires> requires,
+                                                            Set<Exports> exports,
+                                                            Set<Opens> opens,
                                                             Set<String> uses,
-                                                            Set<Exports> exports,
-                                                            Map<String, Provides> provides,
+                                                            Set<Provides> provides,
                                                             Version version,
                                                             String mainClass,
                                                             String osName,
                                                             String osArch,
                                                             String osVersion,
                                                             Set<String> packages,
-                                                            ModuleHashes hashes) {
+                                                            ModuleHashes hashes,
+                                                            int hashCode) {
                     return new ModuleDescriptor(name,
+                                                open,
                                                 automatic,
                                                 synthetic,
                                                 requires,
+                                                exports,
+                                                opens,
                                                 uses,
-                                                exports,
                                                 provides,
                                                 version,
                                                 mainClass,
@@ -1975,7 +2464,14 @@
                                                 osArch,
                                                 osVersion,
                                                 packages,
-                                                hashes);
+                                                hashes,
+                                                hashCode,
+                                                false);
+                }
+
+                @Override
+                public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
+                    return descriptor.hashes();
                 }
 
                 @Override
@@ -1995,11 +2491,6 @@
                 }
 
                 @Override
-                public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
-                    return descriptor.hashes();
-                }
-
-                @Override
                 public ModuleFinder newModulePath(Runtime.Version version,
                                                   boolean isLinkPhase,
                                                   Path... entries) {
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Thu Dec 01 21:39:49 2016 +0000
@@ -233,10 +233,11 @@
      *         ModuleDescriptor.Version} and ignored if it cannot be parsed as
      *         a {@code Version}. </p></li>
      *
-     *         <li><p> For the module name, then all non-alphanumeric
-     *         characters ({@code [^A-Za-z0-9])} are replaced with a dot
-     *         ({@code "."}), all repeating dots are replaced with one dot,
-     *         and all leading and trailing dots are removed. </p></li>
+     *         <li><p> For the module name, then any trailing digits and dots
+     *         are removed, all non-alphanumeric characters ({@code [^A-Za-z0-9]})
+     *         are replaced with a dot ({@code "."}), all repeating dots are
+     *         replaced with one dot, and all leading and trailing dots are
+     *         removed. </p></li>
      *
      *         <li><p> As an example, a JAR file named {@code foo-bar.jar} will
      *         derive a module name {@code foo.bar} and no version. A JAR file
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, 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
@@ -31,13 +31,17 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor.Requires.Modifier;
+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.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Supplier;
@@ -56,15 +60,12 @@
 
 final class ModuleInfo {
 
-    // supplies the set of packages when ConcealedPackages not present
+    // supplies the set of packages when ModulePackages attribute not present
     private final Supplier<Set<String>> packageFinder;
 
-    // indicates if the Hashes attribute should be parsed
+    // indicates if the ModuleHashes attribute should be parsed
     private final boolean parseHashes;
 
-    // the builder, created when parsing
-    private ModuleDescriptor.Builder builder;
-
     private ModuleInfo(Supplier<Set<String>> pf, boolean ph) {
         packageFinder = pf;
         parseHashes = ph;
@@ -86,9 +87,8 @@
     {
         try {
             return new ModuleInfo(pf).doRead(new DataInputStream(in));
-        } catch (IllegalArgumentException iae) {
-            // IllegalArgumentException means a malformed class
-            throw invalidModuleDescriptor(iae.getMessage());
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
         } catch (EOFException x) {
             throw truncatedModuleDescriptor();
         }
@@ -105,9 +105,8 @@
     {
         try {
             return new ModuleInfo(pf).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException iae) {
-            // IllegalArgumentException means a malformed class
-            throw invalidModuleDescriptor(iae.getMessage());
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
         } catch (EOFException x) {
             throw truncatedModuleDescriptor();
         } catch (IOException ioe) {
@@ -117,7 +116,7 @@
 
     /**
      * Reads a {@code module-info.class} from the given byte buffer
-     * but ignore the {@code Hashes} attribute.
+     * but ignore the {@code ModuleHashes} attribute.
      *
      * @throws InvalidModuleDescriptorException
      * @throws UncheckedIOException
@@ -127,8 +126,8 @@
     {
         try {
             return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb));
-        } catch (IllegalArgumentException iae) {
-            throw invalidModuleDescriptor(iae.getMessage());
+        } catch (IllegalArgumentException | IllegalStateException e) {
+            throw invalidModuleDescriptor(e.getMessage());
         } catch (EOFException x) {
             throw truncatedModuleDescriptor();
         } catch (IOException ioe) {
@@ -164,12 +163,8 @@
             throw invalidModuleDescriptor("access_flags should be ACC_MODULE");
 
         int this_class = in.readUnsignedShort();
-        String mn = cpool.getClassName(this_class);
-        int suffix = mn.indexOf("/module-info");
-        if (suffix < 1)
-            throw invalidModuleDescriptor("this_class not of form name/module-info");
-        mn = mn.substring(0, suffix).replace('/', '.');
-        builder = new ModuleDescriptor.Builder(mn);
+        if (this_class != 0)
+            throw invalidModuleDescriptor("this_class must be 0");
 
         int super_class = in.readUnsignedShort();
         if (super_class > 0)
@@ -192,6 +187,13 @@
         // 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);
@@ -206,28 +208,28 @@
             switch (attribute_name) {
 
                 case MODULE :
-                    readModuleAttribute(mn, in, cpool);
+                    builder = readModuleAttribute(in, cpool);
                     break;
 
-                case CONCEALED_PACKAGES :
-                    readConcealedPackagesAttribute(in, cpool);
+                case MODULE_PACKAGES :
+                    packages = readModulePackagesAttribute(in, cpool);
                     break;
 
-                case VERSION :
-                    readVersionAttribute(in, cpool);
+                case MODULE_VERSION :
+                    version = readModuleVersionAttribute(in, cpool);
                     break;
 
-                case MAIN_CLASS :
-                    readMainClassAttribute(in, cpool);
+                case MODULE_MAIN_CLASS :
+                    mainClass = readModuleMainClassAttribute(in, cpool);
                     break;
 
-                case TARGET_PLATFORM :
-                    readTargetPlatformAttribute(in, cpool);
+                case MODULE_TARGET :
+                    osValues = readModuleTargetAttribute(in, cpool);
                     break;
 
-                case HASHES :
+                case MODULE_HASHES :
                     if (parseHashes) {
-                        readHashesAttribute(in, cpool);
+                        hashes = readModuleHashesAttribute(in, cpool);
                     } else {
                         in.skipBytes(length);
                     }
@@ -245,53 +247,91 @@
         }
 
         // the Module attribute is required
-        if (!attributes.contains(MODULE)) {
+        if (builder == null) {
             throw invalidModuleDescriptor(MODULE + " attribute not found");
         }
 
-        // If the ConcealedPackages attribute is not present then the
-        // packageFinder is used to to find any non-exported packages.
-        if (!attributes.contains(CONCEALED_PACKAGES) && packageFinder != null) {
-            Set<String> pkgs;
+        // 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 {
-                pkgs = new HashSet<>(packageFinder.get());
+                packages = new HashSet<>(packageFinder.get());
             } catch (UncheckedIOException x) {
                 throw x.getCause();
             }
-            pkgs.removeAll(builder.exportedPackages());
-            builder.conceals(pkgs);
+            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);
         }
 
-        // Was the Synthetic attribute present?
-        if (attributes.contains(SYNTHETIC))
-            builder.synthetic(true);
+        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.
+     * Reads the Module attribute, returning the ModuleDescriptor.Builder to
+     * build the corresponding ModuleDescriptor.
      */
-    private void readModuleAttribute(String mn, DataInput in, ConstantPool cpool)
+    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.getUtf8(index);
-            Set<Modifier> mods;
+            String dn = cpool.getUtf8AsBinaryName(index);
+            Set<Requires.Modifier> mods;
             if (flags == 0) {
                 mods = Collections.emptySet();
             } else {
                 mods = new HashSet<>();
-                if ((flags & ACC_PUBLIC) != 0)
-                    mods.add(Modifier.PUBLIC);
+                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(Modifier.SYNTHETIC);
+                    mods.add(Requires.Modifier.SYNTHETIC);
                 if ((flags & ACC_MANDATED) != 0)
-                    mods.add(Modifier.MANDATED);
+                    mods.add(Requires.Modifier.MANDATED);
             }
             builder.requires(mods, dn);
             if (dn.equals("java.base"))
@@ -311,17 +351,66 @@
         if (exports_count > 0) {
             for (int i=0; i<exports_count; i++) {
                 int index = in.readUnsignedShort();
-                String pkg = cpool.getUtf8(index).replace('/', '.');
+                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.getUtf8(exports_to_index));
+                        targets.add(cpool.getUtf8AsBinaryName(exports_to_index));
                     }
-                    builder.exports(pkg, targets);
+                    builder.exports(mods, pkg, targets);
                 } else {
-                    builder.exports(pkg);
+                    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);
                 }
             }
         }
@@ -330,111 +419,114 @@
         if (uses_count > 0) {
             for (int i=0; i<uses_count; i++) {
                 int index = in.readUnsignedShort();
-                String sn = cpool.getClassName(index).replace('/', '.');
+                String sn = cpool.getClassNameAsBinaryName(index);
                 builder.uses(sn);
             }
         }
 
         int provides_count = in.readUnsignedShort();
         if (provides_count > 0) {
-            Map<String, Set<String>> pm = new HashMap<>();
             for (int i=0; i<provides_count; i++) {
                 int index = in.readUnsignedShort();
-                int with_index = in.readUnsignedShort();
-                String sn = cpool.getClassName(index).replace('/', '.');
-                String cn = cpool.getClassName(with_index).replace('/', '.');
-                // computeIfAbsent
-                Set<String> providers = pm.get(sn);
-                if (providers == null) {
-                    providers = new LinkedHashSet<>(); // preserve order
-                    pm.put(sn, providers);
+                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);
                 }
-                providers.add(cn);
-            }
-            for (Map.Entry<String, Set<String>> e : pm.entrySet()) {
-                builder.provides(e.getKey(), e.getValue());
+                builder.provides(sn, providers);
             }
         }
+
+        return builder;
     }
 
     /**
-     * Reads the ConcealedPackages attribute
+     * Reads the ModulePackages attribute
      */
-    private void readConcealedPackagesAttribute(DataInput in, ConstantPool cpool)
+    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.getUtf8(index).replace('/', '.');
-            builder.conceals(pn);
+            String pn = cpool.getUtf8AsBinaryName(index);
+            packages.add(pn);
         }
+        return packages;
     }
 
     /**
-     * Reads the Version attribute
+     * Reads the ModuleVersion attribute
      */
-    private void readVersionAttribute(DataInput in, ConstantPool cpool)
+    private String readModuleVersionAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
         int index = in.readUnsignedShort();
-        builder.version(cpool.getUtf8(index));
+        return cpool.getUtf8(index);
     }
 
     /**
-     * Reads the MainClass attribute
+     * Reads the ModuleMainClass attribute
      */
-    private void readMainClassAttribute(DataInput in, ConstantPool cpool)
+    private String readModuleMainClassAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
         int index = in.readUnsignedShort();
-        builder.mainClass(cpool.getClassName(index).replace('/', '.'));
+        return cpool.getClassNameAsBinaryName(index);
     }
 
     /**
-     * Reads the TargetPlatform attribute
+     * Reads the ModuleTarget attribute
      */
-    private void readTargetPlatformAttribute(DataInput in, ConstantPool cpool)
+    private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
+        String[] values = new String[3];
+
         int name_index = in.readUnsignedShort();
         if (name_index != 0)
-            builder.osName(cpool.getUtf8(name_index));
+            values[0] = cpool.getUtf8(name_index);
 
         int arch_index = in.readUnsignedShort();
         if (arch_index != 0)
-            builder.osArch(cpool.getUtf8(arch_index));
+            values[1] = cpool.getUtf8(arch_index);
 
         int version_index = in.readUnsignedShort();
         if (version_index != 0)
-            builder.osVersion(cpool.getUtf8(version_index));
+            values[2] = cpool.getUtf8(version_index);
+
+        return values;
     }
 
 
     /**
-     * Reads the Hashes attribute
-     *
-     * @apiNote For now the hash is stored in base64 as a UTF-8 string, this
-     * should be changed to be an array of u1.
+     * Reads the ModuleHashes attribute
      */
-    private void readHashesAttribute(DataInput in, ConstantPool cpool)
+    private ModuleHashes readModuleHashesAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
-        int index = in.readUnsignedShort();
-        String algorithm = cpool.getUtf8(index);
+        int algorithm_index = in.readUnsignedShort();
+        String algorithm = cpool.getUtf8(algorithm_index);
 
         int hash_count = in.readUnsignedShort();
-
-        Map<String, String> map = new HashMap<>(hash_count);
+        Map<String, byte[]> map = new HashMap<>(hash_count);
         for (int i=0; i<hash_count; i++) {
-            index = in.readUnsignedShort();
-            String dn = cpool.getUtf8(index);
-            index = in.readUnsignedShort();
-            String hash = cpool.getUtf8(index);
-            map.put(dn, hash);
+            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);
         }
 
-        builder.hashes(new ModuleHashes(algorithm, map));
+        return new ModuleHashes(algorithm, map);
     }
 
 
@@ -447,11 +539,11 @@
         if (name.equals(MODULE) ||
                 name.equals(SOURCE_FILE) ||
                 name.equals(SDE) ||
-                name.equals(CONCEALED_PACKAGES) ||
-                name.equals(VERSION) ||
-                name.equals(MAIN_CLASS) ||
-                name.equals(TARGET_PLATFORM) ||
-                name.equals(HASHES))
+                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;
@@ -461,8 +553,8 @@
      * 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, Synthetic, SourceFile, SourceDebugExtension,
-     * and Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
+     * 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;
@@ -477,12 +569,11 @@
                     "LineNumberTable",
                     "LocalVariableTable",
                     "LocalVariableTypeTable",
-                    "RuntimeVisibleAnnotations",
-                    "RuntimeInvisibleAnnotations",
                     "RuntimeVisibleParameterAnnotations",
                     "RuntimeInvisibleParameterAnnotations",
                     "RuntimeVisibleTypeAnnotations",
                     "RuntimeInvisibleTypeAnnotations",
+                    "Synthetic",
                     "AnnotationDefault",
                     "BootstrapMethods",
                     "MethodParameters");
@@ -495,7 +586,6 @@
     private static volatile Set<String> predefinedNotAllowed;
 
 
-
     /**
      * The constant pool in a class file.
      */
@@ -628,6 +718,11 @@
             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];
@@ -638,6 +733,11 @@
             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/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Thu Dec 01 21:39:49 2016 +0000
@@ -40,9 +40,10 @@
 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.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -54,7 +55,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 import jdk.internal.jmod.JmodFile;
@@ -399,8 +399,8 @@
      *
      * 1. The module name (and optionally the version) is derived from the file
      *    name of the JAR file
-     * 2. The packages of all .class files in the JAR file are exported
-     * 3. It has no module-private/concealed packages
+     * 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
@@ -440,8 +440,7 @@
 
         // Builder throws IAE if module name is empty or invalid
         ModuleDescriptor.Builder builder
-            = new ModuleDescriptor.Builder(mn)
-                .automatic()
+            = ModuleDescriptor.automaticModule(mn)
                 .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
         if (vs != null)
             builder.version(vs);
@@ -455,13 +454,12 @@
 
         Set<String> resources = map.get(Boolean.FALSE);
         Set<String> configFiles = map.get(Boolean.TRUE);
-
-        // all packages are exported
+        // all packages are exported and open
         resources.stream()
                 .map(this::toPackageName)
                 .flatMap(Optional::stream)
                 .distinct()
-                .forEach(builder::exports);
+                .forEach(pn -> builder.exports(pn).opens(pn));
 
         // map names of service configuration files to service names
         Set<String> serviceNames = configFiles.stream()
@@ -472,7 +470,7 @@
         // parse each service configuration file
         for (String sn : serviceNames) {
             JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
-            Set<String> providerClasses = new LinkedHashSet<>();
+            List<String> providerClasses = new ArrayList<>();
             try (InputStream in = jf.getInputStream(entry)) {
                 BufferedReader reader
                     = new BufferedReader(new InputStreamReader(in, "UTF-8"));
@@ -493,7 +491,7 @@
             Attributes attrs = man.getMainAttributes();
             String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
             if (mainClass != null)
-                builder.mainClass(mainClass);
+                builder.mainClass(mainClass.replace("/", "."));
         }
 
         return builder.build();
@@ -504,6 +502,7 @@
      */
     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("^\\.");
@@ -514,6 +513,9 @@
      * 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(".");
 
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Thu Dec 01 21:39:49 2016 +0000
@@ -60,8 +60,8 @@
     // the function that computes the hash of this module reference
     private final HashSupplier hasher;
 
-    // cached hash string to avoid needing to compute it many times
-    private String cachedHash;
+    // cached hash to avoid needing to compute it many times
+    private byte[] cachedHash;
 
 
     /**
@@ -183,13 +183,13 @@
     }
 
     /**
-     * Computes the hash of this module, returning it as a hex string.
-     * Returns {@code null} if the hash cannot be computed.
+     * 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
      */
-    String computeHash(String algorithm) {
-        String result = cachedHash;
+    byte[] computeHash(String algorithm) {
+        byte[] result = cachedHash;
         if (result != null)
             return result;
         if (hasher == null)
@@ -211,8 +211,11 @@
     public int hashCode() {
         int hc = hash;
         if (hc == 0) {
-            hc = Objects.hash(descriptor, location, readerSupplier, hasher,
-                    Boolean.valueOf(patched));
+            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;
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Thu Dec 01 21:39:49 2016 +0000
@@ -51,6 +51,7 @@
 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;
@@ -80,9 +81,8 @@
                                              HashSupplier hasher) {
 
         ModuleReference mref = new ModuleReference(md, uri, supplier, hasher);
-
         if (JLA.getBootLayer() == null)
-            mref = ModulePatcher.interposeIfNeeded(mref);
+            mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
 
         return mref;
     }
@@ -93,7 +93,7 @@
     static ModuleReference newJarModule(ModuleDescriptor md, Path file) {
         URI uri = file.toUri();
         Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHashAsString(file, a);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
         return newModule(md, uri, supplier, hasher);
     }
 
@@ -103,7 +103,7 @@
     static ModuleReference newJModModule(ModuleDescriptor md, Path file) {
         URI uri = file.toUri();
         Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
-        HashSupplier hasher = (a) -> ModuleHashes.computeHashAsString(file, a);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
         return newModule(md, file.toUri(), supplier, hasher);
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,9 +26,12 @@
 package java.lang.module;
 
 import java.io.PrintStream;
+import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.reflect.Layer;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Deque;
 import java.util.HashMap;
@@ -47,12 +50,15 @@
 /**
  * The resolver used by {@link Configuration#resolveRequires} and
  * {@link Configuration#resolveRequiresAndUses}.
+ *
+ * @implNote The resolver is used at VM startup and so deliberately avoids
+ * using lambda and stream usages in code paths used during startup.
  */
 
 final class Resolver {
 
     private final ModuleFinder beforeFinder;
-    private final Configuration parent;
+    private final List<Configuration> parents;
     private final ModuleFinder afterFinder;
     private final PrintStream traceOutput;
 
@@ -61,11 +67,11 @@
 
 
     Resolver(ModuleFinder beforeFinder,
-             Configuration parent,
+             List<Configuration> parents,
              ModuleFinder afterFinder,
              PrintStream traceOutput) {
         this.beforeFinder = beforeFinder;
-        this.parent = parent;
+        this.parents = parents;
         this.afterFinder = afterFinder;
         this.traceOutput = traceOutput;
     }
@@ -85,10 +91,12 @@
             // find root module
             ModuleReference mref = findWithBeforeFinder(root);
             if (mref == null) {
-                if (parent.findModule(root).isPresent()) {
+
+                if (findInParent(root) != null) {
                     // in parent, nothing to do
                     continue;
                 }
+
                 mref = findWithAfterFinder(root);
                 if (mref == null) {
                     fail("Module %s not found", root);
@@ -125,13 +133,21 @@
 
             // process dependences
             for (ModuleDescriptor.Requires requires : descriptor.requires()) {
+
+                // only required at compile-time
+                if (requires.modifiers().contains(Modifier.STATIC))
+                    continue;
+
                 String dn = requires.name();
 
                 // find dependence
                 ModuleReference mref = findWithBeforeFinder(dn);
                 if (mref == null) {
-                    if (parent.findModule(dn).isPresent())
+
+                    if (findInParent(dn) != null) {
+                        // dependence is in parent
                         continue;
+                    }
 
                     mref = findWithAfterFinder(dn);
                     if (mref == null) {
@@ -174,7 +190,9 @@
             ModuleDescriptor descriptor = mref.descriptor();
             if (!descriptor.provides().isEmpty()) {
 
-                for (String sn : descriptor.provides().keySet()) {
+                for (Provides provides :  descriptor.provides()) {
+                    String sn = provides.service();
+
                     // computeIfAbsent
                     Set<ModuleReference> providers = availableProviders.get(sn);
                     if (providers == null) {
@@ -191,19 +209,23 @@
         Deque<ModuleDescriptor> q = new ArrayDeque<>();
 
         // the initial set of modules that may use services
-        Set<ModuleDescriptor> candidateConsumers = new HashSet<>();
-        Configuration p = parent;
-        while (p != null) {
-            candidateConsumers.addAll(p.descriptors());
-            p = p.parent().orElse(null);
+        Set<ModuleDescriptor> initialConsumers;
+        if (Layer.boot() == null) {
+            initialConsumers = new HashSet<>();
+        } else {
+            initialConsumers = parents.stream()
+                    .flatMap(Configuration::configurations)
+                    .distinct()
+                    .flatMap(c -> c.descriptors().stream())
+                    .collect(Collectors.toSet());
         }
         for (ModuleReference mref : nameToReference.values()) {
-            candidateConsumers.add(mref.descriptor());
+            initialConsumers.add(mref.descriptor());
         }
 
-
         // Where there is a consumer of a service then resolve all modules
         // that provide an implementation of that service
+        Set<ModuleDescriptor> candidateConsumers = initialConsumers;
         do {
             for (ModuleDescriptor descriptor : candidateConsumers) {
                 if (!descriptor.uses().isEmpty()) {
@@ -234,7 +256,6 @@
             }
 
             candidateConsumers = resolve(q);
-
         } while (!candidateConsumers.isEmpty());
 
         return this;
@@ -429,21 +450,21 @@
             for (String dn : hashes.names()) {
                 ModuleReference other = nameToReference.get(dn);
                 if (other == null) {
-                    other = parent.findModule(dn)
-                            .map(ResolvedModule::reference)
-                            .orElse(null);
+                    ResolvedModule resolvedModule = findInParent(dn);
+                    if (resolvedModule != null)
+                        other = resolvedModule.reference();
                 }
 
                 // skip checking the hash if the module has been patched
                 if (other != null && !other.isPatched()) {
-                    String recordedHash = hashes.hashFor(dn);
-                    String actualHash = other.computeHash(algorithm);
+                    byte[] recordedHash = hashes.hashFor(dn);
+                    byte[] actualHash = other.computeHash(algorithm);
                     if (actualHash == null)
                         fail("Unable to compute the hash of module %s", dn);
-                    if (!recordedHash.equals(actualHash)) {
+                    if (!Arrays.equals(recordedHash, actualHash)) {
                         fail("Hash of %s (%s) differs to expected hash (%s)" +
-                             " recorded in %s", dn, actualHash, recordedHash,
-                             descriptor.name());
+                             " recorded in %s", dn, toHexString(actualHash),
+                             toHexString(recordedHash), descriptor.name());
                     }
                 }
             }
@@ -451,52 +472,68 @@
         }
     }
 
+    private static String toHexString(byte[] ba) {
+        StringBuilder sb = new StringBuilder(ba.length * 2);
+        for (byte b: ba) {
+            sb.append(String.format("%02x", b & 0xff));
+        }
+        return sb.toString();
+    }
+
 
     /**
      * Computes the readability graph for the modules in the given Configuration.
      *
      * The readability graph is created by propagating "requires" through the
-     * "public requires" edges of the module dependence graph. So if the module
-     * dependence graph has m1 requires m2 && m2 requires public m3 then the
-     * resulting readability graph will contain m1 reads m2, m1 reads m3, and
-     * m2 reads m3.
+     * "requires transitive" edges of the module dependence graph. So if the
+     * module dependence graph has m1 requires m2 && m2 requires transitive m3
+     * then the resulting readability graph will contain m1 reads m2, m1 reads m3,
+     * and m2 reads m3.
      */
     private Map<ResolvedModule, Set<ResolvedModule>> makeGraph(Configuration cf) {
 
+        // initial capacity of maps to avoid resizing
+        int capacity = 1 + (4 * nameToReference.size())/ 3;
+
         // the "reads" graph starts as a module dependence graph and
         // is iteratively updated to be the readability graph
-        Map<ResolvedModule, Set<ResolvedModule>> g1 = new HashMap<>();
-
-        // the "requires public" graph, contains requires public edges only
-        Map<ResolvedModule, Set<ResolvedModule>> g2 = new HashMap<>();
+        Map<ResolvedModule, Set<ResolvedModule>> g1 = new HashMap<>(capacity);
 
-
-        // need "requires public" from the modules in parent configurations as
-        // there may be selected modules that have a dependency on modules in
-        // the parent configuration.
+        // the "requires transitive" graph, contains requires transitive edges only
+        Map<ResolvedModule, Set<ResolvedModule>> g2;
 
-        Configuration p = parent;
-        while (p != null) {
-            for (ModuleDescriptor descriptor : p.descriptors()) {
-                String name = descriptor.name();
-                ResolvedModule m1 = p.findModule(name)
-                    .orElseThrow(() -> new InternalError(name + " not found"));
-                for (ModuleDescriptor.Requires requires : descriptor.requires()) {
-                    if (requires.modifiers().contains(Modifier.PUBLIC)) {
-                        String dn = requires.name();
-                        ResolvedModule m2 = p.findModule(dn)
-                            .orElseThrow(() -> new InternalError(dn + " not found"));
-                        g2.computeIfAbsent(m1, k -> new HashSet<>()).add(m2);
-                    }
-                }
-            }
-
-            p = p.parent().orElse(null);
+        // need "requires transitive" from the modules in parent configurations
+        // as there may be selected modules that have a dependency on modules in
+        // the parent configuration.
+        if (Layer.boot() == null) {
+            g2 = new HashMap<>(capacity);
+        } else {
+            g2 = parents.stream()
+                .flatMap(Configuration::configurations)
+                .distinct()
+                .flatMap(c ->
+                    c.modules().stream().flatMap(m1 ->
+                        m1.descriptor().requires().stream()
+                            .filter(r -> r.modifiers().contains(Modifier.TRANSITIVE))
+                            .flatMap(r -> {
+                                Optional<ResolvedModule> m2 = c.findModule(r.name());
+                                assert m2.isPresent()
+                                        || r.modifiers().contains(Modifier.STATIC);
+                                return m2.stream();
+                            })
+                            .map(m2 -> Map.entry(m1, m2))
+                    )
+                )
+                // stream of m1->m2
+                .collect(Collectors.groupingBy(Map.Entry::getKey,
+                        HashMap::new,
+                        Collectors.mapping(Map.Entry::getValue, Collectors.toSet())
+            ));
         }
 
         // populate g1 and g2 with the dependences from the selected modules
 
-        Map<String, ResolvedModule> nameToResolved = new HashMap<>();
+        Map<String, ResolvedModule> nameToResolved = new HashMap<>(capacity);
 
         for (ModuleReference mref : nameToReference.values()) {
             ModuleDescriptor descriptor = mref.descriptor();
@@ -505,20 +542,21 @@
             ResolvedModule m1 = computeIfAbsent(nameToResolved, name, cf, mref);
 
             Set<ResolvedModule> reads = new HashSet<>();
-            Set<ResolvedModule> requiresPublic = new HashSet<>();
+            Set<ResolvedModule> requiresTransitive = new HashSet<>();
 
             for (ModuleDescriptor.Requires requires : descriptor.requires()) {
                 String dn = requires.name();
 
-                ResolvedModule m2;
+                ResolvedModule m2 = null;
                 ModuleReference mref2 = nameToReference.get(dn);
                 if (mref2 != null) {
                     // same configuration
                     m2 = computeIfAbsent(nameToResolved, dn, cf, mref2);
                 } else {
                     // parent configuration
-                    m2 = parent.findModule(dn).orElse(null);
+                    m2 = findInParent(dn);
                     if (m2 == null) {
+                        assert requires.modifiers().contains(Modifier.STATIC);
                         continue;
                     }
                 }
@@ -526,9 +564,9 @@
                 // m1 requires m2 => m1 reads m2
                 reads.add(m2);
 
-                // m1 requires public m2
-                if (requires.modifiers().contains(Modifier.PUBLIC)) {
-                    requiresPublic.add(m2);
+                // m1 requires transitive m2
+                if (requires.modifiers().contains(Modifier.TRANSITIVE)) {
+                    requiresTransitive.add(m2);
                 }
 
             }
@@ -538,7 +576,7 @@
             if (descriptor.isAutomatic()) {
 
                 // reads all selected modules
-                // `requires public` all selected automatic modules
+                // `requires transitive` all selected automatic modules
                 for (ModuleReference mref2 : nameToReference.values()) {
                     ModuleDescriptor descriptor2 = mref2.descriptor();
                     String name2 = descriptor2.name();
@@ -548,40 +586,42 @@
                             = computeIfAbsent(nameToResolved, name2, cf, mref2);
                         reads.add(m2);
                         if (descriptor2.isAutomatic())
-                            requiresPublic.add(m2);
+                            requiresTransitive.add(m2);
                     }
                 }
 
                 // reads all modules in parent configurations
-                // `requires public` all automatic modules in parent configurations
-                p = parent;
-                while (p != null) {
-                    for (ResolvedModule m : p.modules()) {
-                        reads.add(m);
-                        if (m.reference().descriptor().isAutomatic())
-                            requiresPublic.add(m);
-                    }
-                    p = p.parent().orElse(null);
+                // `requires transitive` all automatic modules in parent
+                // configurations
+                for (Configuration parent : parents) {
+                    parent.configurations()
+                            .map(Configuration::modules)
+                            .flatMap(Set::stream)
+                            .forEach(m -> {
+                                reads.add(m);
+                                if (m.reference().descriptor().isAutomatic())
+                                    requiresTransitive.add(m);
+                            });
                 }
-
             }
 
             g1.put(m1, reads);
-            g2.put(m1, requiresPublic);
+            g2.put(m1, requiresTransitive);
         }
 
-        // Iteratively update g1 until there are no more requires public to propagate
+        // Iteratively update g1 until there are no more requires transitive
+        // to propagate
         boolean changed;
-        Set<ResolvedModule> toAdd = new HashSet<>();
+        List<ResolvedModule> toAdd = new ArrayList<>();
         do {
             changed = false;
             for (Set<ResolvedModule> m1Reads : g1.values()) {
                 for (ResolvedModule m2 : m1Reads) {
-                    Set<ResolvedModule> m2RequiresPublic = g2.get(m2);
-                    if (m2RequiresPublic != null) {
-                        for (ResolvedModule m3 : m2RequiresPublic) {
+                    Set<ResolvedModule> m2RequiresTransitive = g2.get(m2);
+                    if (m2RequiresTransitive != null) {
+                        for (ResolvedModule m3 : m2RequiresTransitive) {
                             if (!m1Reads.contains(m3)) {
-                                // m1 reads m2, m2 requires public m3
+                                // m1 reads m2, m2 requires transitive m3
                                 // => need to add m1 reads m3
                                 toAdd.add(m3);
                             }
@@ -655,7 +695,7 @@
                     // source is exported to descriptor2
                     String source = export.source();
                     ModuleDescriptor other
-                        = packageToExporter.put(source, descriptor2);
+                        = packageToExporter.putIfAbsent(source, descriptor2);
 
                     if (other != null && other != descriptor2) {
                         // package might be local to descriptor1
@@ -692,12 +732,8 @@
                 }
 
                 // provides S
-                for (Map.Entry<String, ModuleDescriptor.Provides> entry :
-                        descriptor1.provides().entrySet()) {
-                    String service = entry.getKey();
-                    ModuleDescriptor.Provides provides = entry.getValue();
-
-                    String pn = packageName(service);
+                for (ModuleDescriptor.Provides provides : descriptor1.provides()) {
+                    String pn = packageName(provides.service());
                     if (!packageToExporter.containsKey(pn)) {
                         fail("Module %s does not read a module that exports %s",
                              descriptor1.name(), pn);
@@ -717,6 +753,18 @@
 
     }
 
+    /**
+     * Find a module of the given name in the parent configurations
+     */
+    private ResolvedModule findInParent(String mn) {
+        for (Configuration parent : parents) {
+            Optional<ResolvedModule> om = parent.findModule(mn);
+            if (om.isPresent())
+                return om.get();
+        }
+        return null;
+    }
+
 
     /**
      * Invokes the beforeFinder to find method to find the given module.
@@ -755,15 +803,18 @@
             if (afterModules.isEmpty())
                 return beforeModules;
 
-            if (beforeModules.isEmpty() && parent == Configuration.empty())
+            if (beforeModules.isEmpty()
+                    && parents.size() == 1
+                    && parents.get(0) == Configuration.empty())
                 return afterModules;
 
             Set<ModuleReference> result = new HashSet<>(beforeModules);
             for (ModuleReference mref : afterModules) {
                 String name = mref.descriptor().name();
                 if (!beforeFinder.find(name).isPresent()
-                        && !parent.findModule(name).isPresent())
+                        && findInParent(name) == null) {
                     result.add(mref);
+                }
             }
 
             return result;
--- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Thu Dec 01 21:39:49 2016 +0000
@@ -39,6 +39,7 @@
 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;
@@ -53,6 +54,7 @@
 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;
@@ -64,7 +66,7 @@
  * run-time image.
  *
  * The modules linked into the run-time image are assumed to have the
- * ConcealedPackages attribute.
+ * Packages attribute.
  */
 
 class SystemModuleFinder implements ModuleFinder {
@@ -102,8 +104,11 @@
         int n = names.length;
         moduleCount.add(n);
 
-        Set<ModuleReference> mods = new HashSet<>(n);
-        Map<String, ModuleReference> map = new HashMap<>(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];
@@ -111,16 +116,16 @@
             // create the ModuleReference
             ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i]));
 
-            mods.add(mref);
-            map.put(names[i], mref);
+            mods[i] = mref;
+            map[i] = Map.entry(names[i], mref);
 
             // counters
             packageCount.add(md.packages().size());
             exportsCount.add(md.exports().size());
         }
 
-        modules = Collections.unmodifiableSet(mods);
-        nameToModule = map;
+        modules = Set.of(mods);
+        nameToModule = Map.ofEntries(map);
 
         initTime.addElapsedTimeFrom(t0);
     }
@@ -190,7 +195,7 @@
             new ModuleReference(md, uri, readerSupplier, hash);
 
         // may need a reference to a patched module if --patch-module specified
-        mref = ModulePatcher.interposeIfNeeded(mref);
+        mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
 
         return mref;
     }
@@ -199,7 +204,7 @@
         if (isFastPathSupported()) {
             return new HashSupplier() {
                 @Override
-                public String generate(String algorithm) {
+                public byte[] generate(String algorithm) {
                     return SystemModules.MODULES_TO_HASH[index];
                 }
             };
@@ -213,7 +218,7 @@
      * It will get the recorded hashes from module-info.class.
      */
     private static class Hashes {
-        static Map<String, String> hashes = new HashMap<>();
+        static Map<String, byte[]> hashes = new HashMap<>();
 
         static void add(ModuleDescriptor descriptor) {
             Optional<ModuleHashes> ohashes = descriptor.hashes();
@@ -228,7 +233,7 @@
 
             return new HashSupplier() {
                 @Override
-                public String generate(String algorithm) {
+                public byte[] generate(String algorithm) {
                     return hashes.get(name);
                 }
             };
--- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,12 +25,12 @@
 
 package java.lang.reflect;
 
+import java.lang.annotation.Annotation;
 import java.security.AccessController;
 
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.reflect.ReflectionFactory;
-import java.lang.annotation.Annotation;
 
 /**
  * The AccessibleObject class is the base class for Field, Method and
@@ -81,8 +81,10 @@
      * <p>This method cannot be used to enable access to an object that is a
      * {@link Member member} of a class in a different module to the caller and
      * where the class is in a package that is not exported to the caller's
-     * module. Additionally, this method cannot be used to enable access to
-     * non-public members of {@code AccessibleObject} or {@link Module}.
+     * module. Additionally, if the member is non-public or its declaring
+     * class is non-public, then this method can only be used to enable access
+     * if the package is {@link Module#isOpen(String,Module) open} to at least
+     * the caller's module.
      *
      * <p>If there is a security manager, its
      * {@code checkPermission} method is first called with a
@@ -126,8 +128,10 @@
      * <p>This method cannot be used to enable access to an object that is a
      * {@link Member member} of a class in a different module to the caller and
      * where the class is in a package that is not exported to the caller's
-     * module. Additionally, this method cannot be used to enable access to
-     * non-public members of {@code AccessibleObject} or {@link Module}.
+     * module. Additionally, if the member is non-public or its declaring
+     * class is non-public, then this method can only be used to enable access
+     * if the package is {@link Module#isOpen(String,Module) open} to at least
+     * the caller's module.
      *
      * <p>If there is a security manager, its
      * {@code checkPermission} method is first called with a
@@ -138,6 +142,7 @@
      * @throws SecurityException if the request is denied
      * @see SecurityManager#checkPermission
      * @see ReflectPermission
+     * @see java.lang.invoke.MethodHandles#privateLookupIn
      */
     public void setAccessible(boolean flag) {
         AccessibleObject.checkPermission();
@@ -161,35 +166,39 @@
         Module callerModule = caller.getModule();
         Module declaringModule = declaringClass.getModule();
 
-        if (callerModule != declaringModule
-                && callerModule != Object.class.getModule()) {
+        if (callerModule == declaringModule) return;
+        if (callerModule == Object.class.getModule()) return;
+        if (!declaringModule.isNamed()) return;
 
-            // check exports to target module
-            String pn = packageName(declaringClass);
-            if (!declaringModule.isExported(pn, callerModule)) {
-                String msg = "Unable to make member of "
-                        + declaringClass + " accessible:  "
-                        + declaringModule + " does not export "
-                        + pn + " to " + callerModule;
-                Reflection.throwInaccessibleObjectException(msg);
-            }
-
-        }
+        // package is open to caller
+        String pn = packageName(declaringClass);
+        if (declaringModule.isOpen(pn, callerModule))
+            return;
 
-        if (declaringClass == Module.class
-                || declaringClass == AccessibleObject.class) {
-            int modifiers;
-            if (this instanceof Executable) {
-                modifiers = ((Executable) this).getModifiers();
-            } else {
-                modifiers = ((Field) this).getModifiers();
-            }
-            if (!Modifier.isPublic(modifiers)) {
-                String msg = "Cannot make a non-public member of "
-                        + declaringClass + " accessible";
-                Reflection.throwInaccessibleObjectException(msg);
-            }
+        // package is exported to caller and class/member is public
+        boolean isExported = declaringModule.isExported(pn, callerModule);
+        boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
+        int modifiers;
+        if (this instanceof Executable) {
+            modifiers = ((Executable) this).getModifiers();
+        } else {
+            modifiers = ((Field) this).getModifiers();
         }
+        boolean isMemberPublic = Modifier.isPublic(modifiers);
+        if (isExported && isClassPublic && isMemberPublic)
+            return;
+
+        // not accessible
+        String msg = "Unable to make ";
+        if (this instanceof Field)
+            msg += "field ";
+        msg += this + " accessible: " + declaringModule + " does not \"";
+        if (isClassPublic && isMemberPublic)
+            msg += "exports";
+        else
+            msg += "opens";
+        msg += " " + pn + "\" to " + callerModule;
+        Reflection.throwInaccessibleObjectException(msg);
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,23 +27,29 @@
 
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ResolvedModule;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
+import jdk.internal.loader.ClassLoaderValue;
 import jdk.internal.loader.Loader;
 import jdk.internal.loader.LoaderPool;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Modules;
 import jdk.internal.module.ServicesCatalog;
-import jdk.internal.module.ServicesCatalog.ServiceProvider;
 import sun.security.util.SecurityConstants;
 
 
@@ -55,7 +61,7 @@
  * Creating a layer informs the Java virtual machine about the classes that
  * may be loaded from modules so that the Java virtual machine knows which
  * module that each class is a member of. Each layer, except the {@link
- * #empty() empty} layer, has a {@link #parent() parent}. </p>
+ * #empty() empty} layer, has at least one {@link #parents() parent}. </p>
  *
  * <p> Creating a layer creates a {@link Module} object for each {@link
  * ResolvedModule} in the configuration. For each resolved module that is
@@ -71,7 +77,11 @@
  * mapped to a single class loader or where each module is mapped to its own
  * class loader. The {@link #defineModules defineModules} method is for more
  * advanced cases where modules are mapped to custom class loaders by means of
- * a function specified to the method. </p>
+ * a function specified to the method. Each of these methods has an instance
+ * and static variant. The instance methods create a layer with the receiver
+ * as the parent layer. The static methods are for more advanced cases where
+ * there can be more than one parent layer or a {@link Layer.Controller
+ * Controller} is needed to control modules in the layer. </p>
  *
  * <p> A Java virtual machine has at least one non-empty layer, the {@link
  * #boot() boot} layer, that is created when the Java virtual machine is
@@ -80,7 +90,7 @@
  * The modules in the boot layer are mapped to the bootstrap class loader and
  * other class loaders that are <a href="../ClassLoader.html#builtinLoaders">
  * built-in</a> into the Java virtual machine. The boot layer will often be
- * the {@link #parent() parent} when creating additional layers. </p>
+ * the {@link #parents() parent} when creating additional layers. </p>
  *
  * <p> As when creating a {@code Configuration},
  * {@link ModuleDescriptor#isAutomatic() automatic} modules receive
@@ -123,30 +133,29 @@
 
     // the empty Layer
     private static final Layer EMPTY_LAYER
-        = new Layer(Configuration.empty(), null, null);
+        = new Layer(Configuration.empty(), List.of(), null);
 
     // the configuration from which this Layer was created
     private final Configuration cf;
 
-    // parent layer, null in the case of the empty layer
-    private final Layer parent;
+    // parent layers, empty in the case of the empty layer
+    private final List<Layer> parents;
 
     // maps module name to jlr.Module
     private final Map<String, Module> nameToModule;
 
-
     /**
      * Creates a new Layer from the modules in the given configuration.
      */
     private Layer(Configuration cf,
-                  Layer parent,
+                  List<Layer> parents,
                   Function<String, ClassLoader> clf)
     {
         this.cf = cf;
-        this.parent = parent;
+        this.parents = parents; // no need to do defensive copy
 
         Map<String, Module> map;
-        if (parent == null) {
+        if (parents.isEmpty()) {
             map = Collections.emptyMap();
         } else {
             map = Module.defineModules(cf, clf, this);
@@ -154,12 +163,230 @@
         this.nameToModule = map; // no need to do defensive copy
     }
 
+    /**
+     * Controls a layer. The static methods defined by {@link Layer} to create
+     * module layers return a {@code Controller} that can be used to control
+     * modules in the layer.
+     *
+     * @apiNote Care should be taken with {@code Controller} objects, they
+     * should never be shared with untrusted code.
+     *
+     * @since 9
+     */
+    public static final class Controller {
+        private final Layer layer;
+
+        Controller(Layer layer) {
+            this.layer = layer;
+        }
+
+        /**
+         * Returns the layer that this object controls.
+         *
+         * @return the layer
+         */
+        public Layer layer() {
+            return layer;
+        }
+
+        private void ensureInLayer(Module source) {
+            if (!layer.modules().contains(source))
+                throw new IllegalArgumentException(source + " not in layer");
+        }
+
+
+        /**
+         * Updates module {@code source} in the layer to read module
+         * {@code target}. This method is a no-op if {@code source} already
+         * reads {@code target}.
+         *
+         * @implNote <em>Read edges</em> added by this method are <em>weak</em>
+         * and do not prevent {@code target} from being GC'ed when {@code source}
+         * is strongly reachable.
+         *
+         * @param  source
+         *         The source module
+         * @param  target
+         *         The target module to read
+         *
+         * @return This controller
+         *
+         * @throws IllegalArgumentException
+         *         If {@code source} is not in the layer
+         *
+         * @see Module#addReads
+         */
+        public Controller addReads(Module source, Module target) {
+            Objects.requireNonNull(source);
+            Objects.requireNonNull(target);
+            ensureInLayer(source);
+            Modules.addReads(source, target);
+            return this;
+        }
+
+        /**
+         * Updates module {@code source} in the layer to open a package to
+         * module {@code target}. This method is a no-op if {@code source}
+         * already opens the package to at least {@code target}.
+         *
+         * @param  source
+         *         The source module
+         * @param  pn
+         *         The package name
+         * @param  target
+         *         The target module to read
+         *
+         * @return This controller
+         *
+         * @throws IllegalArgumentException
+         *         If {@code source} is not in the layer or the package is not
+         *         in the source module
+         *
+         * @see Module#addOpens
+         */
+        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);
+            return this;
+        }
+    }
+
 
     /**
      * Creates a new layer, with this layer as its parent, by defining the
      * modules in the given {@code Configuration} to the Java virtual machine.
      * This method creates one class loader and defines all modules to that
-     * class loader.
+     * class loader. The {@link ClassLoader#getParent() parent} of each class
+     * loader is the given parent class loader. This method works exactly as
+     * specified by the static {@link
+     * #defineModulesWithOneLoader(Configuration,List,ClassLoader)
+     * defineModulesWithOneLoader} method when invoked with this layer as the
+     * parent. In other words, if this layer is {@code thisLayer} then this
+     * method is equivalent to invoking:
+     * <pre> {@code
+     *     Layer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer();
+     * }</pre>
+     *
+     * @param  cf
+     *         The configuration for the layer
+     * @param  parentLoader
+     *         The parent class loader for the class loader created by this
+     *         method; may be {@code null} for the bootstrap class loader
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         for this layer
+     * @throws LayerInstantiationException
+     *         If all modules cannot be defined to the same class loader for any
+     *         of the reasons listed above or the layer cannot be created because
+     *         the configuration contains a module named "{@code java.base}" or
+     *         a module with a package name starting with "{@code java.}"
+     * @throws SecurityException
+     *         If {@code RuntimePermission("createClassLoader")} or
+     *         {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
+     *
+     * @see #findLoader
+     */
+    public Layer defineModulesWithOneLoader(Configuration cf,
+                                            ClassLoader parentLoader) {
+        return defineModulesWithOneLoader(cf, List.of(this), parentLoader).layer();
+    }
+
+
+    /**
+     * Creates a new layer, with this layer as its parent, by defining the
+     * modules in the given {@code Configuration} to the Java virtual machine.
+     * Each module is defined to its own {@link ClassLoader} created by this
+     * method. The {@link ClassLoader#getParent() parent} of each class loader
+     * is the given parent class loader. This method works exactly as specified
+     * by the static {@link
+     * #defineModulesWithManyLoaders(Configuration,List,ClassLoader)
+     * defineModulesWithManyLoaders} method when invoked with this layer as the
+     * parent. In other words, if this layer is {@code thisLayer} then this
+     * method is equivalent to invoking:
+     * <pre> {@code
+     *     Layer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer();
+     * }</pre>
+     *
+     * @param  cf
+     *         The configuration for the layer
+     * @param  parentLoader
+     *         The parent class loader for each of the class loaders created by
+     *         this method; may be {@code null} for the bootstrap class loader
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         for this layer
+     * @throws LayerInstantiationException
+     *         If the layer cannot be created because the configuration contains
+     *         a module named "{@code java.base}" or a module with a package
+     *         name starting with "{@code java.}"
+     * @throws SecurityException
+     *         If {@code RuntimePermission("createClassLoader")} or
+     *         {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
+     *
+     * @see #findLoader
+     */
+    public Layer defineModulesWithManyLoaders(Configuration cf,
+                                              ClassLoader parentLoader) {
+        return defineModulesWithManyLoaders(cf, List.of(this), parentLoader).layer();
+    }
+
+
+    /**
+     * Creates a new layer, with this layer as its parent, by defining the
+     * modules in the given {@code Configuration} to the Java virtual machine.
+     * Each module is mapped, by name, to its class loader by means of the
+     * given function. This method works exactly as specified by the static
+     * {@link #defineModules(Configuration,List,Function) defineModules}
+     * method when invoked with this layer as the parent. In other words, if
+     * this layer is {@code thisLayer} then this method is equivalent to
+     * invoking:
+     * <pre> {@code
+     *     Layer.defineModules(cf, List.of(thisLayer), clf).layer();
+     * }</pre>
+     *
+     * @param  cf
+     *         The configuration for the layer
+     * @param  clf
+     *         The function to map a module name to a class loader
+     *
+     * @return The newly created layer
+     *
+     * @throws IllegalArgumentException
+     *         If the parent of the given configuration is not the configuration
+     *         for this layer
+     * @throws LayerInstantiationException
+     *         If creating the {@code Layer} fails for any of the reasons
+     *         listed above, the layer cannot be created because the
+     *         configuration contains a module named "{@code java.base}",
+     *         a module with a package name starting with "{@code java.}" is
+     *         mapped to a class loader other than the {@link
+     *         ClassLoader#getPlatformClassLoader() platform class loader},
+     *         or the function to map a module name to a class loader returns
+     *         {@code null}
+     * @throws SecurityException
+     *         If {@code RuntimePermission("getClassLoader")} is denied by
+     *         the security manager
+     */
+    public Layer defineModules(Configuration cf,
+                               Function<String, ClassLoader> clf) {
+        return defineModules(cf, List.of(this), clf).layer();
+    }
+
+    /**
+     * Creates a new layer by defining the modules in the given {@code
+     * Configuration} to the Java virtual machine. This method creates one
+     * class loader and defines all modules to that class loader.
      *
      * <p> The class loader created by this method implements <em>direct
      * delegation</em> when loading types from modules. When its {@link
@@ -180,7 +407,7 @@
      * <ul>
      *
      *     <li><p> <em>Overlapping packages</em>: Two or more modules in the
-     *     configuration have the same package (exported or concealed). </p></li>
+     *     configuration have the same package. </p></li>
      *
      *     <li><p> <em>Split delegation</em>: The resulting class loader would
      *     need to delegate to more than one class loader in order to load types
@@ -194,19 +421,22 @@
      *
      * @param  cf
      *         The configuration for the layer
+     * @param  parentLayers
+     *         The list parent layers in search order
      * @param  parentLoader
      *         The parent class loader for the class loader created by this
      *         method; may be {@code null} for the bootstrap class loader
      *
-     * @return The newly created layer
+     * @return A controller that controls the newly created layer
      *
      * @throws IllegalArgumentException
-     *         If the parent of the given configuration is not the configuration
-     *         for this layer
+     *         If the parent configurations do not match the configuration of
+     *         the parent layers, including order
      * @throws LayerInstantiationException
      *         If all modules cannot be defined to the same class loader for any
      *         of the reasons listed above or the layer cannot be created because
-     *         the configuration contains a module named "{@code java.base}"
+     *         the configuration contains a module named "{@code java.base}" or
+     *         a module with a package name starting with "{@code java.}"
      * @throws SecurityException
      *         If {@code RuntimePermission("createClassLoader")} or
      *         {@code RuntimePermission("getClassLoader")} is denied by
@@ -214,29 +444,32 @@
      *
      * @see #findLoader
      */
-    public Layer defineModulesWithOneLoader(Configuration cf,
-                                            ClassLoader parentLoader)
+    public static Controller defineModulesWithOneLoader(Configuration cf,
+                                                        List<Layer> parentLayers,
+                                                        ClassLoader parentLoader)
     {
-        checkConfiguration(cf);
+        List<Layer> parents = new ArrayList<>(parentLayers);
+        checkConfiguration(cf, parents);
+
         checkCreateClassLoaderPermission();
         checkGetClassLoaderPermission();
 
         try {
             Loader loader = new Loader(cf.modules(), parentLoader);
-            loader.initRemotePackageMap(cf, this);
-            return new Layer(cf, this, mn -> loader);
+            loader.initRemotePackageMap(cf, parents);
+            Layer layer =  new Layer(cf, parents, mn -> loader);
+            return new Controller(layer);
         } catch (IllegalArgumentException e) {
             throw new LayerInstantiationException(e.getMessage());
         }
     }
 
-
     /**
-     * Creates a new layer, with this layer as its parent, by defining the
-     * modules in the given {@code Configuration} to the Java virtual machine.
-     * Each module is defined to its own {@link ClassLoader} created by this
-     * method. The {@link ClassLoader#getParent() parent} of each class loader
-     * is the given parent class loader.
+     * Creates a new layer by defining the modules in the given {@code
+     * Configuration} to the Java virtual machine. Each module is defined to
+     * its own {@link ClassLoader} created by this method. The {@link
+     * ClassLoader#getParent() parent} of each class loader is the given parent
+     * class loader.
      *
      * <p> The class loaders created by this method implement <em>direct
      * delegation</em> when loading types from modules. When {@link
@@ -258,18 +491,21 @@
      *
      * @param  cf
      *         The configuration for the layer
+     * @param  parentLayers
+     *         The list parent layers in search order
      * @param  parentLoader
      *         The parent class loader for each of the class loaders created by
      *         this method; may be {@code null} for the bootstrap class loader
      *
-     * @return The newly created layer
+     * @return A controller that controls the newly created layer
      *
      * @throws IllegalArgumentException
-     *         If the parent of the given configuration is not the configuration
-     *         for this layer
+     *         If the parent configurations do not match the configuration of
+     *         the parent layers, including order
      * @throws LayerInstantiationException
      *         If the layer cannot be created because the configuration contains
-     *         a module named "{@code java.base}"
+     *         a module named "{@code java.base}" or a module with a package
+     *         name starting with "{@code java.}"
      * @throws SecurityException
      *         If {@code RuntimePermission("createClassLoader")} or
      *         {@code RuntimePermission("getClassLoader")} is denied by
@@ -277,37 +513,43 @@
      *
      * @see #findLoader
      */
-    public Layer defineModulesWithManyLoaders(Configuration cf,
-                                              ClassLoader parentLoader)
+    public static Controller defineModulesWithManyLoaders(Configuration cf,
+                                                          List<Layer> parentLayers,
+                                                          ClassLoader parentLoader)
     {
-        checkConfiguration(cf);
+        List<Layer> parents = new ArrayList<>(parentLayers);
+        checkConfiguration(cf, parents);
+
         checkCreateClassLoaderPermission();
         checkGetClassLoaderPermission();
 
-        LoaderPool pool = new LoaderPool(cf, this, parentLoader);
+        LoaderPool pool = new LoaderPool(cf, parents, parentLoader);
         try {
-            return new Layer(cf, this, pool::loaderFor);
+            Layer layer = new Layer(cf, parents, pool::loaderFor);
+            return new Controller(layer);
         } catch (IllegalArgumentException e) {
             throw new LayerInstantiationException(e.getMessage());
         }
     }
 
-
     /**
-     * Creates a new layer, with this layer as its parent, by defining the
-     * modules in the given {@code Configuration} to the Java virtual machine.
+     * Creates a new layer by defining the modules in the given {@code
+     * Configuration} to the Java virtual machine.
      * Each module is mapped, by name, to its class loader by means of the
      * given function. The class loader delegation implemented by these class
-     * loaders must respect module readability. In addition, the caller needs
-     * to arrange that the class loaders are ready to load from these module
-     * before there are any attempts to load classes or resources.
+     * loaders must respect module readability. The class loaders should be
+     * {@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
+     * classes or resources.
      *
      * <p> Creating a {@code Layer} can fail for the following reasons: </p>
      *
      * <ul>
      *
-     *     <li><p> Two or more modules with the same package (exported or
-     *     concealed) are mapped to the same class loader. </p></li>
+     *     <li><p> Two or more modules with the same package are mapped to the
+     *     same class loader. </p></li>
      *
      *     <li><p> A module is mapped to a class loader that already has a
      *     module of the same name defined to it. </p></li>
@@ -328,26 +570,35 @@
      *
      * @param  cf
      *         The configuration for the layer
+     * @param  parentLayers
+     *         The list parent layers in search order
      * @param  clf
      *         The function to map a module name to a class loader
      *
-     * @return The newly created layer
+     * @return A controller that controls the newly created layer
      *
      * @throws IllegalArgumentException
-     *         If the parent of the given configuration is not the configuration
-     *         for this layer
+     *         If the parent configurations do not match the configuration of
+     *         the parent layers, including order
      * @throws LayerInstantiationException
      *         If creating the {@code Layer} fails for any of the reasons
-     *         listed above or the layer cannot be created because the
-     *         configuration contains a module named "{@code java.base}"
+     *         listed above, the layer cannot be created because the
+     *         configuration contains a module named "{@code java.base}",
+     *         a module with a package name starting with "{@code java.}" is
+     *         mapped to a class loader other than the {@link
+     *         ClassLoader#getPlatformClassLoader() platform class loader},
+     *         or the function to map a module name to a class loader returns
+     *         {@code null}
      * @throws SecurityException
      *         If {@code RuntimePermission("getClassLoader")} is denied by
      *         the security manager
      */
-    public Layer defineModules(Configuration cf,
-                               Function<String, ClassLoader> clf)
+    public static Controller defineModules(Configuration cf,
+                                           List<Layer> parentLayers,
+                                           Function<String, ClassLoader> clf)
     {
-        checkConfiguration(cf);
+        List<Layer> parents = new ArrayList<>(parentLayers);
+        checkConfiguration(cf, parents);
         Objects.requireNonNull(clf);
 
         checkGetClassLoaderPermission();
@@ -362,7 +613,8 @@
         }
 
         try {
-            return new Layer(cf, this, clf);
+            Layer layer = new Layer(cf, parents, clf);
+            return new Controller(layer);
         } catch (IllegalArgumentException iae) {
             // IAE is thrown by VM when defining the module fails
             throw new LayerInstantiationException(iae.getMessage());
@@ -370,13 +622,26 @@
     }
 
 
-    private void checkConfiguration(Configuration cf) {
+    /**
+     * Checks that the parent configurations match the configuration of
+     * the parent layers.
+     */
+    private static void checkConfiguration(Configuration cf,
+                                           List<Layer> parentLayers)
+    {
         Objects.requireNonNull(cf);
 
-        Optional<Configuration> oparent = cf.parent();
-        if (!oparent.isPresent() || oparent.get() != this.configuration()) {
-            throw new IllegalArgumentException(
-                    "Parent of configuration != configuration of this Layer");
+        List<Configuration> parentConfigurations = cf.parents();
+        if (parentLayers.size() != parentConfigurations.size())
+            throw new IllegalArgumentException("wrong number of parents");
+
+        int index = 0;
+        for (Layer parent : parentLayers) {
+            if (parent.configuration() != parentConfigurations.get(index)) {
+                throw new IllegalArgumentException(
+                        "Parent of configuration != configuration of this Layer");
+            }
+            index++;
         }
     }
 
@@ -463,18 +728,57 @@
 
 
     /**
-     * Returns this layer's parent unless this is the {@linkplain #empty empty
-     * layer}, which has no parent.
+     * Returns the list of this layer's parents unless this is the
+     * {@linkplain #empty empty layer}, which has no parents and so an
+     * empty list is returned.
      *
-     * @return This layer's parent
+     * @return The list of this layer's parents
      */
-    public Optional<Layer> parent() {
-        return Optional.ofNullable(parent);
+    public List<Layer> parents() {
+        return parents;
     }
 
 
     /**
-     * Returns a set of the modules in this layer.
+     * Returns an ordered stream of layers. The first element is is this layer,
+     * the remaining elements are the parent layers in DFS order.
+     *
+     * @implNote For now, the assumption is that the number of elements will
+     * be very low and so this method does not use a specialized spliterator.
+     */
+    Stream<Layer> layers() {
+        List<Layer> allLayers = this.allLayers;
+        if (allLayers != null)
+            return allLayers.stream();
+
+        allLayers = new ArrayList<>();
+        Set<Layer> visited = new HashSet<>();
+        Deque<Layer> stack = new ArrayDeque<>();
+        visited.add(this);
+        stack.push(this);
+
+        while (!stack.isEmpty()) {
+            Layer layer = stack.pop();
+            allLayers.add(layer);
+
+            // push in reverse order
+            for (int i = layer.parents.size() - 1; i >= 0; i--) {
+                Layer parent = layer.parents.get(i);
+                if (!visited.contains(parent)) {
+                    visited.add(parent);
+                    stack.push(parent);
+                }
+            }
+        }
+
+        this.allLayers = allLayers = Collections.unmodifiableList(allLayers);
+        return allLayers.stream();
+    }
+
+    private volatile List<Layer> allLayers;
+
+    /**
+     * Returns the set of the modules in this layer.
      *
      * @return A possibly-empty unmodifiable set of the modules in this layer
      */
@@ -486,7 +790,11 @@
 
     /**
      * Returns the module with the given name in this layer, or if not in this
-     * layer, the {@linkplain #parent parent} layer.
+     * layer, the {@linkplain #parents parents} layers. Finding a module in
+     * parent layers is equivalent to invoking {@code findModule} on each
+     * parent, in search order, until the module is found or all parents have
+     * been searched. In a <em>tree of layers</em>  then this is equivalent to
+     * a depth-first search.
      *
      * @param  name
      *         The name of the module to find
@@ -496,17 +804,25 @@
      *         parent layer
      */
     public Optional<Module> findModule(String name) {
-        Module m = nameToModule.get(Objects.requireNonNull(name));
+        Objects.requireNonNull(name);
+        Module m = nameToModule.get(name);
         if (m != null)
             return Optional.of(m);
-        return parent().flatMap(l -> l.findModule(name));
+
+        return layers()
+                .skip(1)  // skip this layer
+                .map(l -> l.nameToModule)
+                .filter(map -> map.containsKey(name))
+                .map(map -> map.get(name))
+                .findAny();
     }
 
 
     /**
      * Returns the {@code ClassLoader} for the module with the given name. If
-     * a module of the given name is not in this layer then the {@link #parent}
-     * layer is checked.
+     * a module of the given name is not in this layer then the {@link #parents
+     * parent} layers are searched in the manner specified by {@link
+     * #findModule(String) findModule}.
      *
      * <p> If there is a security manager then its {@code checkPermission}
      * method is called with a {@code RuntimePermission("getClassLoader")}
@@ -527,20 +843,32 @@
      * @throws SecurityException if denied by the security manager
      */
     public ClassLoader findLoader(String name) {
-        Module m = nameToModule.get(Objects.requireNonNull(name));
-        if (m != null)
-            return m.getClassLoader();
-        Optional<Layer> ol = parent();
-        if (ol.isPresent())
-            return ol.get().findLoader(name);
-        throw new IllegalArgumentException("Module " + name
-                                           + " not known to this layer");
+        Optional<Module> om = findModule(name);
+
+        // can't use map(Module::getClassLoader) as class loader can be null
+        if (om.isPresent()) {
+            return om.get().getClassLoader();
+        } else {
+            throw new IllegalArgumentException("Module " + name
+                                               + " not known to this layer");
+        }
     }
 
+    /**
+     * Returns a string describing this layer.
+     *
+     * @return A possibly empty string describing this layer
+     */
+    @Override
+    public String toString() {
+        return modules().stream()
+                .map(Module::getName)
+                .collect(Collectors.joining(", "));
+    }
 
     /**
      * Returns the <em>empty</em> layer. There are no modules in the empty
-     * layer. It has no parent.
+     * layer. It has no parents.
      *
      * @return The empty layer
      */
@@ -572,39 +900,12 @@
         if (servicesCatalog != null)
             return servicesCatalog;
 
-        Map<String, Set<ServiceProvider>> map = new HashMap<>();
-        for (Module m : nameToModule.values()) {
-            ModuleDescriptor descriptor = m.getDescriptor();
-            for (Provides provides : descriptor.provides().values()) {
-                String service = provides.service();
-                Set<ServiceProvider> providers
-                    = map.computeIfAbsent(service, k -> new HashSet<>());
-                for (String pn : provides.providers()) {
-                    providers.add(new ServiceProvider(m, pn));
-                }
-            }
-        }
-
-        ServicesCatalog catalog = new ServicesCatalog() {
-            @Override
-            public void register(Module module) {
-                throw new UnsupportedOperationException();
-            }
-            @Override
-            public Set<ServiceProvider> findServices(String service) {
-                Set<ServiceProvider> providers = map.get(service);
-                if (providers == null) {
-                    return Collections.emptySet();
-                } else {
-                    return Collections.unmodifiableSet(providers);
-                }
-            }
-        };
-
         synchronized (this) {
             servicesCatalog = this.servicesCatalog;
             if (servicesCatalog == null) {
-                this.servicesCatalog = servicesCatalog = catalog;
+                servicesCatalog = ServicesCatalog.create();
+                nameToModule.values().forEach(servicesCatalog::register);
+                this.servicesCatalog = servicesCatalog;
             }
         }
 
@@ -612,4 +913,36 @@
     }
 
     private volatile ServicesCatalog servicesCatalog;
+
+
+    /**
+     * Record that this layer has at least one module defined to the given
+     * class loader.
+     */
+    void bindToLoader(ClassLoader loader) {
+        // CLV.computeIfAbsent(loader, (cl, clv) -> new CopyOnWriteArrayList<>())
+        List<Layer> list = CLV.get(loader);
+        if (list == null) {
+            list = new CopyOnWriteArrayList<>();
+            List<Layer> previous = CLV.putIfAbsent(loader, list);
+            if (previous != null) list = previous;
+        }
+        list.add(this);
+    }
+
+    /**
+     * Returns a stream of the layers that have at least one module defined to
+     * the given class loader.
+     */
+    static Stream<Layer> layers(ClassLoader loader) {
+        List<Layer> list = CLV.get(loader);
+        if (list != null) {
+            return list.stream();
+        } else {
+            return Stream.empty();
+        }
+    }
+
+    // the list of layers with modules defined to a class loader
+    private static final ClassLoaderValue<List<Layer>> CLV = new ClassLoaderValue<>();
 }
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,15 +27,18 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.annotation.Annotation;
 import java.lang.module.Configuration;
 import java.lang.module.ModuleReference;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
-import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Version;
 import java.lang.module.ResolvedModule;
 import java.net.URI;
 import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -49,9 +52,17 @@
 
 import jdk.internal.loader.BuiltinClassLoader;
 import jdk.internal.loader.BootLoader;
+import jdk.internal.loader.ResourceHelper;
+import jdk.internal.misc.JavaLangAccess;
 import jdk.internal.misc.JavaLangReflectModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ServicesCatalog;
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import sun.security.util.SecurityConstants;
@@ -83,7 +94,7 @@
  * @see java.lang.Class#getModule
  */
 
-public final class Module {
+public final class Module implements AnnotatedElement {
 
     // the layer that contains this module, can be null
     private final Layer layer;
@@ -113,6 +124,10 @@
 
         // define module to VM
 
+        boolean isOpen = descriptor.isOpen();
+        Version version = descriptor.version().orElse(null);
+        String vs = Objects.toString(version, null);
+        String loc = Objects.toString(uri, null);
         Set<String> packages = descriptor.packages();
         int n = packages.size();
         String[] array = new String[n];
@@ -120,11 +135,7 @@
         for (String pn : packages) {
             array[i++] = pn.replace('.', '/');
         }
-        Version version = descriptor.version().orElse(null);
-        String vs = Objects.toString(version, null);
-        String loc = Objects.toString(uri, null);
-
-        defineModule0(this, vs, loc, array);
+        defineModule0(this, isOpen, vs, loc, array);
     }
 
 
@@ -240,24 +251,24 @@
 
     // --
 
-    // the special Module to mean reads or exported to "all unnamed modules"
+    // special Module to mean "all unnamed modules"
     private static final Module ALL_UNNAMED_MODULE = new Module(null);
 
-    // special Module to mean exported to "everyone"
+    // special Module to mean "everyone"
     private static final Module EVERYONE_MODULE = new Module(null);
 
-    // exported to all modules
-    private static final Set<Module> EVERYONE = Collections.singleton(EVERYONE_MODULE);
+    // set contains EVERYONE_MODULE, used when a package is opened or
+    // exported unconditionally
+    private static final Set<Module> EVERYONE_SET = Set.of(EVERYONE_MODULE);
 
 
     // -- readability --
 
-    // the modules that this module permanently reads
-    // (will be final when the modules are defined in reverse topology order)
+    // the modules that this module reads
     private volatile Set<Module> reads;
 
     // additional module (2nd key) that some module (1st key) reflectively reads
-    private static final WeakPairMap<Module, Module, Boolean> transientReads
+    private static final WeakPairMap<Module, Module, Boolean> reflectivelyReads
         = new WeakPairMap<>();
 
 
@@ -293,13 +304,13 @@
         }
 
         // check if this module reads the other module reflectively
-        if (transientReads.containsKeyPair(this, other))
+        if (reflectivelyReads.containsKeyPair(this, other))
             return true;
 
         // if other is an unnamed module then check if this module reads
         // all unnamed modules
         if (!other.isNamed()
-            && transientReads.containsKeyPair(this, ALL_UNNAMED_MODULE))
+            && reflectivelyReads.containsKeyPair(this, ALL_UNNAMED_MODULE))
             return true;
 
         return false;
@@ -309,9 +320,13 @@
      * If the caller's module is this module then update this module to read
      * the given module.
      *
-     * This method is a no-op if {@code other} is this module (all modules can
-     * read themselves) or this module is an unnamed module (as unnamed modules
-     * read all modules).
+     * This method is a no-op if {@code other} is this module (all modules read
+     * themselves), this module is an unnamed module (as unnamed modules read
+     * all modules), or this module already reads {@code other}.
+     *
+     * @implNote <em>Read edges</em> added by this method are <em>weak</em> and
+     * do not prevent {@code other} from being GC'ed when this module is
+     * strongly reachable.
      *
      * @param  other
      *         The other module
@@ -381,30 +396,39 @@
         }
 
         // add reflective read
-        transientReads.putIfAbsent(this, other, Boolean.TRUE);
+        reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE);
     }
 
 
-    // -- exports --
+    // -- exported and open packages --
+
+    // the packages are open to other modules, can be null
+    // if the value contains EVERYONE_MODULE then the package is open to all
+    private volatile Map<String, Set<Module>> openPackages;
 
-    // the packages that are permanently exported
-    // (will be final when the modules are defined in reverse topology order)
-    private volatile Map<String, Set<Module>> exports;
+    // the packages that are exported, can be null
+    // if the value contains EVERYONE_MODULE then the package is exported to all
+    private volatile Map<String, Set<Module>> exportedPackages;
 
-    // additional exports added at run-time
-    // this module (1st key), other module (2nd key), exported packages (value)
+    // additional exports or opens added at run-time
+    // this module (1st key), other module (2nd key)
+    // (package name, open?) (value)
     private static final WeakPairMap<Module, Module, Map<String, Boolean>>
-        transientExports = new WeakPairMap<>();
+        reflectivelyExports = new WeakPairMap<>();
 
 
     /**
      * Returns {@code true} if this module exports the given package to at
      * least the given module.
      *
-     * <p> This method always return {@code true} when invoked on an unnamed
+     * <p> This method returns {@code true} if invoked to test if a package in
+     * this module is exported to itself. It always returns {@code true} when
+     * invoked on an unnamed module. A package that is {@link #isOpen open} to
+     * the given module is considered exported to that module at run-time and
+     * so this method returns {@code true} if the package is open to the given
      * module. </p>
      *
-     * <p> This method does not check if the given module reads this module </p>
+     * <p> This method does not check if the given module reads this module. </p>
      *
      * @param  pn
      *         The package name
@@ -413,93 +437,196 @@
      *
      * @return {@code true} if this module exports the package to at least the
      *         given module
+     *
+     * @see ModuleDescriptor#exports()
+     * @see #addExports(String,Module)
      */
     public boolean isExported(String pn, Module other) {
         Objects.requireNonNull(pn);
         Objects.requireNonNull(other);
-        return implIsExported(pn, other);
+        return implIsExportedOrOpen(pn, other, /*open*/false);
+    }
+
+    /**
+     * Returns {@code true} if this module has <em>opened</em> a package to at
+     * least the given module.
+     *
+     * <p> This method returns {@code true} if invoked to test if a package in
+     * this module is open to itself. It returns {@code true} when invoked on an
+     * {@link ModuleDescriptor#isOpen open} module with a package in the module.
+     * It always returns {@code true} when invoked on an unnamed module. </p>
+     *
+     * <p> This method does not check if the given module reads this module. </p>
+     *
+     * @param  pn
+     *         The package name
+     * @param  other
+     *         The other module
+     *
+     * @return {@code true} if this module has <em>opened</em> the package
+     *         to at least the given module
+     *
+     * @see ModuleDescriptor#opens()
+     * @see #addOpens(String,Module)
+     * @see AccessibleObject#setAccessible(boolean)
+     * @see java.lang.invoke.MethodHandles#privateLookupIn
+     */
+    public boolean isOpen(String pn, Module other) {
+        Objects.requireNonNull(pn);
+        Objects.requireNonNull(other);
+        return implIsExportedOrOpen(pn, other, /*open*/true);
     }
 
     /**
      * Returns {@code true} if this module exports the given package
      * unconditionally.
      *
-     * <p> This method always return {@code true} when invoked on an unnamed
-     * module. </p>
+     * <p> This method always returns {@code true} when invoked on an unnamed
+     * module. A package that is {@link #isOpen(String) opened} unconditionally
+     * is considered exported unconditionally at run-time and so this method
+     * returns {@code true} if the package is opened unconditionally. </p>
      *
-     * <p> This method does not check if the given module reads this module </p>
+     * <p> This method does not check if the given module reads this module. </p>
      *
      * @param  pn
      *         The package name
      *
      * @return {@code true} if this module exports the package unconditionally
+     *
+     * @see ModuleDescriptor#exports()
      */
     public boolean isExported(String pn) {
         Objects.requireNonNull(pn);
-        return implIsExported(pn, EVERYONE_MODULE);
+        return implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/false);
     }
 
     /**
-     * Returns {@code true} if this module exports the given package to the
-     * given module. If the other module is {@code EVERYONE_MODULE} then
-     * this method tests if the package is exported unconditionally.
+     * Returns {@code true} if this module has <em>opened</em> a package
+     * unconditionally.
+     *
+     * <p> This method always returns {@code true} when invoked on an unnamed
+     * module. Additionally, it always returns {@code true} when invoked on an
+     * {@link ModuleDescriptor#isOpen open} module with a package in the
+     * module. </p>
+     *
+     * <p> This method does not check if the given module reads this module. </p>
+     *
+     * @param  pn
+     *         The package name
+     *
+     * @return {@code true} if this module has <em>opened</em> the package
+     *         unconditionally
+     *
+     * @see ModuleDescriptor#opens()
      */
-    private boolean implIsExported(String pn, Module other) {
+    public boolean isOpen(String pn) {
+        Objects.requireNonNull(pn);
+        return implIsExportedOrOpen(pn, EVERYONE_MODULE, /*open*/true);
+    }
+
 
-        // all packages are exported by unnamed modules
+    /**
+     * Returns {@code true} if this module exports or opens the given package
+     * to the given module. If the other module is {@code EVERYONE_MODULE} then
+     * this method tests if the package is exported or opened unconditionally.
+     */
+    private boolean implIsExportedOrOpen(String pn, Module other, boolean open) {
+        // all packages in unnamed modules are open
         if (!isNamed())
             return true;
 
-        // exported via module declaration/descriptor
-        if (isExportedPermanently(pn, other))
+        // all packages are exported/open to self
+        if (other == this && containsPackage(pn))
             return true;
 
-        // exported via addExports
-        if (isExportedReflectively(pn, other))
+        // all packages in open modules are open
+        if (descriptor.isOpen())
+            return containsPackage(pn);
+
+        // exported/opened via module declaration/descriptor
+        if (isStaticallyExportedOrOpen(pn, other, open))
             return true;
 
-        // not exported or not exported to other
+        // exported via addExports/addOpens
+        if (isReflectivelyExportedOrOpen(pn, other, open))
+            return true;
+
+        // not exported or open to other
         return false;
     }
 
     /**
-     * Returns {@code true} if this module permanently exports the given
-     * package to the given module.
+     * Returns {@code true} if this module exports or opens a package to
+     * the given module via its module declaration.
      */
-    private boolean isExportedPermanently(String pn, Module other) {
-        Map<String, Set<Module>> exports = this.exports;
-        if (exports != null) {
-            Set<Module> targets = exports.get(pn);
+    private 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) {
+            Set<Module> targets = openPackages.get(pn);
+            if (targets != null) {
+                if (targets.contains(EVERYONE_MODULE))
+                    return true;
+                if (other != EVERYONE_MODULE && targets.contains(other))
+                    return true;
+            }
+        }
 
-            if ((targets != null)
-                && (targets.contains(other) || targets.contains(EVERYONE_MODULE)))
-                return true;
+        if (!open) {
+            // package is exported to everyone or <other>
+            Map<String, Set<Module>> exportedPackages = this.exportedPackages;
+            if (exportedPackages != null) {
+                Set<Module> targets = exportedPackages.get(pn);
+                if (targets != null) {
+                    if (targets.contains(EVERYONE_MODULE))
+                        return true;
+                    if (other != EVERYONE_MODULE && targets.contains(other))
+                        return true;
+                }
+            }
         }
+
         return false;
     }
 
+
     /**
-     * Returns {@code true} if this module reflectively exports the given
+     * Returns {@code true} if this module reflectively exports or opens given
      * package package to the given module.
      */
-    private boolean isExportedReflectively(String pn, Module other) {
-        // exported to all modules
-        Map<String, ?> exports = transientExports.get(this, EVERYONE_MODULE);
-        if (exports != null && exports.containsKey(pn))
-            return true;
+    private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) {
+        // exported or open to all modules
+        Map<String, Boolean> exports = reflectivelyExports.get(this, EVERYONE_MODULE);
+        if (exports != null) {
+            Boolean b = exports.get(pn);
+            if (b != null) {
+                boolean isOpen = b.booleanValue();
+                if (!open || isOpen) return true;
+            }
+        }
 
         if (other != EVERYONE_MODULE) {
 
-            // exported to other
-            exports = transientExports.get(this, other);
-            if (exports != null && exports.containsKey(pn))
-                return true;
+            // exported or open to other
+            exports = reflectivelyExports.get(this, other);
+            if (exports != null) {
+                Boolean b = exports.get(pn);
+                if (b != null) {
+                    boolean isOpen = b.booleanValue();
+                    if (!open || isOpen) return true;
+                }
+            }
 
-            // other is an unnamed module && exported to all unnamed
+            // other is an unnamed module && exported or open to all unnamed
             if (!other.isNamed()) {
-                exports = transientExports.get(this, ALL_UNNAMED_MODULE);
-                if (exports != null && exports.containsKey(pn))
-                    return true;
+                exports = reflectivelyExports.get(this, ALL_UNNAMED_MODULE);
+                if (exports != null) {
+                    Boolean b = exports.get(pn);
+                    if (b != null) {
+                        boolean isOpen = b.booleanValue();
+                        if (!open || isOpen) return true;
+                    }
+                }
             }
 
         }
@@ -510,11 +637,11 @@
 
     /**
      * If the caller's module is this module then update this module to export
-     * package {@code pn} to the given module.
+     * the given package to the given module.
      *
-     * <p> This method has no effect if the package is already exported to the
-     * given module. It also has no effect if invoked on an unnamed module (as
-     * unnamed modules export all packages). </p>
+     * <p> This method has no effect if the package is already exported (or
+     * <em>open</em>) to the given module. It also has no effect if
+     * invoked on an {@link ModuleDescriptor#isOpen open} module. </p>
      *
      * @param  pn
      *         The package name
@@ -528,6 +655,8 @@
      *         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
+     *
+     * @see #isExported(String,Module)
      */
     @CallerSensitive
     public Module addExports(String pn, Module other) {
@@ -535,18 +664,66 @@
             throw new IllegalArgumentException("package is null");
         Objects.requireNonNull(other);
 
-        if (isNamed()) {
+        if (isNamed() && !descriptor.isOpen()) {
             Module caller = Reflection.getCallerClass().getModule();
             if (caller != this) {
                 throw new IllegalStateException(caller + " != " + this);
             }
-            implAddExports(pn, other, true);
+            implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true);
         }
 
         return this;
     }
 
     /**
+     * If the caller's module is this module then update this module to
+     * <em>open</em> the given 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
+     * private access or a way to bypass or suppress default Java language
+     * access control checks.
+     *
+     * <p> This method has no effect if the package is already <em>open</em>
+     * to the given module. It also has no effect if invoked on an {@link
+     * ModuleDescriptor#isOpen open} module. </p>
+     *
+     * @param  pn
+     *         The package name
+     * @param  other
+     *         The module
+     *
+     * @return this module
+     *
+     * @throws IllegalArgumentException
+     *         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
+     *
+     * @see #isOpen(String,Module)
+     * @see AccessibleObject#setAccessible(boolean)
+     * @see java.lang.invoke.MethodHandles#privateLookupIn
+     */
+    @CallerSensitive
+    public Module addOpens(String pn, Module other) {
+        if (pn == null)
+            throw new IllegalArgumentException("package is null");
+        Objects.requireNonNull(other);
+
+        if (isNamed() && !descriptor.isOpen()) {
+            Module caller = Reflection.getCallerClass().getModule();
+            if (caller != this) {
+                throw new IllegalStateException(caller + " != " + this);
+            }
+            implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
+        }
+
+        return this;
+    }
+
+
+    /**
      * Updates the exports so that package {@code pn} is exported to module
      * {@code other} but without notifying the VM.
      *
@@ -555,7 +732,7 @@
     void implAddExportsNoSync(String pn, Module other) {
         if (other == null)
             other = EVERYONE_MODULE;
-        implAddExports(pn.replace('/', '.'), other, false);
+        implAddExportsOrOpens(pn.replace('/', '.'), other, false, false);
     }
 
     /**
@@ -565,25 +742,36 @@
      * @apiNote This method is for white-box testing.
      */
     void implAddExports(String pn, Module other) {
-        implAddExports(pn, other, true);
+        implAddExportsOrOpens(pn, other, false, true);
     }
 
     /**
-     * Updates the exports so that package {@code pn} is exported to module
-     * {@code other}.
+     * Updates the module to open package {@code pn} to module {@code other}.
+     *
+     * @apiNote This method is for white-box tests and jtreg
+     */
+    void implAddOpens(String pn, Module other) {
+        implAddExportsOrOpens(pn, other, true, true);
+    }
+
+    /**
+     * Updates a module to export or open a module to another module.
      *
      * If {@code syncVM} is {@code true} then the VM is notified.
      */
-    private void implAddExports(String pn, Module other, boolean syncVM) {
+    private void implAddExportsOrOpens(String pn,
+                                       Module other,
+                                       boolean open,
+                                       boolean syncVM) {
         Objects.requireNonNull(other);
         Objects.requireNonNull(pn);
 
-        // unnamed modules export all packages
-        if (!isNamed())
+        // all packages are open in unnamed and open modules
+        if (!isNamed() || descriptor.isOpen())
             return;
 
-        // nothing to do if already exported to other
-        if (implIsExported(pn, other))
+        // nothing to do if already exported/open to other
+        if (implIsExportedOrOpen(pn, other, open))
             return;
 
         // can only export a package in the module
@@ -604,18 +792,23 @@
             }
         }
 
-        // add package name to transientExports if absent
-        transientExports
+        // add package name to reflectivelyExports if absent
+        Map<String, Boolean> map = reflectivelyExports
             .computeIfAbsent(this, other,
-                             (_this, _other) -> new ConcurrentHashMap<>())
-            .putIfAbsent(pn, Boolean.TRUE);
+                             (m1, m2) -> new ConcurrentHashMap<>());
+
+        if (open) {
+            map.put(pn, Boolean.TRUE);  // may need to promote from FALSE to TRUE
+        } else {
+            map.putIfAbsent(pn, Boolean.FALSE);
+        }
     }
 
 
     // -- services --
 
     // additional service type (2nd key) that some module (1st key) uses
-    private static final WeakPairMap<Module, Class<?>, Boolean> transientUses
+    private static final WeakPairMap<Module, Class<?>, Boolean> reflectivelyUses
         = new WeakPairMap<>();
 
     /**
@@ -624,13 +817,13 @@
      * for use by frameworks that invoke {@link java.util.ServiceLoader
      * ServiceLoader} on behalf of other modules or where the framework is
      * passed a reference to the service type by other code. This method is
-     * a no-op when invoked on an unnamed module.
+     * a no-op when invoked on an unnamed module or an automatic module.
      *
      * <p> This method does not cause {@link
      * Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be
      * re-run. </p>
      *
-     * @param  st
+     * @param  service
      *         The service type
      *
      * @return this module
@@ -642,39 +835,45 @@
      * @see ModuleDescriptor#uses()
      */
     @CallerSensitive
-    public Module addUses(Class<?> st) {
-        Objects.requireNonNull(st);
+    public Module addUses(Class<?> service) {
+        Objects.requireNonNull(service);
 
-        if (isNamed()) {
-
+        if (isNamed() && !descriptor.isAutomatic()) {
             Module caller = Reflection.getCallerClass().getModule();
             if (caller != this) {
                 throw new IllegalStateException(caller + " != " + this);
             }
-
-            if (!canUse(st)) {
-                transientUses.putIfAbsent(this, st, Boolean.TRUE);
-            }
-
+            implAddUses(service);
         }
 
         return this;
     }
 
     /**
+     * Update this module to add a service dependence on the given service
+     * type.
+     */
+    void implAddUses(Class<?> service) {
+        if (!canUse(service)) {
+            reflectivelyUses.putIfAbsent(this, service, Boolean.TRUE);
+        }
+    }
+
+
+    /**
      * Indicates if this module has a service dependence on the given service
      * type. This method always returns {@code true} when invoked on an unnamed
-     * module.
+     * module or an automatic module.
      *
-     * @param  st
+     * @param  service
      *         The service type
      *
      * @return {@code true} if this module uses service type {@code st}
      *
      * @see #addUses(Class)
      */
-    public boolean canUse(Class<?> st) {
-        Objects.requireNonNull(st);
+    public boolean canUse(Class<?> service) {
+        Objects.requireNonNull(service);
 
         if (!isNamed())
             return true;
@@ -683,11 +882,11 @@
             return true;
 
         // uses was declared
-        if (descriptor.uses().contains(st.getName()))
+        if (descriptor.uses().contains(service.getName()))
             return true;
 
         // uses added via addUses
-        return transientUses.containsKeyPair(this, st);
+        return reflectivelyUses.containsKeyPair(this, service);
     }
 
 
@@ -780,8 +979,12 @@
      * If {@code syncVM} is {@code true} then the VM is notified.
      */
     private void implAddPackage(String pn, boolean syncVM) {
-        if (pn.length() == 0)
-            throw new IllegalArgumentException("<unnamed> package not allowed");
+        if (!isNamed())
+            throw new InternalError("adding package to unnamed module?");
+        if (descriptor.isOpen())
+            throw new InternalError("adding package to open module?");
+        if (pn.isEmpty())
+            throw new InternalError("adding <unnamed> package to module?");
 
         if (descriptor.packages().contains(pn)) {
             // already in module
@@ -822,28 +1025,7 @@
     // -- creating Module objects --
 
     /**
-     * Find the runtime Module corresponding to the given ResolvedModule
-     * in the given parent Layer (or its parents).
-     */
-    private static Module find(ResolvedModule resolvedModule, Layer layer) {
-        Configuration cf = resolvedModule.configuration();
-        String dn = resolvedModule.name();
-
-        Module m = null;
-        while (layer != null) {
-            if (layer.configuration() == cf) {
-                Optional<Module> om = layer.findModule(dn);
-                m = om.get();
-                assert m.getLayer() == layer;
-                break;
-            }
-            layer = layer.parent().orElse(null);
-        }
-        return m;
-    }
-
-    /**
-     * Defines each of the module in the given configuration to the runtime.
+     * Defines all module in a configuration to the runtime.
      *
      * @return a map of module name to runtime {@code Module}
      *
@@ -854,26 +1036,40 @@
                                              Function<String, ClassLoader> clf,
                                              Layer layer)
     {
-        Map<String, Module> modules = new HashMap<>();
-        Map<String, ClassLoader> loaders = new HashMap<>();
+        Map<String, Module> nameToModule = new HashMap<>();
+        Map<String, ClassLoader> moduleToLoader = new HashMap<>();
+
+        boolean isBootLayer = (Layer.boot() == null);
+        Set<ClassLoader> loaders = new HashSet<>();
+
+        // map each module to a class loader
+        for (ResolvedModule resolvedModule : cf.modules()) {
+            String name = resolvedModule.name();
+            ClassLoader loader = clf.apply(name);
+            if (loader != null) {
+                moduleToLoader.put(name, loader);
+                loaders.add(loader);
+            } else if (!isBootLayer) {
+                throw new IllegalArgumentException("loader can't be 'null'");
+            }
+        }
 
         // define each module in the configuration to the VM
         for (ResolvedModule resolvedModule : cf.modules()) {
             ModuleReference mref = resolvedModule.reference();
             ModuleDescriptor descriptor = mref.descriptor();
             String name = descriptor.name();
-            ClassLoader loader = clf.apply(name);
             URI uri = mref.location().orElse(null);
-
+            ClassLoader loader = moduleToLoader.get(resolvedModule.name());
             Module m;
-            if (loader == null && name.equals("java.base") && Layer.boot() == null) {
+            if (loader == null && isBootLayer && name.equals("java.base")) {
+                // java.base is already defined to the VM
                 m = Object.class.getModule();
             } else {
                 m = new Module(layer, loader, descriptor, uri);
             }
-
-            modules.put(name, m);
-            loaders.put(name, loader);
+            nameToModule.put(name, m);
+            moduleToLoader.put(name, loader);
         }
 
         // setup readability and exports
@@ -882,20 +1078,24 @@
             ModuleDescriptor descriptor = mref.descriptor();
 
             String mn = descriptor.name();
-            Module m = modules.get(mn);
+            Module m = nameToModule.get(mn);
             assert m != null;
 
             // reads
             Set<Module> reads = new HashSet<>();
-            for (ResolvedModule d : resolvedModule.reads()) {
-                Module m2;
-                if (d.configuration() == cf) {
-                    String dn = d.reference().descriptor().name();
-                    m2 = modules.get(dn);
-                    assert m2 != null;
+            for (ResolvedModule other : resolvedModule.reads()) {
+                Module m2 = null;
+                if (other.configuration() == cf) {
+                    String dn = other.reference().descriptor().name();
+                    m2 = nameToModule.get(dn);
                 } else {
-                    m2 = find(d, layer.parent().orElse(null));
+                    for (Layer parent: layer.parents()) {
+                        m2 = findModule(parent, other);
+                        if (m2 != null)
+                            break;
+                    }
                 }
+                assert m2 != null;
 
                 reads.add(m2);
 
@@ -904,64 +1104,273 @@
             }
             m.reads = reads;
 
-            // automatic modules reads all unnamed modules
+            // automatic modules read all unnamed modules
             if (descriptor.isAutomatic()) {
                 m.implAddReads(ALL_UNNAMED_MODULE, true);
             }
 
-            // exports
-            Map<String, Set<Module>> exports = new HashMap<>();
-            for (Exports export : descriptor.exports()) {
-                String source = export.source();
-                String sourceInternalForm = source.replace('.', '/');
-
-                if (export.isQualified()) {
+            // exports and opens
+            initExportsAndOpens(descriptor, nameToModule, m);
+        }
 
-                    // qualified export
-                    Set<Module> targets = new HashSet<>();
-                    for (String target : export.targets()) {
-                        // only export to modules that are in this configuration
-                        Module m2 = modules.get(target);
-                        if (m2 != null) {
-                            targets.add(m2);
-                            addExports0(m, sourceInternalForm, m2);
-                        }
+        // register the modules in the boot layer
+        if (isBootLayer) {
+            for (ResolvedModule resolvedModule : cf.modules()) {
+                ModuleReference mref = resolvedModule.reference();
+                ModuleDescriptor descriptor = mref.descriptor();
+                if (!descriptor.provides().isEmpty()) {
+                    String name = descriptor.name();
+                    Module m = nameToModule.get(name);
+                    ClassLoader loader = moduleToLoader.get(name);
+                    ServicesCatalog catalog;
+                    if (loader == null) {
+                        catalog = BootLoader.getServicesCatalog();
+                    } else {
+                        catalog = ServicesCatalog.getServicesCatalog(loader);
                     }
-                    if (!targets.isEmpty()) {
-                        exports.put(source, targets);
-                    }
-
-                } else {
-
-                    // unqualified export
-                    exports.put(source, EVERYONE);
-                    addExportsToAll0(m, sourceInternalForm);
+                    catalog.register(m);
                 }
             }
-            m.exports = exports;
+        }
+
+        // record that there is a layer with modules defined to the class loader
+        for (ClassLoader loader : loaders) {
+            layer.bindToLoader(loader);
         }
 
-        // register the modules in the service catalog if they provide services
-        for (ResolvedModule resolvedModule : cf.modules()) {
-            ModuleReference mref = resolvedModule.reference();
-            ModuleDescriptor descriptor = mref.descriptor();
-            Map<String, Provides> services = descriptor.provides();
-            if (!services.isEmpty()) {
-                String name = descriptor.name();
-                Module m = modules.get(name);
-                ClassLoader loader = loaders.get(name);
-                ServicesCatalog catalog;
-                if (loader == null) {
-                    catalog = BootLoader.getServicesCatalog();
-                } else {
-                    catalog = SharedSecrets.getJavaLangAccess()
-                                           .createOrGetServicesCatalog(loader);
+        return nameToModule;
+    }
+
+
+    /**
+     * Find the runtime Module corresponding to the given ResolvedModule
+     * in the given parent layer (or its parents).
+     */
+    private static Module findModule(Layer parent, ResolvedModule resolvedModule) {
+        Configuration cf = resolvedModule.configuration();
+        String dn = resolvedModule.name();
+        return parent.layers()
+                .filter(l -> l.configuration() == cf)
+                .findAny()
+                .map(layer -> {
+                    Optional<Module> om = layer.findModule(dn);
+                    assert om.isPresent() : dn + " not found in layer";
+                    Module m = om.get();
+                    assert m.getLayer() == layer : m + " not in expected layer";
+                    return m;
+                })
+                .orElse(null);
+    }
+
+    /**
+     * Initialize the maps of exported and open packages for module m.
+     */
+    private static void initExportsAndOpens(ModuleDescriptor descriptor,
+                                            Map<String, Module> nameToModule,
+                                            Module m)
+    {
+        // The VM doesn't know about open modules so need to export all packages
+        if (descriptor.isOpen()) {
+            assert descriptor.opens().isEmpty();
+            for (String source : descriptor.packages()) {
+                String sourceInternalForm = source.replace('.', '/');
+                addExportsToAll0(m, sourceInternalForm);
+            }
+            return;
+        }
+
+        Map<String, Set<Module>> openPackages = new HashMap<>();
+        Map<String, Set<Module>> exportedPackages = new HashMap<>();
+
+        // process the open packages first
+        for (Opens opens : descriptor.opens()) {
+            String source = opens.source();
+            String sourceInternalForm = source.replace('.', '/');
+
+            if (opens.isQualified()) {
+                // qualified opens
+                Set<Module> targets = new HashSet<>();
+                for (String target : opens.targets()) {
+                    // only open to modules that are in this configuration
+                    Module m2 = nameToModule.get(target);
+                    if (m2 != null) {
+                        addExports0(m, sourceInternalForm, m2);
+                        targets.add(m2);
+                    }
                 }
-                catalog.register(m);
+                if (!targets.isEmpty()) {
+                    openPackages.put(source, targets);
+                }
+            } else {
+                // unqualified opens
+                addExportsToAll0(m, sourceInternalForm);
+                openPackages.put(source, EVERYONE_SET);
             }
         }
 
-        return modules;
+        // next the exports, skipping exports when the package is open
+        for (Exports exports : descriptor.exports()) {
+            String source = exports.source();
+            String sourceInternalForm = source.replace('.', '/');
+
+            // skip export if package is already open to everyone
+            Set<Module> openToTargets = openPackages.get(source);
+            if (openToTargets != null && openToTargets.contains(EVERYONE_MODULE))
+                continue;
+
+            if (exports.isQualified()) {
+                // qualified exports
+                Set<Module> targets = new HashSet<>();
+                for (String target : exports.targets()) {
+                    // only export to modules that are in this configuration
+                    Module m2 = nameToModule.get(target);
+                    if (m2 != null) {
+                        // skip qualified export if already open to m2
+                        if (openToTargets == null || !openToTargets.contains(m2)) {
+                            addExports0(m, sourceInternalForm, m2);
+                            targets.add(m2);
+                        }
+                    }
+                }
+                if (!targets.isEmpty()) {
+                    exportedPackages.put(source, targets);
+                }
+
+            } else {
+                // unqualified exports
+                addExportsToAll0(m, sourceInternalForm);
+                exportedPackages.put(source, EVERYONE_SET);
+            }
+        }
+
+        if (!openPackages.isEmpty())
+            m.openPackages = openPackages;
+        if (!exportedPackages.isEmpty())
+            m.exportedPackages = exportedPackages;
+    }
+
+
+    // -- annotations --
+
+    /**
+     * {@inheritDoc}
+     * This method returns {@code null} when invoked on an unnamed module.
+     */
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        return moduleInfoClass().getDeclaredAnnotation(annotationClass);
+    }
+
+    /**
+     * {@inheritDoc}
+     * This method returns an empty array when invoked on an unnamed module.
+     */
+    @Override
+    public Annotation[] getAnnotations() {
+        return moduleInfoClass().getAnnotations();
+    }
+
+    /**
+     * {@inheritDoc}
+     * This method returns an empty array when invoked on an unnamed module.
+     */
+    @Override
+    public Annotation[] getDeclaredAnnotations() {
+        return moduleInfoClass().getDeclaredAnnotations();
+    }
+
+    // cached class file with annotations
+    private volatile Class<?> moduleInfoClass;
+
+    private Class<?> moduleInfoClass() {
+        Class<?> clazz = this.moduleInfoClass;
+        if (clazz != null)
+            return clazz;
+
+        synchronized (this) {
+            clazz = this.moduleInfoClass;
+            if (clazz == null) {
+                if (isNamed()) {
+                    PrivilegedAction<Class<?>> pa = this::loadModuleInfoClass;
+                    clazz = AccessController.doPrivileged(pa);
+                }
+                if (clazz == null) {
+                    class DummyModuleInfo { }
+                    clazz = DummyModuleInfo.class;
+                }
+                this.moduleInfoClass = clazz;
+            }
+            return clazz;
+        }
+    }
+
+    private Class<?> loadModuleInfoClass() {
+        Class<?> clazz = null;
+        try (InputStream in = getResourceAsStream("module-info.class")) {
+            if (in != null)
+                clazz = loadModuleInfoClass(in);
+        } catch (Exception ignore) { }
+        return clazz;
+    }
+
+    /**
+     * Loads module-info.class as a package-private interface in a class loader
+     * that is a child of this module's class loader.
+     */
+    private Class<?> loadModuleInfoClass(InputStream in) throws IOException {
+        final String MODULE_INFO = "module-info";
+
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+
+        ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) {
+            @Override
+            public void visit(int version,
+                              int access,
+                              String name,
+                              String signature,
+                              String superName,
+                              String[] interfaces) {
+                cw.visit(version,
+                        Opcodes.ACC_INTERFACE
+                            + Opcodes.ACC_ABSTRACT
+                            + Opcodes.ACC_SYNTHETIC,
+                        MODULE_INFO,
+                        null,
+                        "java/lang/Object",
+                        null);
+            }
+            @Override
+            public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+                // keep annotations
+                return super.visitAnnotation(desc, visible);
+            }
+            @Override
+            public void visitAttribute(Attribute attr) {
+                // drop non-annotation attributes
+            }
+        };
+
+        ClassReader cr = new ClassReader(in);
+        cr.accept(cv, 0);
+        byte[] bytes = cw.toByteArray();
+
+        ClassLoader cl = new ClassLoader(loader) {
+            @Override
+            protected Class<?> findClass(String cn)throws ClassNotFoundException {
+                if (cn.equals(MODULE_INFO)) {
+                    return super.defineClass(cn, bytes, 0, bytes.length);
+                } else {
+                    throw new ClassNotFoundException(cn);
+                }
+            }
+        };
+
+        try {
+            return cl.loadClass(MODULE_INFO);
+        } catch (ClassNotFoundException e) {
+            throw new InternalError(e);
+        }
     }
 
 
@@ -969,16 +1378,35 @@
 
 
     /**
-     * Returns an input stream for reading a resource in this module. Returns
-     * {@code null} if the resource is not in this module or access to the
-     * resource is denied by the security manager.
-     * The {@code name} is a {@code '/'}-separated path name that identifies
-     * the resource.
+     * Returns an input stream for reading a resource in this module. The
+     * {@code name} parameter is a {@code '/'}-separated path name that
+     * identifies the resource.
+     *
+     * <p> A resource in a named modules may be <em>encapsulated</em> so that
+     * it cannot be located by code in other modules. Whether a resource can be
+     * located or not is determined as follows:
+     *
+     * <ul>
+     *     <li> The <em>package name</em> of the resource is derived from the
+     *     subsequence of characters that precedes the last {@code '/'} and then
+     *     replacing each {@code '/'} character in the subsequence with
+     *     {@code '.'}. For example, the package name derived for a resource
+     *     named "{@code a/b/c/foo.properties}" is "{@code a.b.c}". </li>
      *
-     * <p> If this module is an unnamed module, and the {@code ClassLoader} for
-     * this module is not {@code null}, then this method is equivalent to
-     * invoking the {@link ClassLoader#getResourceAsStream(String)
-     * getResourceAsStream} method on the class loader for this module.
+     *     <li> If the package name is a package in the module then the package
+     *     must be {@link #isOpen open} the module of the caller of this method.
+     *     If the package is not in the module then the resource is not
+     *     encapsulated. Resources in the unnamed package or "{@code META-INF}",
+     *     for example, are never encapsulated because they can never be
+     *     packages in a named module. </li>
+     *
+     *     <li> As a special case, resources ending with "{@code .class}" are
+     *     never encapsulated. </li>
+     * </ul>
+     *
+     * <p> This method returns {@code null} if the resource is not in this
+     * module, the resource is encapsulated and cannot be located by the caller,
+     * or access to the resource is denied by the security manager.
      *
      * @param  name
      *         The resource name
@@ -990,36 +1418,35 @@
      *
      * @see java.lang.module.ModuleReader#open(String)
      */
+    @CallerSensitive
     public InputStream getResourceAsStream(String name) throws IOException {
         Objects.requireNonNull(name);
 
-        URL url = null;
-
-        if (isNamed()) {
-            String mn = this.name;
-
-            // special-case built-in class loaders to avoid URL connection
-            if (loader == null) {
-                return BootLoader.findResourceAsStream(mn, name);
-            } else if (loader instanceof BuiltinClassLoader) {
-                return ((BuiltinClassLoader) loader).findResourceAsStream(mn, name);
+        if (isNamed() && !ResourceHelper.isSimpleResource(name)) {
+            Module caller = Reflection.getCallerClass().getModule();
+            if (caller != this && caller != Object.class.getModule()) {
+                // ignore packages added for proxies via addPackage
+                Set<String> packages = getDescriptor().packages();
+                String pn = ResourceHelper.getPackageName(name);
+                if (packages.contains(pn) && !isOpen(pn, caller)) {
+                    // resource is in package not open to caller
+                    return null;
+                }
             }
-
-            // use SharedSecrets to invoke protected method
-            url = SharedSecrets.getJavaLangAccess().findResource(loader, mn, name);
-
-        } else {
-
-            // unnamed module
-            if (loader == null) {
-                url = BootLoader.findResource(name);
-            } else {
-                return loader.getResourceAsStream(name);
-            }
-
         }
 
-        // fallthrough to URL case
+        String mn = this.name;
+
+        // special-case built-in class loaders to avoid URL connection
+        if (loader == null) {
+            return BootLoader.findResourceAsStream(mn, name);
+        } else if (loader instanceof BuiltinClassLoader) {
+            return ((BuiltinClassLoader) loader).findResourceAsStream(mn, name);
+        }
+
+        // locate resource in module
+        JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
+        URL url = jla.findResource(loader, mn, name);
         if (url != null) {
             try {
                 return url.openStream();
@@ -1053,6 +1480,7 @@
 
     // JVM_DefineModule
     private static native void defineModule0(Module module,
+                                             boolean isOpen,
                                              String version,
                                              String location,
                                              String[] pns);
@@ -1098,15 +1526,31 @@
                 }
                 @Override
                 public void addExports(Module m, String pn, Module other) {
-                    m.implAddExports(pn, other, true);
+                    m.implAddExportsOrOpens(pn, other, false, true);
+                }
+                @Override
+                public void addOpens(Module m, String pn, Module other) {
+                    m.implAddExportsOrOpens(pn, other, true, true);
                 }
                 @Override
                 public void addExportsToAll(Module m, String pn) {
-                    m.implAddExports(pn, Module.EVERYONE_MODULE, true);
+                    m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, false, true);
+                }
+                @Override
+                public void addOpensToAll(Module m, String pn) {
+                    m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, true, true);
                 }
                 @Override
                 public void addExportsToAllUnnamed(Module m, String pn) {
-                    m.implAddExports(pn, Module.ALL_UNNAMED_MODULE, true);
+                    m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, false, true);
+                }
+                @Override
+                public void addOpensToAllUnnamed(Module m, String pn) {
+                    m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, true, true);
+                }
+                @Override
+                public void addUses(Module m, Class<?> service) {
+                    m.implAddUses(service);
                 }
                 @Override
                 public void addPackage(Module m, String pn) {
@@ -1116,6 +1560,14 @@
                 public ServicesCatalog getServicesCatalog(Layer layer) {
                     return layer.getServicesCatalog();
                 }
+                @Override
+                public Stream<Layer> layers(Layer layer) {
+                    return layer.layers();
+                }
+                @Override
+                public Stream<Layer> layers(ClassLoader loader) {
+                    return Layer.layers(loader);
+                }
             });
     }
 }
--- a/jdk/src/java.base/share/classes/java/time/chrono/Chronology.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/time/chrono/Chronology.java	Thu Dec 01 21:39:49 2016 +0000
@@ -151,7 +151,7 @@
  * Each chronology must define a chronology ID that is unique within the system.
  * If the chronology represents a calendar system defined by the
  * CLDR specification then the calendar type is the concatenation of the
- * CLDR type and, if applicable, the CLDR variant,
+ * CLDR type and, if applicable, the CLDR variant.
  *
  * @implSpec
  * This interface must be implemented with care to ensure other classes operate correctly.
@@ -177,7 +177,7 @@
      *
      * @param temporal  the temporal to convert, not null
      * @return the chronology, not null
-     * @throws DateTimeException if unable to convert to an {@code Chronology}
+     * @throws DateTimeException if unable to convert to a {@code Chronology}
      */
     static Chronology from(TemporalAccessor temporal) {
         Objects.requireNonNull(temporal, "temporal");
@@ -203,7 +203,7 @@
      * For example, the locale "en-JP-u-ca-japanese" represents the English
      * language as used in Japan with the Japanese calendar system.
      * <p>
-     * This method finds the desired calendar system by in a manner equivalent
+     * This method finds the desired calendar system in a manner equivalent
      * to passing "ca" to {@link Locale#getUnicodeLocaleType(String)}.
      * If the "ca" key is not present, then {@code IsoChronology} is returned.
      * <p>
@@ -286,7 +286,7 @@
      * <p>
      * The calendar type is an identifier defined by the CLDR and
      * <em>Unicode Locale Data Markup Language (LDML)</em> specifications
-     * to uniquely identification a calendar.
+     * to uniquely identify a calendar.
      * The {@code getCalendarType} is the concatenation of the CLDR calendar type
      * and the variant, if applicable, is appended separated by "-".
      * The calendar type is used to lookup the {@code Chronology} using {@link #of(String)}.
--- a/jdk/src/java.base/share/classes/java/util/ArrayDeque.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/ArrayDeque.java	Thu Dec 01 21:39:49 2016 +0000
@@ -36,6 +36,8 @@
 
 import java.io.Serializable;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
 
 /**
  * Resizable-array implementation of the {@link Deque} interface.  Array
@@ -87,81 +89,89 @@
 public class ArrayDeque<E> extends AbstractCollection<E>
                            implements Deque<E>, Cloneable, Serializable
 {
+    /*
+     * VMs excel at optimizing simple array loops where indices are
+     * incrementing or decrementing over a valid slice, e.g.
+     *
+     * for (int i = start; i < end; i++) ... elements[i]
+     *
+     * Because in a circular array, elements are in general stored in
+     * two disjoint such slices, we help the VM by writing unusual
+     * nested loops for all traversals over the elements.  Having only
+     * one hot inner loop body instead of two or three eases human
+     * maintenance and encourages VM loop inlining into the caller.
+     */
+
     /**
      * The array in which the elements of the deque are stored.
-     * The capacity of the deque is the length of this array, which is
-     * always a power of two. The array is never allowed to become
-     * full, except transiently within an addX method where it is
-     * resized (see doubleCapacity) immediately upon becoming full,
-     * thus avoiding head and tail wrapping around to equal each
-     * other.  We also guarantee that all array cells not holding
-     * deque elements are always null.
+     * All array cells not holding deque elements are always null.
+     * The array always has at least one null slot (at tail).
      */
-    transient Object[] elements; // non-private to simplify nested class access
+    transient Object[] elements;
 
     /**
      * The index of the element at the head of the deque (which is the
      * element that would be removed by remove() or pop()); or an
-     * arbitrary number equal to tail if the deque is empty.
+     * arbitrary number 0 <= head < elements.length equal to tail if
+     * the deque is empty.
      */
     transient int head;
 
     /**
      * The index at which the next element would be added to the tail
-     * of the deque (via addLast(E), add(E), or push(E)).
+     * of the deque (via addLast(E), add(E), or push(E));
+     * elements[tail] is always null.
      */
     transient int tail;
 
     /**
-     * The minimum capacity that we'll use for a newly created deque.
-     * Must be a power of 2.
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
      */
-    private static final int MIN_INITIAL_CAPACITY = 8;
-
-    // ******  Array allocation and resizing utilities ******
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 
     /**
-     * Allocates empty array to hold the given number of elements.
+     * Increases the capacity of this deque by at least the given amount.
      *
-     * @param numElements  the number of elements to hold
+     * @param needed the required minimum extra capacity; must be positive
      */
-    private void allocateElements(int numElements) {
-        int initialCapacity = MIN_INITIAL_CAPACITY;
-        // Find the best power of two to hold elements.
-        // Tests "<=" because arrays aren't kept full.
-        if (numElements >= initialCapacity) {
-            initialCapacity = numElements;
-            initialCapacity |= (initialCapacity >>>  1);
-            initialCapacity |= (initialCapacity >>>  2);
-            initialCapacity |= (initialCapacity >>>  4);
-            initialCapacity |= (initialCapacity >>>  8);
-            initialCapacity |= (initialCapacity >>> 16);
-            initialCapacity++;
-
-            if (initialCapacity < 0)    // Too many elements, must back off
-                initialCapacity >>>= 1; // Good luck allocating 2^30 elements
+    private void grow(int needed) {
+        // overflow-conscious code
+        final int oldCapacity = elements.length;
+        int newCapacity;
+        // Double capacity if small; else grow by 50%
+        int jump = (oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1);
+        if (jump < needed
+            || (newCapacity = (oldCapacity + jump)) - MAX_ARRAY_SIZE > 0)
+            newCapacity = newCapacity(needed, jump);
+        elements = Arrays.copyOf(elements, newCapacity);
+        // Exceptionally, here tail == head needs to be disambiguated
+        if (tail < head || (tail == head && elements[head] != null)) {
+            // wrap around; slide first leg forward to end of array
+            int newSpace = newCapacity - oldCapacity;
+            System.arraycopy(elements, head,
+                             elements, head + newSpace,
+                             oldCapacity - head);
+            Arrays.fill(elements, head, head + newSpace, null);
+            head += newSpace;
         }
-        elements = new Object[initialCapacity];
     }
 
-    /**
-     * Doubles the capacity of this deque.  Call only when full, i.e.,
-     * when head and tail have wrapped around to become equal.
-     */
-    private void doubleCapacity() {
-        assert head == tail;
-        int p = head;
-        int n = elements.length;
-        int r = n - p; // number of elements to the right of p
-        int newCapacity = n << 1;
-        if (newCapacity < 0)
-            throw new IllegalStateException("Sorry, deque too big");
-        Object[] a = new Object[newCapacity];
-        System.arraycopy(elements, p, a, 0, r);
-        System.arraycopy(elements, 0, a, r, p);
-        elements = a;
-        head = 0;
-        tail = n;
+    /** Capacity calculation for edge conditions, especially overflow. */
+    private int newCapacity(int needed, int jump) {
+        final int oldCapacity = elements.length, minCapacity;
+        if ((minCapacity = oldCapacity + needed) - MAX_ARRAY_SIZE > 0) {
+            if (minCapacity < 0)
+                throw new IllegalStateException("Sorry, deque too big");
+            return Integer.MAX_VALUE;
+        }
+        if (needed > jump)
+            return minCapacity;
+        return (oldCapacity + jump - MAX_ARRAY_SIZE < 0)
+            ? oldCapacity + jump
+            : MAX_ARRAY_SIZE;
     }
 
     /**
@@ -176,10 +186,13 @@
      * Constructs an empty array deque with an initial capacity
      * sufficient to hold the specified number of elements.
      *
-     * @param numElements  lower bound on initial capacity of the deque
+     * @param numElements lower bound on initial capacity of the deque
      */
     public ArrayDeque(int numElements) {
-        allocateElements(numElements);
+        elements =
+            new Object[(numElements < 1) ? 1 :
+                       (numElements == Integer.MAX_VALUE) ? Integer.MAX_VALUE :
+                       numElements + 1];
     }
 
     /**
@@ -193,10 +206,71 @@
      * @throws NullPointerException if the specified collection is null
      */
     public ArrayDeque(Collection<? extends E> c) {
-        allocateElements(c.size());
+        this(c.size());
         addAll(c);
     }
 
+    /**
+     * Increments i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int inc(int i, int modulus) {
+        if (++i >= modulus) i = 0;
+        return i;
+    }
+
+    /**
+     * Decrements i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int dec(int i, int modulus) {
+        if (--i < 0) i = modulus - 1;
+        return i;
+    }
+
+    /**
+     * Circularly adds the given distance to index i, mod modulus.
+     * Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
+     * @return index 0 <= i < modulus
+     */
+    static final int add(int i, int distance, int modulus) {
+        if ((i += distance) - modulus >= 0) i -= modulus;
+        return i;
+    }
+
+    /**
+     * Subtracts j from i, mod modulus.
+     * Index i must be logically ahead of index j.
+     * Precondition: 0 <= i < modulus, 0 <= j < modulus.
+     * @return the "circular distance" from j to i; corner case i == j
+     * is diambiguated to "empty", returning 0.
+     */
+    static final int sub(int i, int j, int modulus) {
+        if ((i -= j) < 0) i += modulus;
+        return i;
+    }
+
+    /**
+     * Returns element at array index i.
+     * This is a slight abuse of generics, accepted by javac.
+     */
+    @SuppressWarnings("unchecked")
+    static final <E> E elementAt(Object[] es, int i) {
+        return (E) es[i];
+    }
+
+    /**
+     * A version of elementAt that checks for null elements.
+     * This check doesn't catch all possible comodifications,
+     * but does catch ones that corrupt traversal.
+     */
+    static final <E> E nonNullElementAt(Object[] es, int i) {
+        @SuppressWarnings("unchecked") E e = (E) es[i];
+        if (e == null)
+            throw new ConcurrentModificationException();
+        return e;
+    }
+
     // The main insertion and extraction methods are addFirst,
     // addLast, pollFirst, pollLast. The other methods are defined in
     // terms of these.
@@ -210,9 +284,10 @@
     public void addFirst(E e) {
         if (e == null)
             throw new NullPointerException();
-        elements[head = (head - 1) & (elements.length - 1)] = e;
+        final Object[] es = elements;
+        es[head = dec(head, es.length)] = e;
         if (head == tail)
-            doubleCapacity();
+            grow(1);
     }
 
     /**
@@ -226,9 +301,29 @@
     public void addLast(E e) {
         if (e == null)
             throw new NullPointerException();
-        elements[tail] = e;
-        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
-            doubleCapacity();
+        final Object[] es = elements;
+        es[tail] = e;
+        if (head == (tail = inc(tail, es.length)))
+            grow(1);
+    }
+
+    /**
+     * Adds all of the elements in the specified collection at the end
+     * of this deque, as if by calling {@link #addLast} on each one,
+     * in the order that they are returned by the collection's
+     * iterator.
+     *
+     * @param c the elements to be inserted into this deque
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        final int s, needed;
+        if ((needed = (s = size()) + c.size() + 1 - elements.length) > 0)
+            grow(needed);
+        c.forEach(this::addLast);
+        return size() > s;
     }
 
     /**
@@ -259,78 +354,70 @@
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E removeFirst() {
-        E x = pollFirst();
-        if (x == null)
+        E e = pollFirst();
+        if (e == null)
             throw new NoSuchElementException();
-        return x;
+        return e;
     }
 
     /**
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E removeLast() {
-        E x = pollLast();
-        if (x == null)
+        E e = pollLast();
+        if (e == null)
             throw new NoSuchElementException();
-        return x;
+        return e;
     }
 
     public E pollFirst() {
-        final Object[] elements = this.elements;
-        final int h = head;
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[h];
-        // Element is null if deque empty
-        if (result != null) {
-            elements[h] = null; // Must null out slot
-            head = (h + 1) & (elements.length - 1);
+        final Object[] es;
+        final int h;
+        E e = elementAt(es = elements, h = head);
+        if (e != null) {
+            es[h] = null;
+            head = inc(h, es.length);
         }
-        return result;
+        return e;
     }
 
     public E pollLast() {
-        final Object[] elements = this.elements;
-        final int t = (tail - 1) & (elements.length - 1);
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[t];
-        if (result != null) {
-            elements[t] = null;
-            tail = t;
-        }
-        return result;
+        final Object[] es;
+        final int t;
+        E e = elementAt(es = elements, t = dec(tail, es.length));
+        if (e != null)
+            es[tail = t] = null;
+        return e;
     }
 
     /**
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E getFirst() {
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[head];
-        if (result == null)
+        E e = elementAt(elements, head);
+        if (e == null)
             throw new NoSuchElementException();
-        return result;
+        return e;
     }
 
     /**
      * @throws NoSuchElementException {@inheritDoc}
      */
     public E getLast() {
-        @SuppressWarnings("unchecked")
-        E result = (E) elements[(tail - 1) & (elements.length - 1)];
-        if (result == null)
+        final Object[] es = elements;
+        E e = elementAt(es, dec(tail, es.length));
+        if (e == null)
             throw new NoSuchElementException();
-        return result;
+        return e;
     }
 
-    @SuppressWarnings("unchecked")
     public E peekFirst() {
-        // elements[head] is null if deque empty
-        return (E) elements[head];
+        return elementAt(elements, head);
     }
 
-    @SuppressWarnings("unchecked")
     public E peekLast() {
-        return (E) elements[(tail - 1) & (elements.length - 1)];
+        final Object[] es;
+        return elementAt(es = elements, dec(tail, es.length));
     }
 
     /**
@@ -347,13 +434,15 @@
      */
     public boolean removeFirstOccurrence(Object o) {
         if (o != null) {
-            int mask = elements.length - 1;
-            int i = head;
-            for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
-                if (o.equals(x)) {
-                    delete(i);
-                    return true;
-                }
+            final Object[] es = elements;
+            for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+                 ; i = 0, to = end) {
+                for (; i < to; i++)
+                    if (o.equals(es[i])) {
+                        delete(i);
+                        return true;
+                    }
+                if (to == end) break;
             }
         }
         return false;
@@ -373,13 +462,15 @@
      */
     public boolean removeLastOccurrence(Object o) {
         if (o != null) {
-            int mask = elements.length - 1;
-            int i = (tail - 1) & mask;
-            for (Object x; (x = elements[i]) != null; i = (i - 1) & mask) {
-                if (o.equals(x)) {
-                    delete(i);
-                    return true;
-                }
+            final Object[] es = elements;
+            for (int i = tail, end = head, to = (i >= end) ? end : 0;
+                 ; i = es.length, to = end) {
+                for (i--; i > to - 1; i--)
+                    if (o.equals(es[i])) {
+                        delete(i);
+                        return true;
+                    }
+                if (to == end) break;
             }
         }
         return false;
@@ -499,59 +590,47 @@
         return removeFirst();
     }
 
-    private void checkInvariants() {
-        assert elements[tail] == null;
-        assert head == tail ? elements[head] == null :
-            (elements[head] != null &&
-             elements[(tail - 1) & (elements.length - 1)] != null);
-        assert elements[(head - 1) & (elements.length - 1)] == null;
-    }
-
     /**
-     * Removes the element at the specified position in the elements array,
-     * adjusting head and tail as necessary.  This can result in motion of
-     * elements backwards or forwards in the array.
+     * Removes the element at the specified position in the elements array.
+     * This can result in forward or backwards motion of array elements.
+     * We optimize for least element motion.
      *
      * <p>This method is called delete rather than remove to emphasize
      * that its semantics differ from those of {@link List#remove(int)}.
      *
-     * @return true if elements moved backwards
+     * @return true if elements near tail moved backwards
      */
     boolean delete(int i) {
-        checkInvariants();
-        final Object[] elements = this.elements;
-        final int mask = elements.length - 1;
-        final int h = head;
-        final int t = tail;
-        final int front = (i - h) & mask;
-        final int back  = (t - i) & mask;
-
-        // Invariant: head <= i < tail mod circularity
-        if (front >= ((t - h) & mask))
-            throw new ConcurrentModificationException();
-
-        // Optimize for least element motion
+        final Object[] es = elements;
+        final int capacity = es.length;
+        final int h, t;
+        // number of elements before to-be-deleted elt
+        final int front = sub(i, h = head, capacity);
+        // number of elements after to-be-deleted elt
+        final int back = sub(t = tail, i, capacity) - 1;
         if (front < back) {
+            // move front elements forwards
             if (h <= i) {
-                System.arraycopy(elements, h, elements, h + 1, front);
+                System.arraycopy(es, h, es, h + 1, front);
             } else { // Wrap around
-                System.arraycopy(elements, 0, elements, 1, i);
-                elements[0] = elements[mask];
-                System.arraycopy(elements, h, elements, h + 1, mask - h);
+                System.arraycopy(es, 0, es, 1, i);
+                es[0] = es[capacity - 1];
+                System.arraycopy(es, h, es, h + 1, front - (i + 1));
             }
-            elements[h] = null;
-            head = (h + 1) & mask;
+            es[h] = null;
+            head = inc(h, capacity);
             return false;
         } else {
-            if (i < t) { // Copy the null tail as well
-                System.arraycopy(elements, i + 1, elements, i, back);
-                tail = t - 1;
+            // move back elements backwards
+            tail = dec(t, capacity);
+            if (i <= tail) {
+                System.arraycopy(es, i + 1, es, i, back);
             } else { // Wrap around
-                System.arraycopy(elements, i + 1, elements, i, mask - i);
-                elements[mask] = elements[0];
-                System.arraycopy(elements, 1, elements, 0, t);
-                tail = (t - 1) & mask;
+                System.arraycopy(es, i + 1, es, i, capacity - (i + 1));
+                es[capacity - 1] = es[0];
+                System.arraycopy(es, 1, es, 0, t - 1);
             }
+            es[tail] = null;
             return true;
         }
     }
@@ -564,7 +643,7 @@
      * @return the number of elements in this deque
      */
     public int size() {
-        return (tail - head) & (elements.length - 1);
+        return sub(tail, head, elements.length);
     }
 
     /**
@@ -593,101 +672,317 @@
     }
 
     private class DeqIterator implements Iterator<E> {
-        /**
-         * Index of element to be returned by subsequent call to next.
-         */
-        private int cursor = head;
+        /** Index of element to be returned by subsequent call to next. */
+        int cursor;
 
-        /**
-         * Tail recorded at construction (also in remove), to stop
-         * iterator and also to check for comodification.
-         */
-        private int fence = tail;
+        /** Number of elements yet to be returned. */
+        int remaining = size();
 
         /**
          * Index of element returned by most recent call to next.
          * Reset to -1 if element is deleted by a call to remove.
          */
-        private int lastRet = -1;
+        int lastRet = -1;
 
-        public boolean hasNext() {
-            return cursor != fence;
+        DeqIterator() { cursor = head; }
+
+        public final boolean hasNext() {
+            return remaining > 0;
         }
 
         public E next() {
-            if (cursor == fence)
+            if (remaining <= 0)
                 throw new NoSuchElementException();
-            @SuppressWarnings("unchecked")
-            E result = (E) elements[cursor];
-            // This check doesn't catch all possible comodifications,
-            // but does catch the ones that corrupt traversal
-            if (tail != fence || result == null)
-                throw new ConcurrentModificationException();
-            lastRet = cursor;
-            cursor = (cursor + 1) & (elements.length - 1);
-            return result;
+            final Object[] es = elements;
+            E e = nonNullElementAt(es, cursor);
+            cursor = inc(lastRet = cursor, es.length);
+            remaining--;
+            return e;
         }
 
-        public void remove() {
+        void postDelete(boolean leftShifted) {
+            if (leftShifted)
+                cursor = dec(cursor, elements.length);
+        }
+
+        public final void remove() {
             if (lastRet < 0)
                 throw new IllegalStateException();
-            if (delete(lastRet)) { // if left-shifted, undo increment in next()
-                cursor = (cursor - 1) & (elements.length - 1);
-                fence = tail;
-            }
+            postDelete(delete(lastRet));
             lastRet = -1;
         }
 
         public void forEachRemaining(Consumer<? super E> action) {
             Objects.requireNonNull(action);
-            Object[] a = elements;
-            int m = a.length - 1, f = fence, i = cursor;
-            cursor = f;
-            while (i != f) {
-                @SuppressWarnings("unchecked") E e = (E)a[i];
-                i = (i + 1) & m;
-                if (e == null)
-                    throw new ConcurrentModificationException();
-                action.accept(e);
+            int r;
+            if ((r = remaining) <= 0)
+                return;
+            remaining = 0;
+            final Object[] es = elements;
+            if (es[cursor] == null || sub(tail, cursor, es.length) != r)
+                throw new ConcurrentModificationException();
+            for (int i = cursor, end = tail, to = (i <= end) ? end : es.length;
+                 ; i = 0, to = end) {
+                for (; i < to; i++)
+                    action.accept(elementAt(es, i));
+                if (to == end) {
+                    if (end != tail)
+                        throw new ConcurrentModificationException();
+                    lastRet = dec(end, es.length);
+                    break;
+                }
+            }
+        }
+    }
+
+    private class DescendingIterator extends DeqIterator {
+        DescendingIterator() { cursor = dec(tail, elements.length); }
+
+        public final E next() {
+            if (remaining <= 0)
+                throw new NoSuchElementException();
+            final Object[] es = elements;
+            E e = nonNullElementAt(es, cursor);
+            cursor = dec(lastRet = cursor, es.length);
+            remaining--;
+            return e;
+        }
+
+        void postDelete(boolean leftShifted) {
+            if (!leftShifted)
+                cursor = inc(cursor, elements.length);
+        }
+
+        public final void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            int r;
+            if ((r = remaining) <= 0)
+                return;
+            remaining = 0;
+            final Object[] es = elements;
+            if (es[cursor] == null || sub(cursor, head, es.length) + 1 != r)
+                throw new ConcurrentModificationException();
+            for (int i = cursor, end = head, to = (i >= end) ? end : 0;
+                 ; i = es.length - 1, to = end) {
+                // hotspot generates faster code than for: i >= to !
+                for (; i > to - 1; i--)
+                    action.accept(elementAt(es, i));
+                if (to == end) {
+                    if (end != head)
+                        throw new ConcurrentModificationException();
+                    lastRet = end;
+                    break;
+                }
             }
         }
     }
 
     /**
-     * This class is nearly a mirror-image of DeqIterator, using tail
-     * instead of head for initial cursor, and head instead of tail
-     * for fence.
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * deque.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#NONNULL}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
      */
-    private class DescendingIterator implements Iterator<E> {
-        private int cursor = tail;
-        private int fence = head;
-        private int lastRet = -1;
+    public Spliterator<E> spliterator() {
+        return new DeqSpliterator();
+    }
+
+    final class DeqSpliterator implements Spliterator<E> {
+        private int fence;      // -1 until first use
+        private int cursor;     // current index, modified on traverse/split
+
+        /** Constructs late-binding spliterator over all elements. */
+        DeqSpliterator() {
+            this.fence = -1;
+        }
+
+        /** Constructs spliterator over the given range. */
+        DeqSpliterator(int origin, int fence) {
+            // assert 0 <= origin && origin < elements.length;
+            // assert 0 <= fence && fence < elements.length;
+            this.cursor = origin;
+            this.fence = fence;
+        }
+
+        /** Ensures late-binding initialization; then returns fence. */
+        private int getFence() { // force initialization
+            int t;
+            if ((t = fence) < 0) {
+                t = fence = tail;
+                cursor = head;
+            }
+            return t;
+        }
 
-        public boolean hasNext() {
-            return cursor != fence;
+        public DeqSpliterator trySplit() {
+            final Object[] es = elements;
+            final int i, n;
+            return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0)
+                ? null
+                : new DeqSpliterator(i, cursor = add(i, n, es.length));
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            final int end = getFence(), cursor = this.cursor;
+            final Object[] es = elements;
+            if (cursor != end) {
+                this.cursor = end;
+                // null check at both ends of range is sufficient
+                if (es[cursor] == null || es[dec(end, es.length)] == null)
+                    throw new ConcurrentModificationException();
+                for (int i = cursor, to = (i <= end) ? end : es.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(elementAt(es, i));
+                    if (to == end) break;
+                }
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final Object[] es = elements;
+            if (fence < 0) { fence = tail; cursor = head; } // late-binding
+            final int i;
+            if ((i = cursor) == fence)
+                return false;
+            E e = nonNullElementAt(es, i);
+            cursor = inc(i, es.length);
+            action.accept(e);
+            return true;
+        }
+
+        public long estimateSize() {
+            return sub(getFence(), cursor, elements.length);
         }
 
-        public E next() {
-            if (cursor == fence)
-                throw new NoSuchElementException();
-            cursor = (cursor - 1) & (elements.length - 1);
-            @SuppressWarnings("unchecked")
-            E result = (E) elements[cursor];
-            if (head != fence || result == null)
-                throw new ConcurrentModificationException();
-            lastRet = cursor;
-            return result;
+        public int characteristics() {
+            return Spliterator.NONNULL
+                | Spliterator.ORDERED
+                | Spliterator.SIZED
+                | Spliterator.SUBSIZED;
+        }
+    }
+
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final Object[] es = elements;
+        for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++)
+                action.accept(elementAt(es, i));
+            if (to == end) {
+                if (end != tail) throw new ConcurrentModificationException();
+                break;
+            }
         }
+    }
 
-        public void remove() {
-            if (lastRet < 0)
-                throw new IllegalStateException();
-            if (!delete(lastRet)) {
-                cursor = (cursor + 1) & (elements.length - 1);
-                fence = head;
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final Object[] es = elements;
+        // Optimize for initial run of survivors
+        for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++)
+                if (filter.test(elementAt(es, i)))
+                    return bulkRemoveModified(filter, i);
+            if (to == end) {
+                if (end != tail) throw new ConcurrentModificationException();
+                break;
             }
-            lastRet = -1;
         }
+        return false;
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /**
+     * Helper for bulkRemove, in case of at least one deletion.
+     * Tolerate predicates that reentrantly access the collection for
+     * read (but writers still get CME), so traverse once to find
+     * elements to delete, a second pass to physically expunge.
+     *
+     * @param beg valid index of first element to be deleted
+     */
+    private boolean bulkRemoveModified(
+        Predicate<? super E> filter, final int beg) {
+        final Object[] es = elements;
+        final int capacity = es.length;
+        final int end = tail;
+        final long[] deathRow = nBits(sub(end, beg, capacity));
+        deathRow[0] = 1L;   // set bit 0
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; i = 0, to = end, k -= capacity) {
+            for (; i < to; i++)
+                if (filter.test(elementAt(es, i)))
+                    setBit(deathRow, i - k);
+            if (to == end) break;
+        }
+        // a two-finger traversal, with hare i reading, tortoise w writing
+        int w = beg;
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; w = 0) { // w rejoins i on second leg
+            // In this loop, i and w are on the same leg, with i > w
+            for (; i < to; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (to == end) break;
+            // In this loop, w is on the first leg, i on the second
+            for (i = 0, to = end, k -= capacity; i < to && w < capacity; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (i >= to) {
+                if (w == capacity) w = 0; // "corner" case
+                break;
+            }
+        }
+        if (end != tail) throw new ConcurrentModificationException();
+        circularClear(es, tail = w, end);
+        return true;
     }
 
     /**
@@ -700,11 +995,13 @@
      */
     public boolean contains(Object o) {
         if (o != null) {
-            int mask = elements.length - 1;
-            int i = head;
-            for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
-                if (o.equals(x))
-                    return true;
+            final Object[] es = elements;
+            for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+                 ; i = 0, to = end) {
+                for (; i < to; i++)
+                    if (o.equals(es[i]))
+                        return true;
+                if (to == end) break;
             }
         }
         return false;
@@ -732,16 +1029,18 @@
      * The deque will be empty after this call returns.
      */
     public void clear() {
-        int h = head;
-        int t = tail;
-        if (h != t) { // clear all cells
-            head = tail = 0;
-            int i = h;
-            int mask = elements.length - 1;
-            do {
-                elements[i] = null;
-                i = (i + 1) & mask;
-            } while (i != t);
+        circularClear(elements, head, tail);
+        head = tail = 0;
+    }
+
+    /**
+     * Nulls out slots starting at array index i, upto index end.
+     */
+    private static void circularClear(Object[] es, int i, int end) {
+        for (int to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            Arrays.fill(es, i, to, null);
+            if (to == end) break;
         }
     }
 
@@ -759,13 +1058,23 @@
      * @return an array containing all of the elements in this deque
      */
     public Object[] toArray() {
-        final int head = this.head;
-        final int tail = this.tail;
-        boolean wrap = (tail < head);
-        int end = wrap ? tail + elements.length : tail;
-        Object[] a = Arrays.copyOfRange(elements, head, end);
-        if (wrap)
-            System.arraycopy(elements, 0, a, elements.length - head, tail);
+        return toArray(Object[].class);
+    }
+
+    private <T> T[] toArray(Class<T[]> klazz) {
+        final Object[] es = elements;
+        final T[] a;
+        final int head = this.head, tail = this.tail, end;
+        if ((end = tail + ((head <= tail) ? 0 : es.length)) >= 0) {
+            // Uses null extension feature of copyOfRange
+            a = Arrays.copyOfRange(es, head, end, klazz);
+        } else {
+            // integer overflow!
+            a = Arrays.copyOfRange(es, 0, end - head, klazz);
+            System.arraycopy(es, head, a, 0, es.length - head);
+        }
+        if (end != tail)
+            System.arraycopy(es, 0, a, es.length - head, tail);
         return a;
     }
 
@@ -807,22 +1116,17 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
-        final int head = this.head;
-        final int tail = this.tail;
-        boolean wrap = (tail < head);
-        int size = (tail - head) + (wrap ? elements.length : 0);
-        int firstLeg = size - (wrap ? tail : 0);
-        int len = a.length;
-        if (size > len) {
-            a = (T[]) Arrays.copyOfRange(elements, head, head + size,
-                                         a.getClass());
-        } else {
-            System.arraycopy(elements, head, a, 0, firstLeg);
-            if (size < len)
-                a[size] = null;
+        final int size;
+        if ((size = size()) > a.length)
+            return toArray((Class<T[]>) a.getClass());
+        final Object[] es = elements;
+        for (int i = head, j = 0, len = Math.min(size, es.length - i);
+             ; i = 0, len = tail) {
+            System.arraycopy(es, i, a, j, len);
+            if ((j += len) == size) break;
         }
-        if (wrap)
-            System.arraycopy(elements, 0, a, firstLeg, tail);
+        if (size < a.length)
+            a[size] = null;
         return a;
     }
 
@@ -863,9 +1167,13 @@
         s.writeInt(size());
 
         // Write out elements in order.
-        int mask = elements.length - 1;
-        for (int i = head; i != tail; i = (i + 1) & mask)
-            s.writeObject(elements[i]);
+        final Object[] es = elements;
+        for (int i = head, end = tail, to = (i <= end) ? end : es.length;
+             ; i = 0, to = end) {
+            for (; i < to; i++)
+                s.writeObject(es[i]);
+            if (to == end) break;
+        }
     }
 
     /**
@@ -881,106 +1189,33 @@
 
         // Read in size and allocate array
         int size = s.readInt();
-        allocateElements(size);
-        head = 0;
-        tail = size;
+        elements = new Object[size + 1];
+        this.tail = size;
 
         // Read in all elements in the proper order.
         for (int i = 0; i < size; i++)
             elements[i] = s.readObject();
     }
 
-    /**
-     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
-     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
-     * deque.
-     *
-     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
-     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
-     * {@link Spliterator#NONNULL}.  Overriding implementations should document
-     * the reporting of additional characteristic values.
-     *
-     * @return a {@code Spliterator} over the elements in this deque
-     * @since 1.8
-     */
-    public Spliterator<E> spliterator() {
-        return new DeqSpliterator<>(this, -1, -1);
-    }
-
-    static final class DeqSpliterator<E> implements Spliterator<E> {
-        private final ArrayDeque<E> deq;
-        private int fence;  // -1 until first use
-        private int index;  // current index, modified on traverse/split
-
-        /** Creates new spliterator covering the given array and range. */
-        DeqSpliterator(ArrayDeque<E> deq, int origin, int fence) {
-            this.deq = deq;
-            this.index = origin;
-            this.fence = fence;
-        }
-
-        private int getFence() { // force initialization
-            int t;
-            if ((t = fence) < 0) {
-                t = fence = deq.tail;
-                index = deq.head;
-            }
-            return t;
-        }
-
-        public DeqSpliterator<E> trySplit() {
-            int t = getFence(), h = index, n = deq.elements.length;
-            if (h != t && ((h + 1) & (n - 1)) != t) {
-                if (h > t)
-                    t += n;
-                int m = ((h + t) >>> 1) & (n - 1);
-                return new DeqSpliterator<E>(deq, h, index = m);
-            }
-            return null;
-        }
-
-        public void forEachRemaining(Consumer<? super E> consumer) {
-            if (consumer == null)
-                throw new NullPointerException();
-            Object[] a = deq.elements;
-            int m = a.length - 1, f = getFence(), i = index;
-            index = f;
-            while (i != f) {
-                @SuppressWarnings("unchecked") E e = (E)a[i];
-                i = (i + 1) & m;
-                if (e == null)
-                    throw new ConcurrentModificationException();
-                consumer.accept(e);
-            }
-        }
-
-        public boolean tryAdvance(Consumer<? super E> consumer) {
-            if (consumer == null)
-                throw new NullPointerException();
-            Object[] a = deq.elements;
-            int m = a.length - 1, f = getFence(), i = index;
-            if (i != f) {
-                @SuppressWarnings("unchecked") E e = (E)a[i];
-                index = (i + 1) & m;
-                if (e == null)
-                    throw new ConcurrentModificationException();
-                consumer.accept(e);
-                return true;
-            }
-            return false;
-        }
-
-        public long estimateSize() {
-            int n = getFence() - index;
-            if (n < 0)
-                n += deq.elements.length;
-            return (long) n;
-        }
-
-        @Override
-        public int characteristics() {
-            return Spliterator.ORDERED | Spliterator.SIZED |
-                Spliterator.NONNULL | Spliterator.SUBSIZED;
+    /** debugging */
+    void checkInvariants() {
+        // Use head and tail fields with empty slot at tail strategy.
+        // head == tail disambiguates to "empty".
+        try {
+            int capacity = elements.length;
+            // assert 0 <= head && head < capacity;
+            // assert 0 <= tail && tail < capacity;
+            // assert capacity > 0;
+            // assert size() < capacity;
+            // assert head == tail || elements[head] != null;
+            // assert elements[tail] == null;
+            // assert head == tail || elements[dec(tail, capacity)] != null;
+        } catch (Throwable t) {
+            System.err.printf("head=%d tail=%d capacity=%d%n",
+                              head, tail, elements.length);
+            System.err.printf("elements=%s%n",
+                              Arrays.toString(elements));
+            throw t;
         }
     }
 
--- a/jdk/src/java.base/share/classes/java/util/ArrayList.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java	Thu Dec 01 21:39:49 2016 +0000
@@ -104,7 +104,6 @@
  * @see     Vector
  * @since   1.2
  */
-
 public class ArrayList<E> extends AbstractList<E>
         implements List<E>, RandomAccess, Cloneable, java.io.Serializable
 {
@@ -424,6 +423,11 @@
         return (E) elementData[index];
     }
 
+    @SuppressWarnings("unchecked")
+    static <E> E elementAt(Object[] es, int index) {
+        return (E) es[index];
+    }
+
     /**
      * Returns the element at the specified position in this list.
      *
@@ -553,7 +557,7 @@
         return false;
     }
 
-    /*
+    /**
      * Private remove method that skips bounds checking and does not
      * return the value removed.
      */
@@ -572,11 +576,7 @@
      */
     public void clear() {
         modCount++;
-
-        // clear to let GC do its work
-        for (int i = 0; i < size; i++)
-            elementData[i] = null;
-
+        Arrays.fill(elementData, 0, size, null);
         size = 0;
     }
 
@@ -665,16 +665,10 @@
                     outOfBoundsMsg(fromIndex, toIndex));
         }
         modCount++;
-        int numMoved = size - toIndex;
-        System.arraycopy(elementData, toIndex, elementData, fromIndex,
-                         numMoved);
-
-        // clear to let GC do its work
-        int newSize = size - (toIndex-fromIndex);
-        for (int i = newSize; i < size; i++) {
-            elementData[i] = null;
-        }
-        size = newSize;
+        final Object[] es = elementData;
+        final int oldSize = size;
+        System.arraycopy(es, toIndex, es, fromIndex, oldSize - toIndex);
+        Arrays.fill(es, size -= (toIndex - fromIndex), oldSize, null);
     }
 
     /**
@@ -717,8 +711,7 @@
      * @see Collection#contains(Object)
      */
     public boolean removeAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return batchRemove(c, false);
+        return batchRemove(c, false, 0, size);
     }
 
     /**
@@ -738,34 +731,35 @@
      * @see Collection#contains(Object)
      */
     public boolean retainAll(Collection<?> c) {
-        Objects.requireNonNull(c);
-        return batchRemove(c, true);
+        return batchRemove(c, true, 0, size);
     }
 
-    private boolean batchRemove(Collection<?> c, boolean complement) {
-        final Object[] elementData = this.elementData;
-        int r = 0, w = 0;
-        boolean modified = false;
-        try {
-            for (; r < size; r++)
-                if (c.contains(elementData[r]) == complement)
-                    elementData[w++] = elementData[r];
-        } finally {
-            // Preserve behavioral compatibility with AbstractCollection,
-            // even if c.contains() throws.
-            if (r != size) {
-                System.arraycopy(elementData, r,
-                                 elementData, w,
-                                 size - r);
-                w += size - r;
-            }
-            if (w != size) {
-                // clear to let GC do its work
-                for (int i = w; i < size; i++)
-                    elementData[i] = null;
-                modCount += size - w;
-                size = w;
-                modified = true;
+    boolean batchRemove(Collection<?> c, boolean complement,
+                        final int from, final int end) {
+        Objects.requireNonNull(c);
+        final Object[] es = elementData;
+        final boolean modified;
+        int r;
+        // Optimize for initial run of survivors
+        for (r = from; r < end && c.contains(es[r]) == complement; r++)
+            ;
+        if (modified = (r < end)) {
+            int w = r++;
+            try {
+                for (Object e; r < end; r++)
+                    if (c.contains(e = es[r]) == complement)
+                        es[w++] = e;
+            } catch (Throwable ex) {
+                // Preserve behavioral compatibility with AbstractCollection,
+                // even if c.contains() throws.
+                System.arraycopy(es, r, es, w, end - r);
+                w += end - r;
+                throw ex;
+            } finally {
+                final int oldSize = size, deleted = end - w;
+                modCount += deleted;
+                System.arraycopy(es, end, es, w, oldSize - end);
+                Arrays.fill(es, size -= deleted, oldSize, null);
             }
         }
         return modified;
@@ -912,25 +906,21 @@
         }
 
         @Override
-        @SuppressWarnings("unchecked")
-        public void forEachRemaining(Consumer<? super E> consumer) {
-            Objects.requireNonNull(consumer);
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
             final int size = ArrayList.this.size;
             int i = cursor;
-            if (i >= size) {
-                return;
-            }
-            final Object[] elementData = ArrayList.this.elementData;
-            if (i >= elementData.length) {
-                throw new ConcurrentModificationException();
+            if (i < size) {
+                final Object[] es = elementData;
+                if (i >= es.length)
+                    throw new ConcurrentModificationException();
+                for (; i < size && modCount == expectedModCount; i++)
+                    action.accept(elementAt(es, i));
+                // update once at end to reduce heap write traffic
+                cursor = i;
+                lastRet = i - 1;
+                checkForComodification();
             }
-            while (i != size && modCount == expectedModCount) {
-                consumer.accept((E) elementData[i++]);
-            }
-            // update once at end of iteration to reduce heap write traffic
-            cursor = i;
-            lastRet = i - 1;
-            checkForComodification();
         }
 
         final void checkForComodification() {
@@ -1117,6 +1107,33 @@
             return true;
         }
 
+        public boolean removeAll(Collection<?> c) {
+            return batchRemove(c, false);
+        }
+
+        public boolean retainAll(Collection<?> c) {
+            return batchRemove(c, true);
+        }
+
+        private boolean batchRemove(Collection<?> c, boolean complement) {
+            checkForComodification();
+            int oldSize = root.size;
+            boolean modified =
+                root.batchRemove(c, complement, offset, offset + size);
+            if (modified)
+                updateSizeAndModCount(root.size - oldSize);
+            return modified;
+        }
+
+        public boolean removeIf(Predicate<? super E> filter) {
+            checkForComodification();
+            int oldSize = root.size;
+            boolean modified = root.removeIf(filter, offset, offset + size);
+            if (modified)
+                updateSizeAndModCount(root.size - oldSize);
+            return modified;
+        }
+
         public Iterator<E> iterator() {
             return listIterator();
         }
@@ -1164,24 +1181,21 @@
                     return (E) elementData[offset + (lastRet = i)];
                 }
 
-                @SuppressWarnings("unchecked")
-                public void forEachRemaining(Consumer<? super E> consumer) {
-                    Objects.requireNonNull(consumer);
+                public void forEachRemaining(Consumer<? super E> action) {
+                    Objects.requireNonNull(action);
                     final int size = SubList.this.size;
                     int i = cursor;
-                    if (i >= size) {
-                        return;
-                    }
-                    final Object[] elementData = root.elementData;
-                    if (offset + i >= elementData.length) {
-                        throw new ConcurrentModificationException();
+                    if (i < size) {
+                        final Object[] es = root.elementData;
+                        if (offset + i >= es.length)
+                            throw new ConcurrentModificationException();
+                        for (; i < size && modCount == expectedModCount; i++)
+                            action.accept(elementAt(es, offset + i));
+                        // update once at end to reduce heap write traffic
+                        cursor = i;
+                        lastRet = i - 1;
+                        checkForComodification();
                     }
-                    while (i != size && modCount == expectedModCount) {
-                        consumer.accept((E) elementData[offset + (i++)]);
-                    }
-                    // update once at end of iteration to reduce heap write traffic
-                    lastRet = cursor = i;
-                    checkForComodification();
                 }
 
                 public int nextIndex() {
@@ -1348,15 +1362,12 @@
     public void forEach(Consumer<? super E> action) {
         Objects.requireNonNull(action);
         final int expectedModCount = modCount;
-        @SuppressWarnings("unchecked")
-        final E[] elementData = (E[]) this.elementData;
+        final Object[] es = elementData;
         final int size = this.size;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            action.accept(elementData[i]);
-        }
-        if (modCount != expectedModCount) {
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            action.accept(elementAt(es, i));
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
     }
 
     /**
@@ -1417,7 +1428,7 @@
         private int fence; // -1 until used; then one past last index
         private int expectedModCount; // initialized when fence set
 
-        /** Create new spliterator covering the given  range */
+        /** Create new spliterator covering the given range */
         ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                              int expectedModCount) {
             this.list = list; // OK if null unless traversed
@@ -1495,61 +1506,73 @@
         }
     }
 
-    @Override
-    public boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        // figure out which elements are to be removed
-        // any exception thrown from the filter predicate at this stage
-        // will leave the collection unmodified
-        int removeCount = 0;
-        final BitSet removeSet = new BitSet(size);
-        final int expectedModCount = modCount;
-        final int size = this.size;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            @SuppressWarnings("unchecked")
-            final E element = (E) elementData[i];
-            if (filter.test(element)) {
-                removeSet.set(i);
-                removeCount++;
-            }
-        }
-        if (modCount != expectedModCount) {
-            throw new ConcurrentModificationException();
-        }
+    // A tiny bit set implementation
 
-        // shift surviving elements left over the spaces left by removed elements
-        final boolean anyToRemove = removeCount > 0;
-        if (anyToRemove) {
-            final int newSize = size - removeCount;
-            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
-                i = removeSet.nextClearBit(i);
-                elementData[j] = elementData[i];
-            }
-            for (int k=newSize; k < size; k++) {
-                elementData[k] = null;  // Let gc do its work
-            }
-            this.size = newSize;
-            if (modCount != expectedModCount) {
-                throw new ConcurrentModificationException();
-            }
-            modCount++;
-        }
-
-        return anyToRemove;
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
     }
 
     @Override
-    @SuppressWarnings("unchecked")
+    public boolean removeIf(Predicate<? super E> filter) {
+        return removeIf(filter, 0, size);
+    }
+
+    /**
+     * Removes all elements satisfying the given predicate, from index
+     * i (inclusive) to index end (exclusive).
+     */
+    boolean removeIf(Predicate<? super E> filter, int i, final int end) {
+        Objects.requireNonNull(filter);
+        int expectedModCount = modCount;
+        final Object[] es = elementData;
+        // Optimize for initial run of survivors
+        for (; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        // Tolerate predicates that reentrantly access the collection for
+        // read (but writers still get CME), so traverse once to find
+        // elements to delete, a second pass to physically expunge.
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i)))
+                    setBit(deathRow, i - beg);
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            expectedModCount++;
+            modCount++;
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    es[w++] = es[i];
+            final int oldSize = size;
+            System.arraycopy(es, end, es, w, oldSize - end);
+            Arrays.fill(es, size -= (end - w), oldSize, null);
+            return true;
+        } else {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return false;
+        }
+    }
+
+    @Override
     public void replaceAll(UnaryOperator<E> operator) {
         Objects.requireNonNull(operator);
         final int expectedModCount = modCount;
+        final Object[] es = elementData;
         final int size = this.size;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            elementData[i] = operator.apply((E) elementData[i]);
-        }
-        if (modCount != expectedModCount) {
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
         modCount++;
     }
 
@@ -1558,9 +1581,13 @@
     public void sort(Comparator<? super E> c) {
         final int expectedModCount = modCount;
         Arrays.sort((E[]) elementData, 0, size, c);
-        if (modCount != expectedModCount) {
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
         modCount++;
     }
+
+    void checkInvariants() {
+        // assert size >= 0;
+        // assert size == elementData.length || elementData[size] == null;
+    }
 }
--- a/jdk/src/java.base/share/classes/java/util/Iterator.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/Iterator.java	Thu Dec 01 21:39:49 2016 +0000
@@ -76,10 +76,15 @@
     /**
      * Removes from the underlying collection the last element returned
      * by this iterator (optional operation).  This method can be called
-     * only once per call to {@link #next}.  The behavior of an iterator
-     * is unspecified if the underlying collection is modified while the
-     * iteration is in progress in any way other than by calling this
-     * method.
+     * only once per call to {@link #next}.
+     * <p>
+     * The behavior of an iterator is unspecified if the underlying collection
+     * is modified while the iteration is in progress in any way other than by
+     * calling this method, unless an overriding class has specified a
+     * concurrent modification policy.
+     * <p>
+     * The behavior of an iterator is unspecified if this method is called
+     * after a call to the {@link #forEachRemaining forEachRemaining} method.
      *
      * @implSpec
      * The default implementation throws an instance of
@@ -102,6 +107,13 @@
      * have been processed or the action throws an exception.  Actions are
      * performed in the order of iteration, if that order is specified.
      * Exceptions thrown by the action are relayed to the caller.
+     * <p>
+     * The behavior of an iterator is unspecified if the action modifies the
+     * collection in any way (even by calling the {@link #remove remove} method),
+     * unless an overriding class has specified a concurrent modification policy.
+     * <p>
+     * Subsequent behavior of an iterator is unspecified if the action throws an
+     * exception.
      *
      * @implSpec
      * <p>The default implementation behaves as if:
--- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java	Thu Dec 01 21:39:49 2016 +0000
@@ -42,6 +42,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
 import java.lang.ref.WeakReference;
@@ -62,13 +63,14 @@
 import java.util.spi.ResourceBundleControlProvider;
 import java.util.spi.ResourceBundleProvider;
 
+import jdk.internal.loader.BootLoader;
 import jdk.internal.misc.JavaUtilResourceBundleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
+import sun.security.action.GetPropertyAction;
 import sun.util.locale.BaseLocale;
 import sun.util.locale.LocaleObjectCache;
-import sun.util.locale.provider.ResourceBundleProviderSupport;
 import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
 
 
@@ -247,7 +249,8 @@
  * used to load resource bundles. If no service provider is available, or if
  * none of the service providers returns a resource bundle and the caller module
  * doesn't have its own service provider, the {@code getBundle} factory method
- * searches for resource bundles local to the caller module. The resource bundle
+ * searches for resource bundles that are local in the caller module and that
+ * are visible to the class loader of the caller module.  The resource bundle
  * formats for local module searching are "java.class" and "java.properties".
  *
  * <h3>ResourceBundle.Control</h3>
@@ -372,6 +375,18 @@
                 public void setName(ResourceBundle bundle, String name) {
                     bundle.name = name;
                 }
+
+                @Override
+                public ResourceBundle getBundle(String baseName, Locale locale, Module module) {
+                    // use the given module as the caller to bypass the access check
+                    return getBundleImpl(module, module, getLoader(module),
+                                         baseName, locale, Control.INSTANCE);
+                }
+
+                @Override
+                public ResourceBundle newResourceBundle(Class<? extends ResourceBundle> bundleClass) {
+                    return ResourceBundleProviderHelper.newResourceBundle(bundleClass);
+                }
             });
     }
 
@@ -999,6 +1014,14 @@
      * <code>getBundle(baseName, Locale.getDefault(), module)</code>
      * </blockquote>
      *
+     * <p> Resource bundles in named modules may be encapsulated.  When
+     * the resource bundle is loaded from a provider, the caller module
+     * must have an appropriate <i>uses</i> clause in its <i>module descriptor</i>
+     * to declare that the module uses implementations of {@code "baseName"Provider}.
+     * When the resource bundle is loaded from the specified module, it is
+     * subject to the encapsulation rules specified by
+     * {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     *
      * @param baseName the base name of the resource bundle,
      *                 a fully qualified class name
      * @param module   the module for which the resource bundle is searched
@@ -1024,10 +1047,19 @@
      * Gets a resource bundle using the specified base name and locale
      * on behalf of the specified module.
      *
+     * <p> Resource bundles in named modules may be encapsulated.  When
+     * the resource bundle is loaded from a provider, the caller module
+     * must have an appropriate <i>uses</i> clause in its <i>module descriptor</i>
+     * to declare that the module uses implementations of {@code "baseName"Provider}.
+     * When the resource bundle is loaded from the specified module, it is
+     * subject to the encapsulation rules specified by
+     * {@link Module#getResourceAsStream Module.getResourceAsStream}.
+     *
      * <p>
      * If the given {@code module} is a named module, this method will
      * load the service providers for {@link java.util.spi.ResourceBundleProvider}
-     * and also resource bundles local in the given module (refer to the
+     * and also resource bundles that are local in the given module or that
+     * are visible to the class loader of the given module (refer to the
      * <a href="#bundleprovider">Resource Bundles in Named Modules</a> section
      * for details).
      *
@@ -1035,9 +1067,8 @@
      * If the given {@code module} is an unnamed module, then this method is
      * equivalent to calling {@link #getBundle(String, Locale, ClassLoader)
      * getBundle(baseName, targetLocale, module.getClassLoader()} to load
-     * resource bundles that are in unnamed modules visible to the
-     * class loader of the given unnamed module.  It will not find resource
-     * bundles from named modules.
+     * resource bundles that are visible to the class loader of the given
+     * unnamed module.
      *
      * @param baseName the base name of the resource bundle,
      *                 a fully qualified class name
@@ -1126,7 +1157,8 @@
      * Resource bundles in a named module are private to that module.  If
      * the caller is in a named module, this method will find resource bundles
      * from the service providers of {@link java.util.spi.ResourceBundleProvider}
-     * and also find resource bundles private to the caller's module.
+     * and also find resource bundles that are in the caller's module or
+     * that are visible to the given class loader.
      * If the caller is in a named module and the given {@code loader} is
      * different than the caller's class loader, or if the caller is not in
      * a named module, this method will not find resource bundles from named
@@ -1587,13 +1619,20 @@
             // get resource bundles for a named module only
             // if loader is the module's class loader
             if (loader == ml || (ml == null && loader == RBClassLoader.INSTANCE)) {
-                return getBundleImpl(baseName, locale, loader, module, control);
+                return getBundleImpl(module, module, loader, baseName, locale, control);
             }
         }
         // find resource bundles from unnamed module
-        Module module = loader != null ? loader.getUnnamedModule()
-                                       : ClassLoader.getSystemClassLoader().getUnnamedModule();
-        return getBundleImpl(baseName, locale, loader, module, control);
+        Module unnamedModule = loader != null
+            ? loader.getUnnamedModule()
+            : ClassLoader.getSystemClassLoader().getUnnamedModule();
+
+        if (caller == null) {
+            throw new InternalError("null caller");
+        }
+
+        Module callerModule = caller.getModule();
+        return getBundleImpl(callerModule, unnamedModule, loader, baseName, locale, control);
     }
 
     private static ResourceBundle getBundleFromModule(Class<?> caller,
@@ -1602,19 +1641,21 @@
                                                       Locale locale,
                                                       Control control) {
         Objects.requireNonNull(module);
-        if (caller.getModule() != module) {
+        Module callerModule = caller.getModule();
+        if (callerModule != module) {
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
                 sm.checkPermission(GET_CLASSLOADER_PERMISSION);
             }
         }
-        return getBundleImpl(baseName, locale, getLoader(module), module, control);
+        return getBundleImpl(callerModule, module, getLoader(module), baseName, locale, control);
     }
 
-    private static ResourceBundle getBundleImpl(String baseName,
+    private static ResourceBundle getBundleImpl(Module callerModule,
+                                                Module module,
+                                                ClassLoader loader,
+                                                String baseName,
                                                 Locale locale,
-                                                ClassLoader loader,
-                                                Module module,
                                                 Control control) {
         if (locale == null || control == null) {
             throw new NullPointerException();
@@ -1661,7 +1702,8 @@
                 throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
             }
 
-            bundle = findBundle(cacheKey, module, candidateLocales, formats, 0, control, baseBundle);
+            bundle = findBundle(callerModule, module, cacheKey,
+                                candidateLocales, formats, 0, control, baseBundle);
 
             // If the loaded bundle is the base bundle and exactly for the
             // requested locale or the only candidate locale, then take the
@@ -1710,8 +1752,9 @@
         return valid;
     }
 
-    private static ResourceBundle findBundle(CacheKey cacheKey,
+    private static ResourceBundle findBundle(Module callerModule,
                                              Module module,
+                                             CacheKey cacheKey,
                                              List<Locale> candidateLocales,
                                              List<String> formats,
                                              int index,
@@ -1720,7 +1763,8 @@
         Locale targetLocale = candidateLocales.get(index);
         ResourceBundle parent = null;
         if (index != candidateLocales.size() - 1) {
-            parent = findBundle(cacheKey, module, candidateLocales, formats, index + 1,
+            parent = findBundle(callerModule, module, cacheKey,
+                                candidateLocales, formats, index + 1,
                                 control, baseBundle);
         } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
             return baseBundle;
@@ -1764,10 +1808,10 @@
 
         if (bundle != NONEXISTENT_BUNDLE) {
             CacheKey constKey = (CacheKey) cacheKey.clone();
-
+            trace("findBundle: %d %s %s formats: %s%n", index, candidateLocales, cacheKey, formats);
             try {
                 if (module.isNamed()) {
-                    bundle = loadBundle(cacheKey, formats, control, module);
+                    bundle = loadBundle(cacheKey, formats, control, module, callerModule);
                 } else {
                     bundle = loadBundle(cacheKey, formats, control, expiredBundle);
                 }
@@ -1794,39 +1838,60 @@
 
     private static final String UNKNOWN_FORMAT = "";
 
+
     /*
      * Loads a ResourceBundle in named modules
      */
     private static ResourceBundle loadBundle(CacheKey cacheKey,
                                              List<String> formats,
                                              Control control,
-                                             Module module) {
+                                             Module module,
+                                             Module callerModule) {
         String baseName = cacheKey.getName();
         Locale targetLocale = cacheKey.getLocale();
 
         ResourceBundle bundle = null;
         if (cacheKey.hasProviders()) {
-            bundle = loadBundleFromProviders(baseName, targetLocale,
-                                             cacheKey.getProviders(), cacheKey);
+            if (callerModule == module) {
+                bundle = loadBundleFromProviders(baseName,
+                                                 targetLocale,
+                                                 cacheKey.getProviders(),
+                                                 cacheKey);
+            } else {
+                // load from provider if the caller module has access to the
+                // service type and also declares `uses`
+                ClassLoader loader = getLoader(module);
+                Class<ResourceBundleProvider> svc =
+                    getResourceBundleProviderType(baseName, loader);
+                if (svc != null
+                        && Reflection.verifyModuleAccess(callerModule, svc)
+                        && callerModule.canUse(svc)) {
+                    bundle = loadBundleFromProviders(baseName,
+                                                     targetLocale,
+                                                     cacheKey.getProviders(),
+                                                      cacheKey);
+                }
+            }
+
             if (bundle != null) {
                 cacheKey.setFormat(UNKNOWN_FORMAT);
             }
         }
+
         // If none of providers returned a bundle and the caller has no provider,
-        // look up module-local bundles.
+        // look up module-local bundles or from the class path
         if (bundle == null && !cacheKey.callerHasProvider()) {
-            String bundleName = control.toBundleName(baseName, targetLocale);
             for (String format : formats) {
                 try {
                     switch (format) {
                     case "java.class":
-                        PrivilegedAction<ResourceBundle> pa = ()
-                                -> ResourceBundleProviderSupport
-                                    .loadResourceBundle(module, bundleName);
-                        bundle = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+                        bundle = ResourceBundleProviderHelper
+                            .loadResourceBundle(callerModule, module, baseName, targetLocale);
+
                         break;
                     case "java.properties":
-                        bundle = ResourceBundleProviderSupport.loadPropertyResourceBundle(module, bundleName);
+                        bundle = ResourceBundleProviderHelper
+                            .loadPropertyResourceBundle(callerModule, module, baseName, targetLocale);
                         break;
                     default:
                         throw new InternalError("unexpected format: " + format);
@@ -1844,29 +1909,46 @@
         return bundle;
     }
 
+    /**
+     * Returns a ServiceLoader that will find providers that are bound to
+     * a given named module.
+     */
     private static ServiceLoader<ResourceBundleProvider> getServiceLoader(Module module,
-                                                                          String baseName) {
+                                                                          String baseName)
+    {
         if (!module.isNamed()) {
             return null;
         }
-        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
-        ClassLoader loader = AccessController.doPrivileged(pa);
-        return getServiceLoader(module, loader, baseName);
+
+        ClassLoader loader = getLoader(module);
+        Class<ResourceBundleProvider> service =
+                getResourceBundleProviderType(baseName, loader);
+        if (service != null && Reflection.verifyModuleAccess(module, service)) {
+            try {
+                // locate providers that are visible to the class loader
+                // ServiceConfigurationError will be thrown if the module
+                // does not declare `uses` the service type
+                return ServiceLoader.load(service, loader, module);
+            } catch (ServiceConfigurationError e) {
+                // "uses" not declared
+                return null;
+            }
+        }
+        return null;
     }
 
-        /**
-         * Returns a ServiceLoader that will find providers that are bound to
-         * a given module that may be named or unnamed.
-         */
-    private static ServiceLoader<ResourceBundleProvider> getServiceLoader(Module module,
-                                                                          ClassLoader loader,
-                                                                          String baseName)
+    /**
+     * Returns the service type of the given baseName that is visible
+     * to the given class loader
+     */
+    private static Class<ResourceBundleProvider>
+            getResourceBundleProviderType(String baseName, ClassLoader loader)
     {
         // Look up <baseName> + "Provider"
         String providerName = baseName + "Provider";
         // Use the class loader of the getBundle caller so that the caller's
         // visibility of the provider type is checked.
-        Class<ResourceBundleProvider> service = AccessController.doPrivileged(
+        return AccessController.doPrivileged(
             new PrivilegedAction<>() {
                 @Override
                 public Class<ResourceBundleProvider> run() {
@@ -1881,16 +1963,6 @@
                     return null;
                 }
             });
-
-        if (service != null && Reflection.verifyModuleAccess(module, service)) {
-            try {
-                return ServiceLoader.load(service, loader, module);
-            } catch (ServiceConfigurationError e) {
-                // "uses" not declared: load bundle local in the module
-                return null;
-            }
-        }
-        return null;
     }
 
     /**
@@ -1914,6 +1986,7 @@
                                     cacheKey.callerHasProvider = Boolean.TRUE;
                                 }
                                 ResourceBundle bundle = provider.getBundle(baseName, locale);
+                                trace("provider %s %s locale: %s bundle: %s%n", provider, baseName, locale, bundle);
                                 if (bundle != null) {
                                     return bundle;
                                 }
@@ -3016,6 +3089,14 @@
          * indicates that this method is being called because the previously
          * loaded resource bundle has expired.
          *
+         * @implSpec
+         *
+         * Resource bundles in named modules are subject to the encapsulation
+         * rules specified by {@link Module#getResourceAsStream Module.getResourceAsStream}.
+         * A resource bundle in a named module visible to the given class loader
+         * is accessible when the package of the resource file corresponding
+         * to the resource bundle is open unconditionally.
+         *
          * <p>The default implementation instantiates a
          * <code>ResourceBundle</code> as follows.
          *
@@ -3026,12 +3107,15 @@
          * locale)}.</li>
          *
          * <li>If <code>format</code> is <code>"java.class"</code>, the
-         * {@link Class} specified by the bundle name is loaded by calling
-         * {@link ClassLoader#loadClass(String)}. Then, a
-         * <code>ResourceBundle</code> is instantiated by calling {@link
-         * Class#newInstance()}.  Note that the <code>reload</code> flag is
-         * ignored for loading class-based resource bundles in this default
-         * implementation.</li>
+         * {@link Class} specified by the bundle name is loaded with the
+         * given class loader. If the {@code Class} is found and accessible
+         * then the <code>ResourceBundle</code> is instantiated.  The
+         * resource bundle is accessible if the package of the bundle class file
+         * is open unconditionally; otherwise, {@code IllegalAccessException}
+         * will be thrown.
+         * Note that the <code>reload</code> flag is ignored for loading
+         * class-based resource bundles in this default implementation.
+         * </li>
          *
          * <li>If <code>format</code> is <code>"java.properties"</code>,
          * {@link #toResourceName(String, String) toResourceName(bundlename,
@@ -3105,7 +3189,6 @@
             /*
              * Legacy mechanism to locate resource bundle in unnamed module only
              * that is visible to the given loader and accessible to the given caller.
-             * This only finds resources on the class path but not in named modules.
              */
             String bundleName = toBundleName(baseName, locale);
             ResourceBundle bundle = null;
@@ -3117,18 +3200,15 @@
                     if (ResourceBundle.class.isAssignableFrom(c)) {
                         @SuppressWarnings("unchecked")
                         Class<ResourceBundle> bundleClass = (Class<ResourceBundle>)c;
+                        Module m = bundleClass.getModule();
 
-                        // This doesn't allow unnamed modules to find bundles in
-                        // named modules other than via the service loader mechanism.
-                        // Otherwise, this will make the newBundle method to be
-                        // caller-sensitive in order to verify access check.
-                        // So migrating resource bundles to named module can't
-                        // just export the package (in general, legacy resource
-                        // bundles have split package if they are packaged separate
-                        // from the consumer.)
-                        if (bundleClass.getModule().isNamed()) {
-                            throw new IllegalAccessException("unnamed modules can't load " + bundleName
-                                     + " in named module " + bundleClass.getModule().getName());
+                        // To access a resource bundle in a named module,
+                        // either class-based or properties-based, the resource
+                        // bundle must be opened unconditionally,
+                        // same rule as accessing a resource file.
+                        if (m.isNamed() && !m.isOpen(bundleClass.getPackageName())) {
+                            throw new IllegalAccessException("unnamed module can't load " +
+                                bundleClass.getName() + " in " + m.toString());
                         }
                         try {
                             // bundle in a unnamed module
@@ -3502,4 +3582,173 @@
             return null;
         }
     }
+
+    private static class ResourceBundleProviderHelper {
+        /**
+         * Returns a new ResourceBundle instance of the given bundleClass
+         */
+        static ResourceBundle newResourceBundle(Class<? extends ResourceBundle> bundleClass) {
+            try {
+                @SuppressWarnings("unchecked")
+                Constructor<? extends ResourceBundle> ctor =
+                    bundleClass.getConstructor();
+                if (!Modifier.isPublic(ctor.getModifiers())) {
+                    return null;
+                }
+                // java.base may not be able to read the bundleClass's module.
+                PrivilegedAction<Void> pa = () -> { ctor.setAccessible(true); return null;};
+                AccessController.doPrivileged(pa);
+                try {
+                    return ctor.newInstance((Object[]) null);
+                } catch (InvocationTargetException e) {
+                    uncheckedThrow(e);
+                } catch (InstantiationException | IllegalAccessException e) {
+                    throw new InternalError(e);
+                }
+            } catch (NoSuchMethodException e) {
+                throw new InternalError(e);
+            }
+            return null;
+        }
+
+        /**
+         * Loads a {@code ResourceBundle} of the given {@code bundleName} local to
+         * the given {@code module}. If not found, search the bundle class
+         * that is visible from the module's class loader.
+         *
+         * The caller module is used for access check only.
+         */
+        static ResourceBundle loadResourceBundle(Module callerModule,
+                                                 Module module,
+                                                 String baseName,
+                                                 Locale locale)
+        {
+            String bundleName = Control.INSTANCE.toBundleName(baseName, locale);
+            try {
+                PrivilegedAction<Class<?>> pa = () -> Class.forName(module, bundleName);
+                Class<?> c = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+                trace("local in %s %s caller %s: %s%n", module, bundleName, callerModule, c);
+
+                if (c == null) {
+                    // if not found from the given module, locate resource bundle
+                    // that is visible to the module's class loader
+                    ClassLoader loader = getLoader(module);
+                    if (loader != null) {
+                        c = Class.forName(bundleName, false, loader);
+                    } else {
+                        c = BootLoader.loadClassOrNull(bundleName);
+                    }
+                    trace("loader for %s %s caller %s: %s%n", module, bundleName, callerModule, c);
+                }
+
+                if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
+                    @SuppressWarnings("unchecked")
+                    Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
+                    Module m = bundleClass.getModule();
+                    if (!isAccessible(callerModule, m, bundleClass.getPackageName())) {
+                        trace("   %s does not have access to %s/%s%n", callerModule,
+                              m.getName(), bundleClass.getPackageName());
+                        return null;
+                    }
+
+                    return newResourceBundle(bundleClass);
+                }
+            } catch (ClassNotFoundException e) {}
+            return null;
+        }
+
+        /**
+         * Tests if resources of the given package name from the given module are
+         * open to the caller module.
+         */
+        static boolean isAccessible(Module callerModule, Module module, String pn) {
+            if (!module.isNamed() || callerModule == module)
+                return true;
+
+            return module.isOpen(pn, callerModule);
+        }
+
+        /**
+         * Loads properties of the given {@code bundleName} local in the given
+         * {@code module}.  If the .properties is not found or not open
+         * to the caller module to access, it will find the resource that
+         * is visible to the module's class loader.
+         *
+         * The caller module is used for access check only.
+         */
+        static ResourceBundle loadPropertyResourceBundle(Module callerModule,
+                                                         Module module,
+                                                         String baseName,
+                                                         Locale locale)
+            throws IOException
+        {
+            String bundleName = Control.INSTANCE.toBundleName(baseName, locale);
+
+            PrivilegedAction<InputStream> pa = () -> {
+                try {
+                    String resourceName = Control.INSTANCE
+                        .toResourceName0(bundleName, "properties");
+                    if (resourceName == null) {
+                        return null;
+                    }
+                    trace("local in %s %s caller %s%n", module, resourceName, callerModule);
+
+                    // if the package is in the given module but not opened
+                    // locate it from the given module first.
+                    String pn = toPackageName(bundleName);
+                    trace("   %s/%s is accessible to %s : %s%n",
+                            module.getName(), pn, callerModule,
+                            isAccessible(callerModule, module, pn));
+                    if (isAccessible(callerModule, module, pn)) {
+                        InputStream in = module.getResourceAsStream(resourceName);
+                        if (in != null) {
+                            return in;
+                        }
+                    }
+
+                    ClassLoader loader = module.getClassLoader();
+                    trace("loader for %s %s caller %s%n", module, resourceName, callerModule);
+
+                    try {
+                        if (loader != null) {
+                            return loader.getResourceAsStream(resourceName);
+                        } else {
+                            URL url = BootLoader.findResource(resourceName);
+                            if (url != null) {
+                                return url.openStream();
+                            }
+                        }
+                    } catch (Exception e) {}
+                    return null;
+
+                } catch (IOException e) {
+                    throw new UncheckedIOException(e);
+                }
+            };
+
+            try (InputStream stream = AccessController.doPrivileged(pa)) {
+                if (stream != null) {
+                    return new PropertyResourceBundle(stream);
+                } else {
+                    return null;
+                }
+            } catch (UncheckedIOException e) {
+                throw e.getCause();
+            }
+        }
+
+        private static String toPackageName(String bundleName) {
+            int i = bundleName.lastIndexOf('.');
+            return i != -1 ? bundleName.substring(0, i) : "";
+        }
+
+    }
+
+    private static final boolean TRACE_ON = Boolean.valueOf(
+        GetPropertyAction.privilegedGetProperty("resource.bundle.debug", "false"));
+
+    private static void trace(String format, Object... params) {
+        if (TRACE_ON)
+            System.out.format(format, params);
+    }
 }
--- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java	Thu Dec 01 21:39:49 2016 +0000
@@ -32,23 +32,28 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Module;
 import java.net.URL;
 import java.net.URLConnection;
+import java.security.AccessControlContext;
 import java.security.AccessController;
-import java.security.AccessControlContext;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 import jdk.internal.loader.BootLoader;
-import jdk.internal.loader.Loader;
-import jdk.internal.loader.LoaderPool;
 import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.JavaLangReflectModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
 import jdk.internal.module.ServicesCatalog;
 import jdk.internal.module.ServicesCatalog.ServiceProvider;
-
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 
@@ -76,21 +81,49 @@
  * request together with code that can create the actual provider on demand.
  * The details of provider classes tend to be highly service-specific; no
  * single class or interface could possibly unify them, so no such type is
- * defined here. A requirement enforced by this facility is that each provider
- * class must have a {@code public} zero-argument constructor.
+ * defined here.
+ *
+ * <p> Providers deployed as explicit modules on the module path are
+ * instantiated by a <em>provider factory</em> or directly via the provider's
+ * constructor. In the module declaration then the class name specified in the
+ * <i>provides</i> clause is a provider factory if it is public and defines a
+ * public static no-args method named "{@code provider}". The return type of
+ * the method must be assignable to the <i>service</i> type. If the class is
+ * not a provider factory then it is public with a public zero-argument
+ * constructor. The requirement that the provider factory or provider class
+ * be public helps to document the intent that the provider will be
+ * instantiated by the service-provider loading facility.
+ *
+ * <p> As an example, suppose a module declares the following:
+ *
+ * <pre>{@code
+ *     provides com.example.CodecSet with com.example.impl.StandardCodecs;
+ *     provides com.example.CodecSet with com.example.impl.ExtendedCodecsFactory;
+ * }</pre>
+ *
+ * <p> where {@code com.example.CodecSet} is the service type, {@code
+ * com.example.impl.StandardCodecs} is a provider class that is public with a
+ * public no-args constructor, {@code com.example.impl.ExtendedCodecsFactory}
+ * is a public class that defines a public static no-args method named
+ * "{@code provider}" with a return type that is {@code CodecSet} or a subtype
+ * of. For this example then {@code StandardCodecs}'s no-arg constructor will
+ * be used to instantiate {@code StandardCodecs}. {@code ExtendedCodecsFactory}
+ * will be treated as a provider factory and {@code
+ * ExtendedCodecsFactory.provider()} will be invoked to obtain the provider.
+ *
+ * <p> Providers deployed on the class path or as {@link
+ * java.lang.module.ModuleDescriptor#isAutomatic automatic-modules} on the
+ * module path must have a public zero-argument constructor.
  *
  * <p> An application or library using this loading facility and developed
- * and deployed as a named module must have an appropriate <i>uses</i> clause
- * in its <i>module descriptor</i> to declare that the module uses
+ * and deployed as an explicit module must have an appropriate <i>uses</i>
+ * clause in its <i>module descriptor</i> to declare that the module uses
  * implementations of the service. A corresponding requirement is that a
  * provider deployed as a named module must have an appropriate
  * <i>provides</i> clause in its module descriptor to declare that the module
  * provides an implementation of the service. The <i>uses</i> and
- * <i>provides</i> allow consumers of a service to be <i>linked</i> to
- * providers of the service. In the case of {@code load} methods that locate
- * service providers using a class loader, then provider modules defined to
- * that class loader, or a class loader <i>reachable</i> using {@link
- * ClassLoader#getParent() parent} delegation, will be located.
+ * <i>provides</i> allow consumers of a service to be <i>linked</i> to modules
+ * containing providers of the service.
  *
  * <p> A service provider that is packaged as a JAR file for the class path is
  * identified by placing a <i>provider-configuration file</i> in the resource
@@ -114,27 +147,116 @@
  *
  * <p> Providers are located and instantiated lazily, that is, on demand.  A
  * service loader maintains a cache of the providers that have been loaded so
- * far.  Each invocation of the {@link #iterator iterator} method returns an
- * iterator that first yields all of the elements of the cache, in
- * instantiation order, and then lazily locates and instantiates any remaining
- * providers, adding each one to the cache in turn.  The cache can be cleared
+ * far. Each invocation of the {@link #iterator iterator} method returns an
+ * iterator that first yields all of the elements cached from previous
+ * iteration, in instantiation order, and then lazily locates and instantiates
+ * any remaining providers, adding each one to the cache in turn.  Similarly,
+ * each invocation of the {@link #stream stream} method returns a stream that
+ * first processes all providers loaded by previous stream operations, in load
+ * order, and then lazily locates any remaining providers. Caches are cleared
  * via the {@link #reload reload} method.
  *
+ * <h2> Locating providers </h2>
+ *
+ * <p> The {@code load} methods locate providers using a class loader or module
+ * {@link Layer layer}. When locating providers using a class loader then
+ * providers in both named and unnamed modules may be located. When locating
+ * providers using a module layer then only providers in named modules in
+ * the layer (or parent layers) are located.
+ *
+ * <p> When locating providers using a class loader then any providers in named
+ * modules defined to the class loader, or any class loader that is reachable
+ * via parent delegation, are located. Additionally, providers in module layers
+ * other than the {@link Layer#boot() boot} layer, where the module layer
+ * contains modules defined to the class loader, or any class loader reachable
+ * via parent delegation, are also located. For example, suppose there is a
+ * module layer where each module is defined to its own class loader (see {@link
+ * Layer#defineModulesWithManyLoaders defineModulesWithManyLoaders}). If the
+ * {@code load} method is invoked to locate providers using any of these class
+ * loaders for this layer then it will locate all of the providers in that
+ * layer, irrespective of their defining class loader.
+ *
+ * <p> In the case of unnamed modules then the service configuration files are
+ * located using the class loader's {@link ClassLoader#getResources(String)
+ * ClassLoader.getResources(String)} method. Any providers listed should be
+ * visible via the class loader specified to the {@code load} method. If a
+ * provider in a named module is listed then it is ignored - this is to avoid
+ * duplicates that would otherwise arise when a module has both a
+ * <i>provides</i> clause and a service configuration file in {@code
+ * META-INF/services} that lists the same provider.
+ *
+ * <h2> Ordering </h2>
+ *
+ * <p> Service loaders created to locate providers using a {@code ClassLoader}
+ * locate providers as follows:
+ * <ul>
+ *     <li> Providers in named modules are located before providers on the
+ *     class path (or more generally, unnamed modules). </li>
+ *
+ *     <li> When locating providers in named modules then the service loader
+ *     will locate providers in modules defined to the class loader, then its
+ *     parent class loader, its parent parent, and so on to the bootstrap class
+ *     loader. If a {@code ClassLoader}, or any class loader in the parent
+ *     delegation chain, defines modules in a custom module {@link Layer} then
+ *     all providers in that layer are located, irrespective of their class
+ *     loader. The ordering of modules defined to the same class loader, or the
+ *     ordering of modules in a layer, is not defined. </li>
+ *
+ *     <li> If a named module declares more than one provider then the providers
+ *     are located in the order that they appear in the {@code provides} table of
+ *     the {@code Module} class file attribute ({@code module-info.class}). </li>
+ *
+ *     <li> When locating providers in unnamed modules then the ordering is
+ *     based on the order that the class loader's {@link
+ *     ClassLoader#getResources(String) ClassLoader.getResources(String)}
+ *     method finds the service configuration files. </li>
+ * </ul>
+ *
+ * <p> Service loaders created to locate providers in a module {@link Layer}
+ * will first locate providers in the layer, before locating providers in
+ * parent layers. Traversal of parent layers is depth-first with each layer
+ * visited at most once. For example, suppose L0 is the boot layer, L1 and
+ * L2 are custom layers with L0 as their parent. Now suppose that L3 is
+ * created with L1 and L2 as the parents (in that order). Using a service
+ * loader to locate providers with L3 as the content will locate providers
+ * in the following order: L3, L1, L0, L2. The ordering of modules in a layer
+ * is not defined.
+ *
+ * <h2> Selection and filtering </h2>
+ *
+ * <p> Selecting a provider or filtering providers will usually involve invoking
+ * a provider method. Where selection or filtering based on the provider class is
+ * needed then it can be done using a {@link #stream() stream}. For example, the
+ * following collects the providers that have a specific annotation:
+ * <pre>{@code
+ *     Set<CodecSet> providers = ServiceLoader.load(CodecSet.class)
+ *            .stream()
+ *            .filter(p -> p.type().isAnnotationPresent(Managed.class))
+ *            .map(Provider::get)
+ *            .collect(Collectors.toSet());
+ * }</pre>
+ *
+ * <h2> Security </h2>
+ *
  * <p> Service loaders always execute in the security context of the caller
- * of the iterator methods and may also be restricted by the security
+ * of the iterator or stream methods and may also be restricted by the security
  * context of the caller that created the service loader.
  * Trusted system code should typically invoke the methods in this class, and
  * the methods of the iterators which they return, from within a privileged
  * security context.
  *
+ * <h2> Concurrency </h2>
+ *
  * <p> Instances of this class are not safe for use by multiple concurrent
  * threads.
  *
- * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * <h2> Null handling </h2>
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
  * method in this class will cause a {@link NullPointerException} to be thrown.
  *
- * <p><span style="font-weight: bold; padding-right: 1em">Example</span>
- * Suppose we have a service type <tt>com.example.CodecSet</tt> which is
+ * <h2> Example </h2>
+ * <p> Suppose we have a service type <tt>com.example.CodecSet</tt> which is
  * intended to represent sets of encoder/decoder pairs for some protocol.  In
  * this case it is an abstract class with two abstract methods:
  *
@@ -218,11 +340,12 @@
 public final class ServiceLoader<S>
     implements Iterable<S>
 {
-    private static final String PREFIX = "META-INF/services/";
-
     // The class or interface representing the service being loaded
     private final Class<S> service;
 
+    // The class of the service type
+    private final String serviceName;
+
     // The module Layer used to locate providers; null when locating
     // providers using a class loader
     private final Layer layer;
@@ -234,75 +357,86 @@
     // The access control context taken when the ServiceLoader is created
     private final AccessControlContext acc;
 
-    // Cached providers, in instantiation order
-    private List<S> providers = new ArrayList<>();
+    // The lazy-lookup iterator for iterator operations
+    private Iterator<Provider<S>> lookupIterator1;
+    private final List<S> instantiatedProviders = new ArrayList<>();
 
-    // The class names of the cached providers, only used when locating
-    // service providers via a class loader
-    private Set<String> providerNames = new HashSet<>();
+    // The lazy-lookup iterator for stream operations
+    private Iterator<Provider<S>> lookupIterator2;
+    private final List<Provider<S>> loadedProviders = new ArrayList<>();
+    private boolean loadedAllProviders; // true when all providers loaded
 
     // Incremented when reload is called
     private int reloadCount;
 
-    // the service iterator when locating services via a module layer
-    private LayerLookupIterator layerLookupIterator;
-
-    // The module services iterator when locating services in modules
-    // defined to a class loader
-    private ModuleServicesIterator moduleServicesIterator;
-
-    // The current lazy-lookup iterator for locating legacy provider on the
-    // class path via a class loader
-    private LazyClassPathIterator lazyClassPathIterator;
-
+    private static JavaLangAccess LANG_ACCESS;
+    private static JavaLangReflectModuleAccess JLRM_ACCESS;
+    static {
+        LANG_ACCESS = SharedSecrets.getJavaLangAccess();
+        JLRM_ACCESS = SharedSecrets.getJavaLangReflectModuleAccess();
+    }
 
     /**
-     * Clear this loader's provider cache so that all providers will be
-     * reloaded.
+     * Represents a service provider located by {@code ServiceLoader}.
+     *
+     * <p> When using a loader's {@link ServiceLoader#stream() stream()} method
+     * then the elements are of type {@code Provider}. This allows processing
+     * to select or filter on the provider class without instantiating the
+     * provider. </p>
      *
-     * <p> After invoking this method, subsequent invocations of the {@link
-     * #iterator() iterator} method will lazily look up and instantiate
-     * providers from scratch, just as is done by a newly-created loader.
-     *
-     * <p> This method is intended for use in situations in which new providers
-     * can be installed into a running Java virtual machine.
+     * @param  <S> The service type
+     * @since 9
      */
-    public void reload() {
-        providers.clear();
+    public static interface Provider<S> extends Supplier<S> {
+        /**
+         * Returns the provider type. There is no guarantee that this type is
+         * accessible or that it has a public no-args constructor. The {@link
+         * #get() get()} method should be used to obtain the provider instance.
+         *
+         * <p> When a module declares that the provider class is created by a
+         * provider factory then this method returns the return type of its
+         * public static "{@code provider()}" method.
+         *
+         * @return The provider type
+         */
+        Class<? extends S> type();
 
-        assert layer == null || loader == null;
-        if (layer != null) {
-            layerLookupIterator = new LayerLookupIterator();
-        } else {
-            providerNames.clear();
-            moduleServicesIterator = new ModuleServicesIterator();
-            lazyClassPathIterator = new LazyClassPathIterator();
-        }
-
-        reloadCount++;
+        /**
+         * Returns an instance of the provider.
+         *
+         * @return An instance of the provider.
+         *
+         * @throws ServiceConfigurationError
+         *         If the service provider cannot be instantiated, or in the
+         *         case of a provider factory, the public static
+         *         "{@code provider()}" method returns {@code null} or throws
+         *         an error or exception. The {@code ServiceConfigurationError}
+         *         will carry an appropriate cause where possible.
+         */
+        @Override S get();
     }
 
-
     /**
      * Initializes a new instance of this class for locating service providers
      * in a module Layer.
      *
      * @throws ServiceConfigurationError
-     *         If {@code svc} is not accessible to {@code caller} or that the
-     *         caller's module does not declare that it uses the service type.
+     *         If {@code svc} is not accessible to {@code caller} or the caller
+     *         module does not use the service type.
      */
     private ServiceLoader(Class<?> caller, Layer layer, Class<S> svc) {
-
-        checkModule(caller.getModule(), svc);
+        Objects.requireNonNull(caller);
+        Objects.requireNonNull(layer);
+        Objects.requireNonNull(svc);
+        checkCaller(caller, svc);
 
         this.service = svc;
+        this.serviceName = svc.getName();
         this.layer = layer;
         this.loader = null;
         this.acc = (System.getSecurityManager() != null)
                 ? AccessController.getContext()
                 : null;
-
-        reload();
     }
 
     /**
@@ -310,23 +444,23 @@
      * via a class loader.
      *
      * @throws ServiceConfigurationError
-     *         If {@code svc} is not accessible to {@code caller} or that the
-     *         caller's module does not declare that it uses the service type.
+     *         If {@code svc} is not accessible to {@code caller} or the caller
+     *         module does not use the service type.
      */
-    private ServiceLoader(Module callerModule, Class<S> svc, ClassLoader cl) {
-        if (VM.isBooted()) {
+    private ServiceLoader(Class<?> caller, Class<S> svc, ClassLoader cl) {
+        Objects.requireNonNull(svc);
 
-            checkModule(callerModule, svc);
-
+        if (VM.isBooted()) {
+            checkCaller(caller, svc);
             if (cl == null) {
                 cl = ClassLoader.getSystemClassLoader();
             }
-
         } else {
 
             // if we get here then it means that ServiceLoader is being used
             // before the VM initialization has completed. At this point then
             // only code in the java.base should be executing.
+            Module callerModule = caller.getModule();
             Module base = Object.class.getModule();
             Module svcModule = svc.getModule();
             if (callerModule != base || svcModule != base) {
@@ -338,39 +472,55 @@
         }
 
         this.service = svc;
+        this.serviceName = svc.getName();
         this.layer = null;
         this.loader = cl;
         this.acc = (System.getSecurityManager() != null)
                 ? AccessController.getContext()
                 : null;
-
-        reload();
     }
 
-    private ServiceLoader(Class<?> caller, Class<S> svc, ClassLoader cl) {
-        this(caller.getModule(), svc, cl);
+    /**
+     * Initializes a new instance of this class for locating service providers
+     * via a class loader.
+     *
+     * @apiNote For use by ResourceBundle
+     *
+     * @throws ServiceConfigurationError
+     *         If the caller module does not use the service type.
+     */
+    private ServiceLoader(Module callerModule, Class<S> svc, ClassLoader cl) {
+        if (!callerModule.canUse(svc)) {
+            fail(svc, callerModule + " does not declare `uses`");
+        }
+
+        this.service = Objects.requireNonNull(svc);
+        this.serviceName = svc.getName();
+        this.layer = null;
+        this.loader = cl;
+        this.acc = (System.getSecurityManager() != null)
+                ? AccessController.getContext()
+                : null;
     }
 
-
-
     /**
      * Checks that the given service type is accessible to types in the given
-     * module, and check that the module declare that it uses the service type.
+     * module, and check that the module declare that it uses the service type. ??
      */
-    private static void checkModule(Module module, Class<?> svc) {
+    private static void checkCaller(Class<?> caller, Class<?> svc) {
+        Module callerModule = caller.getModule();
 
-        // Check that the service type is in a package that is
-        // exported to the caller.
-        if (!Reflection.verifyModuleAccess(module, svc)) {
-            fail(svc, "not accessible to " + module);
+        // Check access to the service type
+        int mods = svc.getModifiers();
+        if (!Reflection.verifyMemberAccess(caller, svc, null, mods)) {
+            fail(svc, "service type not accessible to " + callerModule);
         }
 
         // If the caller is in a named module then it should "uses" the
         // service type
-        if (!module.canUse(svc)) {
-            fail(svc, "use not declared in " + module);
+        if (!callerModule.canUse(svc)) {
+            fail(svc, callerModule + " does not declare `uses`");
         }
-
     }
 
     private static void fail(Class<?> service, String msg, Throwable cause)
@@ -392,310 +542,422 @@
         fail(service, u + ":" + line + ": " + msg);
     }
 
-    // Parse a single line from the given configuration file, adding the name
-    // on the line to the names list.
-    //
-    private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
-                          List<String> names)
-        throws IOException, ServiceConfigurationError
-    {
-        String ln = r.readLine();
-        if (ln == null) {
-            return -1;
-        }
-        int ci = ln.indexOf('#');
-        if (ci >= 0) ln = ln.substring(0, ci);
-        ln = ln.trim();
-        int n = ln.length();
-        if (n != 0) {
-            if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
-                fail(service, u, lc, "Illegal configuration-file syntax");
-            int cp = ln.codePointAt(0);
-            if (!Character.isJavaIdentifierStart(cp))
-                fail(service, u, lc, "Illegal provider-class name: " + ln);
-            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
-                cp = ln.codePointAt(i);
-                if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
-                    fail(service, u, lc, "Illegal provider-class name: " + ln);
-            }
-            if (!providerNames.contains(ln) && !names.contains(ln))
-                names.add(ln);
-        }
-        return lc + 1;
-    }
-
     /**
-     * Parse the content of the given URL as a provider-configuration file.
-     *
-     * @param  service
-     *         The service type for which providers are being sought;
-     *         used to construct error detail strings
-     *
-     * @param  u
-     *         The URL naming the configuration file to be parsed
-     *
-     * @return A (possibly empty) iterator that will yield the provider-class
-     *         names in the given configuration file that are not yet members
-     *         of the returned set
+     * Uses Class.forName to load a provider class in a module.
      *
      * @throws ServiceConfigurationError
-     *         If an I/O error occurs while reading from the given URL, or
-     *         if a configuration-file format error is detected
-     *
+     *         If the class cannot be loaded
      */
-    private Iterator<String> parse(Class<?> service, URL u)
-        throws ServiceConfigurationError
-    {
-        ArrayList<String> names = new ArrayList<>();
-        try {
-            URLConnection uc = u.openConnection();
-            uc.setUseCaches(false);
-            try (InputStream in = uc.getInputStream();
-                 BufferedReader r
-                     = new BufferedReader(new InputStreamReader(in, "utf-8")))
-            {
-                int lc = 1;
-                while ((lc = parseLine(service, u, r, lc, names)) >= 0);
+    private Class<?> loadProviderInModule(Module module, String cn) {
+        Class<?> clazz = null;
+        if (acc == null) {
+            try {
+                clazz = Class.forName(module, cn);
+            } catch (LinkageError e) {
+                fail(service, "Unable to load " + cn, e);
             }
-        } catch (IOException x) {
-            fail(service, "Error accessing configuration file", x);
+        } else {
+            PrivilegedExceptionAction<Class<?>> pa = () -> Class.forName(module, cn);
+            try {
+                clazz = AccessController.doPrivileged(pa);
+            } catch (PrivilegedActionException pae) {
+                Throwable x = pae.getCause();
+                fail(service, "Unable to load " + cn, x);
+                return null;
+            }
         }
-        return names.iterator();
+        if (clazz == null)
+            fail(service, "Provider " + cn  + " not found");
+        return clazz;
     }
 
     /**
-     * Returns the {@code Constructor} to instantiate the service provider.
-     * The constructor has its accessible flag set so that the access check
-     * is suppressed when instantiating the provider. This is necessary
-     * because newInstance is a caller sensitive method and ServiceLoader
-     * is instantiating the service provider on behalf of the service
-     * consumer.
+     * A Provider implementation that supports invoking, with reduced
+     * permissions, the static factory to obtain the provider or the
+     * provider's no-arg constructor.
      */
-    private static Constructor<?> checkAndGetConstructor(Class<?> c)
-        throws NoSuchMethodException, IllegalAccessException
-    {
-        Constructor<?> ctor = c.getConstructor();
+    private final static class ProviderImpl<S> implements Provider<S> {
+        final Class<S> service;
+        final AccessControlContext acc;
+
+        final Method factoryMethod;  // factory method or null
+        final Class<? extends S> type;
+        final Constructor<? extends S> ctor; // public no-args constructor or null
+
+        /**
+         * Creates a Provider.
+         *
+         * @param service
+         *        The service type
+         * @param clazz
+         *        The provider (or provider factory) class
+         * @param acc
+         *        The access control context when running with security manager
+         *
+         * @throws ServiceConfigurationError
+         *         If the class is not public; If the class defines a public
+         *         static provider() method with a return type that is assignable
+         *         to the service type or the class is not a provider class with
+         *         a public no-args constructor.
+         */
+        @SuppressWarnings("unchecked")
+        ProviderImpl(Class<?> service, Class<?> clazz, AccessControlContext acc) {
+            this.service = (Class<S>) service;
+            this.acc = acc;
 
-        // check class and no-arg constructor are public
-        int modifiers = ctor.getModifiers();
-        if (!Modifier.isPublic(Reflection.getClassAccessFlags(c) & modifiers)) {
-            String cn = c.getName();
-            throw new IllegalAccessException(cn + " is not public");
+            int mods = clazz.getModifiers();
+            if (!Modifier.isPublic(mods)) {
+                fail(service, clazz + " is not public");
+            }
+
+            // if the class is in an explicit module then see if it is
+            // a provider factory class
+            Method factoryMethod = null;
+            if (inExplicitModule(clazz)) {
+                factoryMethod = findStaticProviderMethod(clazz);
+                if (factoryMethod != null) {
+                    Class<?> returnType = factoryMethod.getReturnType();
+                    if (!service.isAssignableFrom(returnType)) {
+                        fail(service, factoryMethod + " return type not a subtype");
+                    }
+                }
+            }
+            this.factoryMethod = factoryMethod;
+
+            if (factoryMethod == null) {
+                // no factory method so must have a public no-args constructor
+                if (!service.isAssignableFrom(clazz)) {
+                    fail(service, clazz.getName() + " not a subtype");
+                }
+                this.type = (Class<? extends S>) clazz;
+                this.ctor = (Constructor<? extends S>) getConstructor(clazz);
+            } else {
+                this.type = (Class<? extends S>) factoryMethod.getReturnType();
+                this.ctor = null;
+            }
         }
 
-        // return Constructor to create the service implementation
-        PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
-            public Void run() { ctor.setAccessible(true); return null; }
-        };
-        AccessController.doPrivileged(action);
-        return ctor;
-    }
-
-    /**
-     * Uses Class.forName to load a class in a module.
-     */
-    private static Class<?> loadClassInModule(Module module, String cn) {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm == null) {
-            return Class.forName(module, cn);
-        } else {
-            PrivilegedAction<Class<?>> pa = () -> Class.forName(module, cn);
-            return AccessController.doPrivileged(pa);
+        @Override
+        public Class<? extends S> type() {
+            return type;
         }
-    }
 
-    /**
-     * An Iterator that runs the next and hasNext methods with permissions
-     * restricted by the {@code AccessControlContext} obtained when the
-     * ServiceLoader was created.
-     */
-    private abstract class RestrictedIterator<S>
-        implements Iterator<S>
-    {
-        /**
-         * Returns {@code true} if the iteration has more elements.
-         */
-        abstract boolean hasNextService();
-
-        /**
-         * Returns the next element in the iteration
-         */
-        abstract S nextService();
-
-        public final boolean hasNext() {
-            if (acc == null) {
-                return hasNextService();
+        @Override
+        public S get() {
+            if (factoryMethod != null) {
+                return invokeFactoryMethod();
             } else {
-                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
-                    public Boolean run() { return hasNextService(); }
-                };
-                return AccessController.doPrivileged(action, acc);
+                return newInstance();
             }
         }
 
-        public final S next() {
+        /**
+         * Returns {@code true} if the provider is in an explicit module
+         */
+        private boolean inExplicitModule(Class<?> clazz) {
+            Module module = clazz.getModule();
+            return module.isNamed() && !module.getDescriptor().isAutomatic();
+        }
+
+        /**
+         * Returns the public static provider method if found.
+         *
+         * @throws ServiceConfigurationError if there is an error finding the
+         *         provider method
+         */
+        private Method findStaticProviderMethod(Class<?> clazz) {
+            Method method = null;
+            try {
+                method = LANG_ACCESS.getMethodOrNull(clazz, "provider");
+            } catch (Throwable x) {
+                fail(service, "Unable to get public provider() method", x);
+            }
+            if (method != null) {
+                int mods = method.getModifiers();
+                if (Modifier.isStatic(mods)) {
+                    assert Modifier.isPublic(mods);
+                    Method m = method;
+                    PrivilegedAction<Void> pa = () -> {
+                        m.setAccessible(true);
+                        return null;
+                    };
+                    AccessController.doPrivileged(pa);
+                    return method;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Returns the public no-arg constructor of a class.
+         *
+         * @throws ServiceConfigurationError if the class does not have
+         *         public no-arg constructor
+         */
+        private Constructor<?> getConstructor(Class<?> clazz) {
+            PrivilegedExceptionAction<Constructor<?>> pa
+                = new PrivilegedExceptionAction<>() {
+                    @Override
+                    public Constructor<?> run() throws Exception {
+                        Constructor<?> ctor = clazz.getConstructor();
+                        if (inExplicitModule(clazz))
+                            ctor.setAccessible(true);
+                        return ctor;
+                    }
+                };
+            Constructor<?> ctor = null;
+            try {
+                ctor = AccessController.doPrivileged(pa);
+            } catch (Throwable x) {
+                if (x instanceof PrivilegedActionException)
+                    x = x.getCause();
+                String cn = clazz.getName();
+                fail(service, cn + " Unable to get public no-arg constructor", x);
+            }
+            return ctor;
+        }
+
+        /**
+         * Invokes the provider's "provider" method to instantiate a provider.
+         * When running with a security manager then the method runs with
+         * permissions that are restricted by the security context of whatever
+         * created this loader.
+         */
+        private S invokeFactoryMethod() {
+            Object result = null;
+            Throwable exc = null;
             if (acc == null) {
-                return nextService();
+                try {
+                    result = factoryMethod.invoke(null);
+                } catch (Throwable x) {
+                    exc = x;
+                }
             } else {
-                PrivilegedAction<S> action = new PrivilegedAction<S>() {
-                    public S run() { return nextService(); }
+                PrivilegedExceptionAction<?> pa = new PrivilegedExceptionAction<>() {
+                    @Override
+                    public Object run() throws Exception {
+                        return factoryMethod.invoke(null);
+                    }
                 };
-                return AccessController.doPrivileged(action, acc);
+                // invoke factory method with permissions restricted by acc
+                try {
+                    result = AccessController.doPrivileged(pa, acc);
+                } catch (PrivilegedActionException pae) {
+                    exc = pae.getCause();
+                }
+            }
+            if (exc != null) {
+                if (exc instanceof InvocationTargetException)
+                    exc = exc.getCause();
+                fail(service, factoryMethod + " failed", exc);
+            }
+            if (result == null) {
+                fail(service, factoryMethod + " returned null");
             }
+            @SuppressWarnings("unchecked")
+            S p = (S) result;
+            return p;
+        }
+
+        /**
+         * Invokes Constructor::newInstance to instantiate a provider. When running
+         * with a security manager then the constructor runs with permissions that
+         * are restricted by the security context of whatever created this loader.
+         */
+        private S newInstance() {
+            S p = null;
+            Throwable exc = null;
+            if (acc == null) {
+                try {
+                    p = ctor.newInstance();
+                } catch (Throwable x) {
+                    exc = x;
+                }
+            } else {
+                PrivilegedExceptionAction<S> pa = new PrivilegedExceptionAction<>() {
+                    @Override
+                    public S run() throws Exception {
+                        return ctor.newInstance();
+                    }
+                };
+                // invoke constructor with permissions restricted by acc
+                try {
+                    p = AccessController.doPrivileged(pa, acc);
+                } catch (PrivilegedActionException pae) {
+                    exc = pae.getCause();
+                }
+            }
+            if (exc != null) {
+                if (exc instanceof InvocationTargetException)
+                    exc = exc.getCause();
+                String cn = ctor.getDeclaringClass().getName();
+                fail(service,
+                     "Provider " + cn + " could not be instantiated", exc);
+            }
+            return p;
+        }
+
+        // For now, equals/hashCode uses the access control context to ensure
+        // that two Providers created with different contexts are not equal
+        // when running with a security manager.
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(type, acc);
+        }
+
+        @Override
+        public boolean equals(Object ob) {
+            if (!(ob instanceof ProviderImpl))
+                return false;
+            @SuppressWarnings("unchecked")
+            ProviderImpl<?> that = (ProviderImpl<?>)ob;
+            return this.type == that.type
+                    && Objects.equals(this.acc, that.acc);
         }
     }
 
     /**
      * Implements lazy service provider lookup of service providers that
-     * are provided by modules in a module Layer.
+     * are provided by modules in a module Layer (or parent layers)
      */
-    private class LayerLookupIterator
-        extends RestrictedIterator<S>
+    private final class LayerLookupIterator<T>
+        implements Iterator<Provider<T>>
     {
-        final String serviceName;
-        Layer currentLayer;
+        Deque<Layer> stack = new ArrayDeque<>();
+        Set<Layer> visited = new HashSet<>();
         Iterator<ServiceProvider> iterator;
-        ServiceProvider nextProvider;
+        ServiceProvider next;  // next provider to load
 
         LayerLookupIterator() {
-            serviceName = service.getName();
-            currentLayer = layer;
-
-            // need to get us started
-            iterator = providers(currentLayer, serviceName);
+            visited.add(layer);
+            stack.push(layer);
         }
 
-        Iterator<ServiceProvider> providers(Layer layer, String service) {
-            ServicesCatalog catalog = SharedSecrets
-                    .getJavaLangReflectModuleAccess()
-                    .getServicesCatalog(layer);
-
+        private Iterator<ServiceProvider> providers(Layer layer) {
+            ServicesCatalog catalog = JLRM_ACCESS.getServicesCatalog(layer);
             return catalog.findServices(serviceName).iterator();
         }
 
         @Override
-        boolean hasNextService() {
-
+        public boolean hasNext() {
             // already have the next provider cached
-            if (nextProvider != null)
+            if (next != null)
                 return true;
 
             while (true) {
 
-                // next provider
+                // next provider (or provider factory)
                 if (iterator != null && iterator.hasNext()) {
-                    nextProvider = iterator.next();
+                    next = iterator.next();
                     return true;
                 }
 
-                // next layer
-                Layer parent = currentLayer.parent().orElse(null);
-                if (parent == null)
+                // next layer (DFS order)
+                if (stack.isEmpty())
                     return false;
 
-                currentLayer = parent;
-                iterator = providers(currentLayer, serviceName);
+                Layer layer = stack.pop();
+                List<Layer> parents = layer.parents();
+                for (int i = parents.size() - 1; i >= 0; i--) {
+                    Layer parent = parents.get(i);
+                    if (!visited.contains(parent)) {
+                        visited.add(parent);
+                        stack.push(parent);
+                    }
+                }
+                iterator = providers(layer);
             }
         }
 
         @Override
-        S nextService() {
-            if (!hasNextService())
+        public Provider<T> next() {
+            if (!hasNext())
                 throw new NoSuchElementException();
 
-            ServiceProvider provider = nextProvider;
-            nextProvider = null;
+            // take next provider
+            ServiceProvider provider = next;
+            next = null;
 
+            // attempt to load provider
             Module module = provider.module();
             String cn = provider.providerName();
-
-            // attempt to load the provider
-            Class<?> c = loadClassInModule(module, cn);
-            if (c == null)
-                fail(service, "Provider " + cn  + " not found");
-            if (!service.isAssignableFrom(c))
-                fail(service, "Provider " + cn  + " not a subtype");
-
-            // instantiate the provider
-            S p = null;
-            try {
-                Constructor<?> ctor = checkAndGetConstructor(c);
-                p = service.cast(ctor.newInstance());
-            } catch (Throwable x) {
-                if (x instanceof InvocationTargetException)
-                    x = x.getCause();
-                fail(service,
-                        "Provider " + cn + " could not be instantiated", x);
-            }
-
-            // add to cached provider list
-            providers.add(p);
-
-            return p;
+            Class<?> clazz = loadProviderInModule(module, cn);
+            return new ProviderImpl<T>(service, clazz, acc);
         }
     }
 
     /**
      * Implements lazy service provider lookup of service providers that
-     * are provided by modules defined to a class loader.
+     * are provided by modules defined to a class loader or to modules in
+     * layers with a module defined to the class loader.
      */
-    private class ModuleServicesIterator
-        extends RestrictedIterator<S>
+    private final class ModuleServicesLookupIterator<T>
+        implements Iterator<Provider<T>>
     {
-        final JavaLangAccess langAccess = SharedSecrets.getJavaLangAccess();
-
         ClassLoader currentLoader;
         Iterator<ServiceProvider> iterator;
-        ServiceProvider nextProvider;
+        ServiceProvider next;  // next provider to load
 
-        ModuleServicesIterator() {
+        ModuleServicesLookupIterator() {
             this.currentLoader = loader;
             this.iterator = iteratorFor(loader);
         }
 
         /**
+         * Returns iterator to iterate over the implementations of {@code
+         * service} in the given layer.
+         */
+        private List<ServiceProvider> providers(Layer layer) {
+            ServicesCatalog catalog = JLRM_ACCESS.getServicesCatalog(layer);
+            return catalog.findServices(serviceName);
+        }
+
+        /**
          * Returns an iterator to iterate over the implementations of {@code
-         * service} in modules defined to the given class loader.
+         * service} in modules defined to the given class loader or in custom
+         * layers with a module defined to this class loader.
          */
         private Iterator<ServiceProvider> iteratorFor(ClassLoader loader) {
 
-            // if the class loader is in a loader pool then return an Iterator
-            // that iterates over all service providers in the pool that provide
-            // an implementation of the service
-            if (currentLoader instanceof Loader) {
-                LoaderPool pool = ((Loader) loader).pool();
-                if (pool != null) {
-                    return pool.loaders()
-                            .map(l -> langAccess.getServicesCatalog(l))
-                            .filter(sc -> sc != null)
-                            .map(sc -> sc.findServices(service.getName()))
-                            .flatMap(Set::stream)
-                            .iterator();
-                }
+            // modules defined to this class loader
+            ServicesCatalog catalog;
+            if (loader == null) {
+                catalog = BootLoader.getServicesCatalog();
+            } else {
+                catalog = ServicesCatalog.getServicesCatalogOrNull(loader);
+            }
+            Stream<ServiceProvider> stream1;
+            if (catalog == null) {
+                stream1 = Stream.empty();
+            } else {
+                stream1 = catalog.findServices(serviceName).stream();
             }
 
-            ServicesCatalog catalog;
-            if (currentLoader == null) {
-                catalog = BootLoader.getServicesCatalog();
+            // modules in custom layers that define modules to the class loader
+            Stream<ServiceProvider> stream2;
+            if (loader == null) {
+                stream2 = Stream.empty();
             } else {
-                catalog = langAccess.getServicesCatalog(currentLoader);
+                Layer bootLayer = Layer.boot();
+                stream2 = JLRM_ACCESS.layers(loader)
+                        .filter(l -> (l != bootLayer))
+                        .map(l -> providers(l))
+                        .flatMap(List::stream);
             }
-            if (catalog == null) {
-                return Collections.emptyIterator();
-            } else {
-                return catalog.findServices(service.getName()).iterator();
-            }
+
+            return Stream.concat(stream1, stream2).iterator();
         }
 
         @Override
-        boolean hasNextService() {
+        public boolean hasNext() {
             // already have the next provider cached
-            if (nextProvider != null)
+            if (next != null)
                 return true;
 
             while (true) {
                 if (iterator.hasNext()) {
-                    nextProvider = iterator.next();
+                    next = iterator.next();
                     return true;
                 }
 
@@ -710,138 +972,220 @@
         }
 
         @Override
-        S nextService() {
-            if (!hasNextService())
+        public Provider<T> next() {
+            if (!hasNext())
                 throw new NoSuchElementException();
 
-            ServiceProvider provider = nextProvider;
-            nextProvider = null;
+            // take next provider
+            ServiceProvider provider = next;
+            next = null;
 
-            // attempt to load the provider
+            // attempt to load provider
             Module module = provider.module();
             String cn = provider.providerName();
-
-            Class<?> c = loadClassInModule(module, cn);
-            if (c == null) {
-                fail(service,
-                    "Provider " + cn + " not found in " + module.getName());
-            }
-            if (!service.isAssignableFrom(c)) {
-                fail(service, "Provider " + cn  + " not a subtype");
-            }
-
-            // instantiate the provider
-            S p = null;
-            try {
-                Constructor<?> ctor = checkAndGetConstructor(c);
-                p = service.cast(ctor.newInstance());
-            } catch (Throwable x) {
-                if (x instanceof InvocationTargetException)
-                    x = x.getCause();
-                fail(service,
-                    "Provider " + cn + " could not be instantiated", x);
-            }
-
-            // add to provider list
-            providers.add(p);
-
-            // record the class name of the service provider, this is
-            // needed for cases where there a module has both a "uses"
-            // and a services configuration file listing the same
-            // provider
-            providerNames.add(cn);
-
-            return p;
+            Class<?> clazz = loadProviderInModule(module, cn);
+            return new ProviderImpl<T>(service, clazz, acc);
         }
     }
 
     /**
-     * Implements lazy service provider lookup where the service providers
-     * are configured via service configuration files.
+     * Implements lazy service provider lookup where the service providers are
+     * configured via service configuration files. Service providers in named
+     * modules are silently ignored by this lookup iterator.
      */
-    private class LazyClassPathIterator
-        extends RestrictedIterator<S>
+    private final class LazyClassPathLookupIterator<T>
+        implements Iterator<Provider<T>>
     {
+        static final String PREFIX = "META-INF/services/";
+
         Enumeration<URL> configs;
         Iterator<String> pending;
-        String nextName;
+        Class<?> nextClass;
+        String nextErrorMessage;  // when hasNext fails with CNFE
+
+        LazyClassPathLookupIterator() { }
 
-        @Override
-        boolean hasNextService() {
-            if (nextName != null) {
+        /**
+         * Parse a single line from the given configuration file, adding the
+         * name on the line to the names list.
+         */
+        private int parseLine(URL u, BufferedReader r, int lc, Set<String> names)
+            throws IOException
+        {
+            String ln = r.readLine();
+            if (ln == null) {
+                return -1;
+            }
+            int ci = ln.indexOf('#');
+            if (ci >= 0) ln = ln.substring(0, ci);
+            ln = ln.trim();
+            int n = ln.length();
+            if (n != 0) {
+                if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
+                    fail(service, u, lc, "Illegal configuration-file syntax");
+                int cp = ln.codePointAt(0);
+                if (!Character.isJavaIdentifierStart(cp))
+                    fail(service, u, lc, "Illegal provider-class name: " + ln);
+                int start = Character.charCount(cp);
+                for (int i = start; i < n; i += Character.charCount(cp)) {
+                    cp = ln.codePointAt(i);
+                    if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
+                        fail(service, u, lc, "Illegal provider-class name: " + ln);
+                }
+                names.add(ln);
+            }
+            return lc + 1;
+        }
+
+        /**
+         * Parse the content of the given URL as a provider-configuration file.
+         */
+        private Iterator<String> parse(URL u) {
+            Set<String> names = new LinkedHashSet<>(); // preserve insertion order
+            try {
+                URLConnection uc = u.openConnection();
+                uc.setUseCaches(false);
+                try (InputStream in = uc.getInputStream();
+                     BufferedReader r
+                         = new BufferedReader(new InputStreamReader(in, "utf-8")))
+                {
+                    int lc = 1;
+                    while ((lc = parseLine(u, r, lc, names)) >= 0);
+                }
+            } catch (IOException x) {
+                fail(service, "Error accessing configuration file", x);
+            }
+            return names.iterator();
+        }
+
+        private boolean hasNextService() {
+            if (nextClass != null || nextErrorMessage != null) {
                 return true;
             }
-            if (configs == null) {
+
+            Class<?> clazz = null;
+            do {
+                if (configs == null) {
+                    try {
+                        String fullName = PREFIX + service.getName();
+                        if (loader == null)
+                            configs = ClassLoader.getSystemResources(fullName);
+                        else
+                            configs = loader.getResources(fullName);
+                    } catch (IOException x) {
+                        fail(service, "Error locating configuration files", x);
+                    }
+                }
+                while ((pending == null) || !pending.hasNext()) {
+                    if (!configs.hasMoreElements()) {
+                        return false;
+                    }
+                    pending = parse(configs.nextElement());
+                }
+                String cn = pending.next();
                 try {
-                    String fullName = PREFIX + service.getName();
-                    if (loader == null)
-                        configs = ClassLoader.getSystemResources(fullName);
-                    else
-                        configs = loader.getResources(fullName);
-                } catch (IOException x) {
-                    fail(service, "Error locating configuration files", x);
+                    clazz = Class.forName(cn, false, loader);
+                } catch (ClassNotFoundException x) {
+                    // don't throw SCE here to long standing behavior
+                    nextErrorMessage = "Provider " + cn + " not found";
+                    return true;
                 }
-            }
-            while ((pending == null) || !pending.hasNext()) {
-                if (!configs.hasMoreElements()) {
-                    return false;
-                }
-                pending = parse(service, configs.nextElement());
-            }
-            nextName = pending.next();
+
+            } while (clazz.getModule().isNamed()); // ignore if in named module
+
+            nextClass = clazz;
             return true;
         }
 
-        @Override
-        S nextService() {
+        private Provider<T> nextService() {
             if (!hasNextService())
                 throw new NoSuchElementException();
-            String cn = nextName;
-            nextName = null;
-            Class<?> c = null;
-            try {
-                c = Class.forName(cn, false, loader);
-            } catch (ClassNotFoundException x) {
-                fail(service,
-                     "Provider " + cn + " not found");
-            }
-            if (!service.isAssignableFrom(c)) {
-                fail(service,
-                     "Provider " + cn  + " not a subtype");
+
+            // throw any SCE with error recorded by hasNext
+            if (nextErrorMessage != null) {
+                String msg = nextErrorMessage;
+                nextErrorMessage = null;
+                fail(service, msg);
             }
-            S p = null;
-            try {
-                @SuppressWarnings("deprecation")
-                Object tmp = c.newInstance();
-                p = service.cast(tmp);
-            } catch (Throwable x) {
-                fail(service,
-                     "Provider " + cn + " could not be instantiated",
-                     x);
+
+            // return next provider
+            Class<?> clazz = nextClass;
+            nextClass = null;
+            return new ProviderImpl<T>(service, clazz, acc);
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (acc == null) {
+                return hasNextService();
+            } else {
+                PrivilegedAction<Boolean> action = new PrivilegedAction<>() {
+                    public Boolean run() { return hasNextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
             }
-            providers.add(p);
-            providerNames.add(cn);
-            return p;
+        }
+
+        @Override
+        public Provider<T> next() {
+            if (acc == null) {
+                return nextService();
+            } else {
+                PrivilegedAction<Provider<T>> action = new PrivilegedAction<>() {
+                    public Provider<T> run() { return nextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
         }
     }
 
     /**
-     * Lazily loads the available providers of this loader's service.
+     * Returns a new lookup iterator.
+     */
+    private Iterator<Provider<S>> newLookupIterator() {
+        assert layer == null || loader == null;
+        if (layer != null) {
+            return new LayerLookupIterator<>();
+        } else {
+            Iterator<Provider<S>> first = new ModuleServicesLookupIterator<>();
+            Iterator<Provider<S>> second = new LazyClassPathLookupIterator<>();
+            return new Iterator<Provider<S>>() {
+                @Override
+                public boolean hasNext() {
+                    return (first.hasNext() || second.hasNext());
+                }
+                @Override
+                public Provider<S> next() {
+                    if (first.hasNext()) {
+                        return first.next();
+                    } else if (second.hasNext()) {
+                        return second.next();
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+    }
+
+    /**
+     * Lazily load and instantiate the available providers of this loader's
+     * service.
      *
      * <p> The iterator returned by this method first yields all of the
-     * elements of the provider cache, in instantiation order.  It then lazily
-     * loads and instantiates any remaining providers, adding each one to the
-     * cache in turn.
+     * elements of the provider cache, in the order that they were loaded.
+     * It then lazily loads and instantiates any remaining providers,
+     * adding each one to the cache in turn.
      *
      * <p> To achieve laziness the actual work of locating and instantiating
      * providers must be done by the iterator itself. Its {@link
      * java.util.Iterator#hasNext hasNext} and {@link java.util.Iterator#next
      * next} methods can therefore throw a {@link ServiceConfigurationError}
-     * if a provider class cannot be loaded, doesn't have the appropriate
-     * constructor, can't be assigned to the service type or if any other kind
-     * of exception or error is thrown as the next provider is located and
-     * instantiated. To write robust code it is only necessary to catch {@link
-     * ServiceConfigurationError} when using a service iterator.
+     * if a provider class cannot be loaded, doesn't have an appropriate static
+     * factory method or constructor, can't be assigned to the service type or
+     * if any other kind of exception or error is thrown as the next provider
+     * is located and instantiated. To write robust code it is only necessary
+     * to catch {@link ServiceConfigurationError} when using a service iterator.
      *
      * <p> If such an error is thrown then subsequent invocations of the
      * iterator will make a best effort to locate and instantiate the next
@@ -856,7 +1200,7 @@
      * preferable to throw an error rather than try to recover or, even worse,
      * fail silently.</blockquote>
      *
-     * <p> If this loader's provider cache is cleared by invoking the {@link
+     * <p> If this loader's provider caches are cleared by invoking the {@link
      * #reload() reload} method then existing iterators for this service
      * loader should be discarded.
      * The {@link java.util.Iterator#hasNext() hasNext} and {@link
@@ -868,16 +1212,16 @@
      * Invoking its {@link java.util.Iterator#remove() remove} method will
      * cause an {@link UnsupportedOperationException} to be thrown.
      *
-     * @implNote When adding providers to the cache, the {@link #iterator
-     * Iterator} processes resources in the order that the {@link
-     * java.lang.ClassLoader#getResources(java.lang.String)
-     * ClassLoader.getResources(String)} method finds the service configuration
-     * files.
-     *
      * @return  An iterator that lazily loads providers for this loader's
      *          service
      */
     public Iterator<S> iterator() {
+
+        // create lookup iterator if needed
+        if (lookupIterator1 == null) {
+            lookupIterator1 = newLookupIterator();
+        }
+
         return new Iterator<S>() {
 
             // record reload count
@@ -895,34 +1239,23 @@
                     throw new ConcurrentModificationException();
             }
 
+            @Override
             public boolean hasNext() {
                 checkReloadCount();
-                if (index < providers.size())
+                if (index < instantiatedProviders.size())
                     return true;
-
-                if (layerLookupIterator != null) {
-                    return layerLookupIterator.hasNext();
-                } else {
-                    return moduleServicesIterator.hasNext() ||
-                            lazyClassPathIterator.hasNext();
-                }
+                return lookupIterator1.hasNext();
             }
 
+            @Override
             public S next() {
                 checkReloadCount();
                 S next;
-                if (index < providers.size()) {
-                    next = providers.get(index);
+                if (index < instantiatedProviders.size()) {
+                    next = instantiatedProviders.get(index);
                 } else {
-                    if (layerLookupIterator != null) {
-                        next = layerLookupIterator.next();
-                    } else {
-                        if (moduleServicesIterator.hasNext()) {
-                            next = moduleServicesIterator.next();
-                        } else {
-                            next = lazyClassPathIterator.next();
-                        }
-                    }
+                    next = lookupIterator1.next().get();
+                    instantiatedProviders.add(next);
                 }
                 index++;
                 return next;
@@ -932,6 +1265,108 @@
     }
 
     /**
+     * Returns a stream that lazily loads the available providers of this
+     * loader's service. The stream elements are of type {@link Provider
+     * Provider}, the {@code Provider}'s {@link Provider#get() get} method
+     * must be invoked to get or instantiate the provider.
+     *
+     * <p> When processing the stream then providers that were previously
+     * loaded by stream operations are processed first, in load order. It then
+     * lazily loads any remaining providers. If a provider class cannot be
+     * loaded, can't be assigned to the service type, or some other error is
+     * thrown when locating the provider then it is wrapped with a {@code
+     * ServiceConfigurationError} and thrown by whatever method caused the
+     * provider to be loaded. </p>
+     *
+     * <p> If this loader's provider caches are cleared by invoking the {@link
+     * #reload() reload} method then existing streams for this service
+     * loader should be discarded. </p>
+     *
+     * <p> The following examples demonstrate usage. The first example
+     * creates a stream of providers, the second example is the same except
+     * that it sorts the providers by provider class name (and so locate all
+     * providers).
+     * <pre>{@code
+     *    Stream<CodecSet> providers = ServiceLoader.load(CodecSet.class)
+     *            .stream()
+     *            .map(Provider::get);
+     *
+     *    Stream<CodecSet> providers = ServiceLoader.load(CodecSet.class)
+     *            .stream()
+     *            .sorted(Comparator.comparing(p -> p.type().getName()))
+     *            .map(Provider::get);
+     * }</pre>
+     *
+     * @return  A stream that lazily loads providers for this loader's service
+     *
+     * @since 9
+     */
+    public Stream<Provider<S>> stream() {
+        // use cached providers as the source when all providers loaded
+        if (loadedAllProviders) {
+            return loadedProviders.stream();
+        }
+
+        // create lookup iterator if needed
+        if (lookupIterator2 == null) {
+            lookupIterator2 = newLookupIterator();
+        }
+
+        // use lookup iterator and cached providers as source
+        Spliterator<Provider<S>> s = new ProviderSpliterator<>(lookupIterator2);
+        return StreamSupport.stream(s, false);
+    }
+
+    private class ProviderSpliterator<T> implements Spliterator<Provider<T>> {
+        final int expectedReloadCount = ServiceLoader.this.reloadCount;
+        final Iterator<Provider<T>> iterator;
+        int index;
+
+        ProviderSpliterator(Iterator<Provider<T>> iterator) {
+            this.iterator = iterator;
+        }
+
+        @Override
+        public Spliterator<Provider<T>> trySplit() {
+            return null;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super Provider<T>> action) {
+            if (ServiceLoader.this.reloadCount != expectedReloadCount)
+                throw new ConcurrentModificationException();
+            Provider<T> next = null;
+            if (index < loadedProviders.size()) {
+                next = (Provider<T>) loadedProviders.get(index++);
+            } else if (iterator.hasNext()) {
+                next = iterator.next();
+            } else {
+                loadedAllProviders = true;
+            }
+            if (next != null) {
+                action.accept(next);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public int characteristics() {
+            // not IMMUTABLE as structural interference possible
+            // not NOTNULL so that the characteristics are a subset of the
+            // characteristics when all Providers have been located.
+            return Spliterator.ORDERED;
+        }
+
+        @Override
+        public long estimateSize() {
+            return Long.MAX_VALUE;
+        }
+    }
+
+    /**
      * Creates a new service loader for the given service type, class
      * loader, and caller.
      *
@@ -977,7 +1412,7 @@
      *
      * @throws ServiceConfigurationError
      *         if the service type is not accessible to the caller or the
-     *         caller is in a named module and its module descriptor does
+     *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
      */
     @CallerSensitive
@@ -993,15 +1428,23 @@
      * context class loader}.
      *
      * <p> An invocation of this convenience method of the form
-     *
-     * <blockquote><pre>
-     * ServiceLoader.load(<i>service</i>)</pre></blockquote>
+     * <pre>{@code
+     * ServiceLoader.load(service)
+     * }</pre>
      *
      * is equivalent to
      *
-     * <blockquote><pre>
-     * ServiceLoader.load(<i>service</i>,
-     *                    Thread.currentThread().getContextClassLoader())</pre></blockquote>
+     * <pre>{@code
+     * ServiceLoader.load(service, Thread.currentThread().getContextClassLoader())
+     * }</pre>
+     *
+     * @apiNote Service loader objects obtained with this method should not be
+     * cached VM-wide. For example, different applications in the same VM may
+     * have different thread context class loaders. A lookup by one application
+     * may locate a service provider that is only visible via its thread
+     * context class loader and so is not suitable to be located by the other
+     * application. Memory leaks can also arise. A thread local may be suited
+     * to some applications.
      *
      * @param  <S> the class of the service type
      *
@@ -1012,7 +1455,7 @@
      *
      * @throws ServiceConfigurationError
      *         if the service type is not accessible to the caller or the
-     *         caller is in a named module and its module descriptor does
+     *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
      */
     @CallerSensitive
@@ -1027,9 +1470,9 @@
      *
      * <p> This convenience method is equivalent to: </p>
      *
-     * <blockquote><pre>
-     * ServiceLoader.load(<i>service</i>, <i>ClassLoader.getPlatformClassLoader())</i>
-     * </pre></blockquote>
+     * <pre>{@code
+     * ServiceLoader.load(service, ClassLoader.getPlatformClassLoader())
+     * }</pre>
      *
      * <p> This method is intended for use when only installed providers are
      * desired.  The resulting service will only find and load providers that
@@ -1045,18 +1488,13 @@
      *
      * @throws ServiceConfigurationError
      *         if the service type is not accessible to the caller or the
-     *         caller is in a named module and its module descriptor does
+     *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
      */
     @CallerSensitive
     public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
-        ClassLoader cl = ClassLoader.getSystemClassLoader();
-        ClassLoader prev = null;
-        while (cl != null) {
-            prev = cl;
-            cl = cl.getParent();
-        }
-        return new ServiceLoader<>(Reflection.getCallerClass(), service, prev);
+        ClassLoader cl = ClassLoader.getPlatformClassLoader();
+        return new ServiceLoader<>(Reflection.getCallerClass(), service, cl);
     }
 
     /**
@@ -1080,16 +1518,71 @@
      *
      * @throws ServiceConfigurationError
      *         if the service type is not accessible to the caller or the
-     *         caller is in a named module and its module descriptor does
+     *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
      *
      * @since 9
      */
     @CallerSensitive
     public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) {
-        return new ServiceLoader<>(Reflection.getCallerClass(),
-                                   Objects.requireNonNull(layer),
-                                   Objects.requireNonNull(service));
+        return new ServiceLoader<>(Reflection.getCallerClass(), layer, service);
+    }
+
+    /**
+     * Load the first available provider of this loader's service. This
+     * convenience method is equivalent to invoking the {@link #iterator()
+     * iterator()} method and obtaining the first element. It therefore
+     * returns the first element from the provider cache if possible, it
+     * otherwise attempts to load and instantiate the first provider.
+     *
+     * <p> The following example loads the first available provider. If there
+     * are no providers deployed then it uses a default implementation.
+     * <pre>{@code
+     *    CodecSet provider =
+     *        ServiceLoader.load(CodecSet.class).findFirst().orElse(DEFAULT_CODECSET);
+     * }</pre>
+     * @return The first provider or empty {@code Optional} if no providers
+     *         are located
+     *
+     * @throws ServiceConfigurationError
+     *         If a provider class cannot be loaded, doesn't have the
+     *         appropriate static factory method or constructor, can't be
+     *         assigned to the service type, or if any other kind of exception
+     *         or error is thrown when locating or instantiating the provider.
+     *
+     * @since 9
+     */
+    public Optional<S> findFirst() {
+        Iterator<S> iterator = iterator();
+        if (iterator.hasNext()) {
+            return Optional.of(iterator.next());
+        } else {
+            return Optional.empty();
+        }
+    }
+
+    /**
+     * Clear this loader's provider cache so that all providers will be
+     * reloaded.
+     *
+     * <p> After invoking this method, subsequent invocations of the {@link
+     * #iterator() iterator} or {@link #stream() stream} methods will lazily
+     * look up providers (and instantiate in the case of {@code iterator})
+     * from scratch, just as is done by a newly-created loader.
+     *
+     * <p> This method is intended for use in situations in which new providers
+     * can be installed into a running Java virtual machine.
+     */
+    public void reload() {
+        lookupIterator1 = null;
+        instantiatedProviders.clear();
+
+        lookupIterator2 = null;
+        loadedProviders.clear();
+        loadedAllProviders = false;
+
+        // increment count to allow CME be thrown
+        reloadCount++;
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/Vector.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/Vector.java	Thu Dec 01 21:39:49 2016 +0000
@@ -513,7 +513,7 @@
      * Returns the last component of the vector.
      *
      * @return  the last component of the vector, i.e., the component at index
-     *          <code>size()&nbsp;-&nbsp;1</code>.
+     *          {@code size() - 1}
      * @throws NoSuchElementException if this vector is empty
      */
     public synchronized E lastElement() {
@@ -675,10 +675,7 @@
      * method (which is part of the {@link List} interface).
      */
     public synchronized void removeAllElements() {
-        // Let gc do its work
-        for (int i = 0; i < elementCount; i++)
-            elementData[i] = null;
-
+        Arrays.fill(elementData, 0, elementCount, null);
         modCount++;
         elementCount = 0;
     }
@@ -693,7 +690,7 @@
     public synchronized Object clone() {
         try {
             @SuppressWarnings("unchecked")
-                Vector<E> v = (Vector<E>) super.clone();
+            Vector<E> v = (Vector<E>) super.clone();
             v.elementData = Arrays.copyOf(elementData, elementCount);
             v.modCount = 0;
             return v;
@@ -759,6 +756,11 @@
         return (E) elementData[index];
     }
 
+    @SuppressWarnings("unchecked")
+    static <E> E elementAt(Object[] es, int index) {
+        return (E) es[index];
+    }
+
     /**
      * Returns the element at the specified position in this Vector.
      *
@@ -855,10 +857,10 @@
      * Shifts any subsequent elements to the left (subtracts one from their
      * indices).  Returns the element that was removed from the Vector.
      *
+     * @param index the index of the element to be removed
+     * @return element that was removed
      * @throws ArrayIndexOutOfBoundsException if the index is out of range
      *         ({@code index < 0 || index >= size()})
-     * @param index the index of the element to be removed
-     * @return element that was removed
      * @since 1.2
      */
     public synchronized E remove(int index) {
@@ -949,8 +951,9 @@
      *         or if the specified collection is null
      * @since 1.2
      */
-    public synchronized boolean removeAll(Collection<?> c) {
-        return super.removeAll(c);
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
     }
 
     /**
@@ -972,8 +975,62 @@
      *         or if the specified collection is null
      * @since 1.2
      */
-    public synchronized boolean retainAll(Collection<?> c) {
-        return super.retainAll(c);
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    @Override
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    private synchronized boolean bulkRemove(Predicate<? super E> filter) {
+        int expectedModCount = modCount;
+        final Object[] es = elementData;
+        final int end = elementCount;
+        int i;
+        // Optimize for initial run of survivors
+        for (i = 0; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        // Tolerate predicates that reentrantly access the collection for
+        // read (but writers still get CME), so traverse once to find
+        // elements to delete, a second pass to physically expunge.
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i)))
+                    setBit(deathRow, i - beg);
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            expectedModCount++;
+            modCount++;
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    es[w++] = es[i];
+            Arrays.fill(es, elementCount = w, end, null);
+            return true;
+        } else {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return false;
+        }
     }
 
     /**
@@ -1095,15 +1152,12 @@
      * (If {@code toIndex==fromIndex}, this operation has no effect.)
      */
     protected synchronized void removeRange(int fromIndex, int toIndex) {
-        int numMoved = elementCount - toIndex;
-        System.arraycopy(elementData, toIndex, elementData, fromIndex,
-                         numMoved);
+        final Object[] es = elementData;
+        final int oldSize = elementCount;
+        System.arraycopy(es, toIndex, es, fromIndex, oldSize - toIndex);
 
-        // Let gc do its work
         modCount++;
-        int newElementCount = elementCount - (toIndex-fromIndex);
-        while (elementCount != newElementCount)
-            elementData[--elementCount] = null;
+        Arrays.fill(es, elementCount -= (toIndex - fromIndex), oldSize, null);
     }
 
     /**
@@ -1212,14 +1266,11 @@
                 if (i >= size) {
                     return;
                 }
-        @SuppressWarnings("unchecked")
-                final E[] elementData = (E[]) Vector.this.elementData;
-                if (i >= elementData.length) {
+                final Object[] es = elementData;
+                if (i >= es.length)
                     throw new ConcurrentModificationException();
-                }
-                while (i != size && modCount == expectedModCount) {
-                    action.accept(elementData[i++]);
-                }
+                while (i < size && modCount == expectedModCount)
+                    action.accept(elementAt(es, i++));
                 // update once at end of iteration to reduce heap write traffic
                 cursor = i;
                 lastRet = i - 1;
@@ -1290,73 +1341,24 @@
     public synchronized void forEach(Consumer<? super E> action) {
         Objects.requireNonNull(action);
         final int expectedModCount = modCount;
-        @SuppressWarnings("unchecked")
-        final E[] elementData = (E[]) this.elementData;
-        final int elementCount = this.elementCount;
-        for (int i=0; modCount == expectedModCount && i < elementCount; i++) {
-            action.accept(elementData[i]);
-        }
-        if (modCount != expectedModCount) {
+        final Object[] es = elementData;
+        final int size = elementCount;
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            action.accept(elementAt(es, i));
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
     }
 
     @Override
-    @SuppressWarnings("unchecked")
-    public synchronized boolean removeIf(Predicate<? super E> filter) {
-        Objects.requireNonNull(filter);
-        // figure out which elements are to be removed
-        // any exception thrown from the filter predicate at this stage
-        // will leave the collection unmodified
-        int removeCount = 0;
-        final int size = elementCount;
-        final BitSet removeSet = new BitSet(size);
-        final int expectedModCount = modCount;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            @SuppressWarnings("unchecked")
-            final E element = (E) elementData[i];
-            if (filter.test(element)) {
-                removeSet.set(i);
-                removeCount++;
-            }
-        }
-        if (modCount != expectedModCount) {
-            throw new ConcurrentModificationException();
-        }
-
-        // shift surviving elements left over the spaces left by removed elements
-        final boolean anyToRemove = removeCount > 0;
-        if (anyToRemove) {
-            final int newSize = size - removeCount;
-            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
-                i = removeSet.nextClearBit(i);
-                elementData[j] = elementData[i];
-            }
-            for (int k=newSize; k < size; k++) {
-                elementData[k] = null;  // Let gc do its work
-            }
-            elementCount = newSize;
-            if (modCount != expectedModCount) {
-                throw new ConcurrentModificationException();
-            }
-            modCount++;
-        }
-
-        return anyToRemove;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
     public synchronized void replaceAll(UnaryOperator<E> operator) {
         Objects.requireNonNull(operator);
         final int expectedModCount = modCount;
+        final Object[] es = elementData;
         final int size = elementCount;
-        for (int i=0; modCount == expectedModCount && i < size; i++) {
-            elementData[i] = operator.apply((E) elementData[i]);
-        }
-        if (modCount != expectedModCount) {
+        for (int i = 0; modCount == expectedModCount && i < size; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
         modCount++;
     }
 
@@ -1365,9 +1367,8 @@
     public synchronized void sort(Comparator<? super E> c) {
         final int expectedModCount = modCount;
         Arrays.sort((E[]) elementData, 0, elementCount, c);
-        if (modCount != expectedModCount) {
+        if (modCount != expectedModCount)
             throw new ConcurrentModificationException();
-        }
         modCount++;
     }
 
@@ -1397,7 +1398,7 @@
         private int fence; // -1 until used; then one past last index
         private int expectedModCount; // initialized when fence set
 
-        /** Create new spliterator covering the given  range */
+        /** Create new spliterator covering the given range */
         VectorSpliterator(Vector<E> list, Object[] array, int origin, int fence,
                           int expectedModCount) {
             this.list = list;
@@ -1410,7 +1411,7 @@
         private int getFence() { // initialize on first use
             int hi;
             if ((hi = fence) < 0) {
-                synchronized(list) {
+                synchronized (list) {
                     array = list.elementData;
                     expectedModCount = list.modCount;
                     hi = fence = list.elementCount;
@@ -1449,7 +1450,7 @@
                 throw new NullPointerException();
             if ((lst = list) != null) {
                 if ((hi = fence) < 0) {
-                    synchronized(lst) {
+                    synchronized (lst) {
                         expectedModCount = lst.modCount;
                         a = array = lst.elementData;
                         hi = fence = lst.elementCount;
@@ -1475,4 +1476,9 @@
             return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
         }
     }
+
+    void checkInvariants() {
+        // assert elementCount >= 0;
+        // assert elementCount == elementData.length || elementData[elementCount] == null;
+    }
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ArrayBlockingQueue.java	Thu Dec 01 21:39:49 2016 +0000
@@ -46,6 +46,8 @@
 import java.util.Spliterators;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 /**
  * A bounded {@linkplain BlockingQueue blocking queue} backed by an
@@ -85,6 +87,11 @@
 public class ArrayBlockingQueue<E> extends AbstractQueue<E>
         implements BlockingQueue<E>, java.io.Serializable {
 
+    /*
+     * Much of the implementation mechanics, especially the unusual
+     * nested loops, are shared and co-maintained with ArrayDeque.
+     */
+
     /**
      * Serialization ID. This class relies on default serialization
      * even for the items array, which is default-serialized, even if
@@ -129,10 +136,21 @@
     // Internal helper methods
 
     /**
-     * Circularly decrements array index i.
+     * Increments i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
      */
-    final int dec(int i) {
-        return ((i == 0) ? items.length : i) - 1;
+    static final int inc(int i, int modulus) {
+        if (++i >= modulus) i = 0;
+        return i;
+    }
+
+    /**
+     * Decrements i, mod modulus.
+     * Precondition and postcondition: 0 <= i < modulus.
+     */
+    static final int dec(int i, int modulus) {
+        if (--i < 0) i = modulus - 1;
+        return i;
     }
 
     /**
@@ -144,14 +162,24 @@
     }
 
     /**
+     * Returns element at array index i.
+     * This is a slight abuse of generics, accepted by javac.
+     */
+    @SuppressWarnings("unchecked")
+    static <E> E itemAt(Object[] items, int i) {
+        return (E) items[i];
+    }
+
+    /**
      * Inserts element at current put position, advances, and signals.
      * Call only when holding lock.
      */
-    private void enqueue(E x) {
+    private void enqueue(E e) {
+        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[putIndex] == null;
         final Object[] items = this.items;
-        items[putIndex] = x;
+        items[putIndex] = e;
         if (++putIndex == items.length) putIndex = 0;
         count++;
         notEmpty.signal();
@@ -162,18 +190,19 @@
      * Call only when holding lock.
      */
     private E dequeue() {
+        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[takeIndex] != null;
         final Object[] items = this.items;
         @SuppressWarnings("unchecked")
-        E x = (E) items[takeIndex];
+        E e = (E) items[takeIndex];
         items[takeIndex] = null;
         if (++takeIndex == items.length) takeIndex = 0;
         count--;
         if (itrs != null)
             itrs.elementDequeued();
         notFull.signal();
-        return x;
+        return e;
     }
 
     /**
@@ -182,6 +211,7 @@
      * Call only when holding lock.
      */
     void removeAt(final int removeIndex) {
+        // assert lock.isHeldByCurrentThread();
         // assert lock.getHoldCount() == 1;
         // assert items[removeIndex] != null;
         // assert removeIndex >= 0 && removeIndex < items.length;
@@ -267,6 +297,7 @@
         final ReentrantLock lock = this.lock;
         lock.lock(); // Lock only for visibility, not mutual exclusion
         try {
+            final Object[] items = this.items;
             int i = 0;
             try {
                 for (E e : c)
@@ -481,15 +512,16 @@
         try {
             if (count > 0) {
                 final Object[] items = this.items;
-                final int putIndex = this.putIndex;
-                int i = takeIndex;
-                do {
-                    if (o.equals(items[i])) {
-                        removeAt(i);
-                        return true;
-                    }
-                    if (++i == items.length) i = 0;
-                } while (i != putIndex);
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        if (o.equals(items[i])) {
+                            removeAt(i);
+                            return true;
+                        }
+                    if (to == end) break;
+                }
             }
             return false;
         } finally {
@@ -512,13 +544,14 @@
         try {
             if (count > 0) {
                 final Object[] items = this.items;
-                final int putIndex = this.putIndex;
-                int i = takeIndex;
-                do {
-                    if (o.equals(items[i]))
-                        return true;
-                    if (++i == items.length) i = 0;
-                } while (i != putIndex);
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        if (o.equals(items[i]))
+                            return true;
+                    if (to == end) break;
+                }
             }
             return false;
         } finally {
@@ -625,15 +658,9 @@
         final ReentrantLock lock = this.lock;
         lock.lock();
         try {
-            int k = count;
-            if (k > 0) {
-                final Object[] items = this.items;
-                final int putIndex = this.putIndex;
-                int i = takeIndex;
-                do {
-                    items[i] = null;
-                    if (++i == items.length) i = 0;
-                } while (i != putIndex);
+            int k;
+            if ((k = count) > 0) {
+                circularClear(items, takeIndex, putIndex);
                 takeIndex = putIndex;
                 count = 0;
                 if (itrs != null)
@@ -647,6 +674,18 @@
     }
 
     /**
+     * Nulls out slots starting at array index i, upto index end.
+     * If i == end, the entire array is cleared!
+     */
+    private static void circularClear(Object[] items, int i, int end) {
+        for (int to = (i < end) ? end : items.length;
+             ; i = 0, to = end) {
+            Arrays.fill(items, i, to, null);
+            if (to == end) break;
+        }
+    }
+
+    /**
      * @throws UnsupportedOperationException {@inheritDoc}
      * @throws ClassCastException            {@inheritDoc}
      * @throws NullPointerException          {@inheritDoc}
@@ -678,8 +717,8 @@
             try {
                 while (i < n) {
                     @SuppressWarnings("unchecked")
-                    E x = (E) items[take];
-                    c.add(x);
+                    E e = (E) items[take];
+                    c.add(e);
                     items[take] = null;
                     if (++take == items.length) take = 0;
                     i++;
@@ -808,7 +847,7 @@
          * there is known to be at least one iterator to collect
          */
         void doSomeSweeping(boolean tryHarder) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             // assert head != null;
             int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
             Node o, p;
@@ -864,7 +903,7 @@
          * Adds a new iterator to the linked list of tracked iterators.
          */
         void register(Itr itr) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             head = new Node(itr, head);
         }
 
@@ -874,7 +913,7 @@
          * Notifies all iterators, and expunges any that are now stale.
          */
         void takeIndexWrapped() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             cycles++;
             for (Node o = null, p = head; p != null;) {
                 final Itr it = p.get();
@@ -931,7 +970,7 @@
          * clears all weak refs, and unlinks the itrs datastructure.
          */
         void queueIsEmpty() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             for (Node p = head; p != null; p = p.next) {
                 Itr it = p.get();
                 if (it != null) {
@@ -947,7 +986,7 @@
          * Called whenever an element has been dequeued (at takeIndex).
          */
         void elementDequeued() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (count == 0)
                 queueIsEmpty();
             else if (takeIndex == 0)
@@ -1008,7 +1047,6 @@
         private static final int DETACHED = -3;
 
         Itr() {
-            // assert lock.getHoldCount() == 0;
             lastRet = NONE;
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
@@ -1041,12 +1079,12 @@
         }
 
         boolean isDetached() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             return prevTakeIndex < 0;
         }
 
         private int incCursor(int index) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (++index == items.length) index = 0;
             if (index == putIndex) index = NONE;
             return index;
@@ -1071,7 +1109,7 @@
          * operation on this iterator.  Call only from iterating thread.
          */
         private void incorporateDequeues() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             // assert itrs != null;
             // assert !isDetached();
             // assert count > 0;
@@ -1114,7 +1152,7 @@
          */
         private void detach() {
             // Switch to detached mode
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             // assert cursor == NONE;
             // assert nextIndex < 0;
             // assert lastRet < 0 || nextItem == null;
@@ -1134,7 +1172,6 @@
          * triggered by queue modifications.
          */
         public boolean hasNext() {
-            // assert lock.getHoldCount() == 0;
             if (nextItem != null)
                 return true;
             noNext();
@@ -1164,9 +1201,8 @@
         }
 
         public E next() {
-            // assert lock.getHoldCount() == 0;
-            final E x = nextItem;
-            if (x == null)
+            final E e = nextItem;
+            if (e == null)
                 throw new NoSuchElementException();
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
@@ -1188,13 +1224,43 @@
             } finally {
                 lock.unlock();
             }
-            return x;
+            return e;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                final E e = nextItem;
+                if (e == null) return;
+                if (!isDetached())
+                    incorporateDequeues();
+                action.accept(e);
+                if (isDetached() || cursor < 0) return;
+                final Object[] items = ArrayBlockingQueue.this.items;
+                for (int i = cursor, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(itemAt(items, i));
+                    if (to == end) break;
+                }
+            } finally {
+                // Calling forEachRemaining is a strong hint that this
+                // iteration is surely over; supporting remove() after
+                // forEachRemaining() is more trouble than it's worth
+                cursor = nextIndex = lastRet = NONE;
+                nextItem = lastItem = null;
+                detach();
+                lock.unlock();
+            }
         }
 
         public void remove() {
-            // assert lock.getHoldCount() == 0;
             final ReentrantLock lock = ArrayBlockingQueue.this.lock;
             lock.lock();
+            // assert lock.getHoldCount() == 1;
             try {
                 if (!isDetached())
                     incorporateDequeues(); // might update lastRet or detach
@@ -1232,7 +1298,7 @@
          * from next(), as promised by returning true from hasNext().
          */
         void shutdown() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             cursor = NONE;
             if (nextIndex >= 0)
                 nextIndex = REMOVED;
@@ -1260,7 +1326,7 @@
          * @return true if this iterator should be unlinked from itrs
          */
         boolean removedAt(int removedIndex) {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (isDetached())
                 return true;
 
@@ -1285,7 +1351,7 @@
                 }
                 else if (x > removedDistance) {
                     // assert cursor != prevTakeIndex;
-                    this.cursor = cursor = dec(cursor);
+                    this.cursor = cursor = dec(cursor, len);
                 }
             }
             int lastRet = this.lastRet;
@@ -1294,7 +1360,7 @@
                 if (x == removedDistance)
                     this.lastRet = lastRet = REMOVED;
                 else if (x > removedDistance)
-                    this.lastRet = lastRet = dec(lastRet);
+                    this.lastRet = lastRet = dec(lastRet, len);
             }
             int nextIndex = this.nextIndex;
             if (nextIndex >= 0) {
@@ -1302,7 +1368,7 @@
                 if (x == removedDistance)
                     this.nextIndex = nextIndex = REMOVED;
                 else if (x > removedDistance)
-                    this.nextIndex = nextIndex = dec(nextIndex);
+                    this.nextIndex = nextIndex = dec(nextIndex, len);
             }
             if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
                 this.prevTakeIndex = DETACHED;
@@ -1317,7 +1383,7 @@
          * @return true if this iterator should be unlinked from itrs
          */
         boolean takeIndexWrapped() {
-            // assert lock.getHoldCount() == 1;
+            // assert lock.isHeldByCurrentThread();
             if (isDetached())
                 return true;
             if (itrs.cycles - prevCycles > 1) {
@@ -1366,4 +1432,170 @@
                     Spliterator.CONCURRENT));
     }
 
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                for (int i = takeIndex, end = putIndex,
+                         to = (i < end) ? end : items.length;
+                     ; i = 0, to = end) {
+                    for (; i < to; i++)
+                        action.accept(itemAt(items, i));
+                    if (to == end) break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        return bulkRemove(filter);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
+    }
+
+    /** Implementation of bulk remove methods. */
+    private boolean bulkRemove(Predicate<? super E> filter) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (itrs == null) { // check for active iterators
+                if (count > 0) {
+                    final Object[] items = this.items;
+                    // Optimize for initial run of survivors
+                    for (int i = takeIndex, end = putIndex,
+                             to = (i < end) ? end : items.length;
+                         ; i = 0, to = end) {
+                        for (; i < to; i++)
+                            if (filter.test(itemAt(items, i)))
+                                return bulkRemoveModified(filter, i);
+                        if (to == end) break;
+                    }
+                }
+                return false;
+            }
+        } finally {
+            lock.unlock();
+        }
+        // Active iterators are too hairy!
+        // Punting (for now) to the slow n^2 algorithm ...
+        return super.removeIf(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    /**
+     * Returns circular distance from i to j, disambiguating i == j to
+     * items.length; never returns 0.
+     */
+    private int distanceNonEmpty(int i, int j) {
+        if ((j -= i) <= 0) j += items.length;
+        return j;
+    }
+
+    /**
+     * Helper for bulkRemove, in case of at least one deletion.
+     * Tolerate predicates that reentrantly access the collection for
+     * read (but not write), so traverse once to find elements to
+     * delete, a second pass to physically expunge.
+     *
+     * @param beg valid index of first element to be deleted
+     */
+    private boolean bulkRemoveModified(
+        Predicate<? super E> filter, final int beg) {
+        final Object[] es = items;
+        final int capacity = items.length;
+        final int end = putIndex;
+        final long[] deathRow = nBits(distanceNonEmpty(beg, putIndex));
+        deathRow[0] = 1L;   // set bit 0
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; i = 0, to = end, k -= capacity) {
+            for (; i < to; i++)
+                if (filter.test(itemAt(es, i)))
+                    setBit(deathRow, i - k);
+            if (to == end) break;
+        }
+        // a two-finger traversal, with hare i reading, tortoise w writing
+        int w = beg;
+        for (int i = beg + 1, to = (i <= end) ? end : es.length, k = beg;
+             ; w = 0) { // w rejoins i on second leg
+            // In this loop, i and w are on the same leg, with i > w
+            for (; i < to; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (to == end) break;
+            // In this loop, w is on the first leg, i on the second
+            for (i = 0, to = end, k -= capacity; i < to && w < capacity; i++)
+                if (isClear(deathRow, i - k))
+                    es[w++] = es[i];
+            if (i >= to) {
+                if (w == capacity) w = 0; // "corner" case
+                break;
+            }
+        }
+        count -= distanceNonEmpty(w, end);
+        circularClear(es, putIndex = w, end);
+        return true;
+    }
+
+    /** debugging */
+    void checkInvariants() {
+        // meta-assertions
+        // assert lock.isHeldByCurrentThread();
+        try {
+            // Unlike ArrayDeque, we have a count field but no spare slot.
+            // We prefer ArrayDeque's strategy (and the names of its fields!),
+            // but our field layout is baked into the serial form, and so is
+            // too annoying to change.
+            //
+            // putIndex == takeIndex must be disambiguated by checking count.
+            int capacity = items.length;
+            // assert capacity > 0;
+            // assert takeIndex >= 0 && takeIndex < capacity;
+            // assert putIndex >= 0 && putIndex < capacity;
+            // assert count <= capacity;
+            // assert takeIndex == putIndex || items[takeIndex] != null;
+            // assert count == capacity || items[putIndex] == null;
+            // assert takeIndex == putIndex || items[dec(putIndex, capacity)] != null;
+        } catch (Throwable t) {
+            System.err.printf("takeIndex=%d putIndex=%d count=%d capacity=%d%n",
+                              takeIndex, putIndex, count, items.length);
+            System.err.printf("items=%s%n",
+                              Arrays.toString(items));
+            throw t;
+        }
+    }
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CompletionStage.java	Thu Dec 01 21:39:49 2016 +0000
@@ -856,13 +856,9 @@
      * CompletableFuture, this method may return this stage itself.
      * Otherwise, invocation of this method may be equivalent in
      * effect to {@code thenApply(x -> x)}, but returning an instance
-     * of type {@code CompletableFuture}. A CompletionStage
-     * implementation that does not choose to interoperate with others
-     * may throw {@code UnsupportedOperationException}.
+     * of type {@code CompletableFuture}.
      *
      * @return the CompletableFuture
-     * @throws UnsupportedOperationException if this implementation
-     * does not interoperate with CompletableFuture
      */
     public CompletableFuture<T> toCompletableFuture();
 
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1650,7 +1650,24 @@
      * Removes all of the mappings from this map.
      */
     public void clear() {
-        initialize();
+        for (;;) {
+            Node<K,V> b, n;
+            HeadIndex<K,V> h = head, d = (HeadIndex<K,V>)h.down;
+            if (d != null)
+                casHead(h, d);            // remove levels
+            else if ((b = h.node) != null && (n = b.next) != null) {
+                Node<K,V> f = n.next;     // remove values
+                if (n == b.next) {
+                    Object v = n.value;
+                    if (v == null)
+                        n.helpDelete(b, f);
+                    else if (n.casValue(v, null) && n.appendMarker(f))
+                        b.casNext(n, f);
+                }
+            }
+            else
+                break;
+        }
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Thu Dec 01 21:39:49 2016 +0000
@@ -380,7 +380,7 @@
     // Positional Access Operations
 
     @SuppressWarnings("unchecked")
-    private E get(Object[] a, int index) {
+    static <E> E elementAt(Object[] a, int index) {
         return (E) a[index];
     }
 
@@ -394,7 +394,7 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public E get(int index) {
-        return get(getArray(), index);
+        return elementAt(getArray(), index);
     }
 
     /**
@@ -406,7 +406,7 @@
     public E set(int index, E element) {
         synchronized (lock) {
             Object[] elements = getArray();
-            E oldValue = get(elements, index);
+            E oldValue = elementAt(elements, index);
 
             if (oldValue != element) {
                 int len = elements.length;
@@ -477,7 +477,7 @@
         synchronized (lock) {
             Object[] elements = getArray();
             int len = elements.length;
-            E oldValue = get(elements, index);
+            E oldValue = elementAt(elements, index);
             int numMoved = len - index - 1;
             if (numMoved == 0)
                 setArray(Arrays.copyOf(elements, len - 1));
@@ -644,34 +644,16 @@
      * @return {@code true} if this list changed as a result of the call
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this list contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
+     * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
     public boolean removeAll(Collection<?> c) {
-        if (c == null) throw new NullPointerException();
-        synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            if (len != 0) {
-                // temp array holds those elements we know we want to keep
-                int newlen = 0;
-                Object[] temp = new Object[len];
-                for (int i = 0; i < len; ++i) {
-                    Object element = elements[i];
-                    if (!c.contains(element))
-                        temp[newlen++] = element;
-                }
-                if (newlen != len) {
-                    setArray(Arrays.copyOf(temp, newlen));
-                    return true;
-                }
-            }
-            return false;
-        }
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> c.contains(e));
     }
 
     /**
@@ -683,34 +665,16 @@
      * @return {@code true} if this list changed as a result of the call
      * @throws ClassCastException if the class of an element of this list
      *         is incompatible with the specified collection
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
+     * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>)
      * @throws NullPointerException if this list contains a null element and the
      *         specified collection does not permit null elements
-     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
+     * (<a href="{@docRoot}/java/util/Collection.html#optional-restrictions">optional</a>),
      *         or if the specified collection is null
      * @see #remove(Object)
      */
     public boolean retainAll(Collection<?> c) {
-        if (c == null) throw new NullPointerException();
-        synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            if (len != 0) {
-                // temp array holds those elements we know we want to keep
-                int newlen = 0;
-                Object[] temp = new Object[len];
-                for (int i = 0; i < len; ++i) {
-                    Object element = elements[i];
-                    if (c.contains(element))
-                        temp[newlen++] = element;
-                }
-                if (newlen != len) {
-                    setArray(Arrays.copyOf(temp, newlen));
-                    return true;
-                }
-            }
-            return false;
-        }
+        Objects.requireNonNull(c);
+        return bulkRemove(e -> !c.contains(e));
     }
 
     /**
@@ -839,55 +803,90 @@
 
     public boolean removeIf(Predicate<? super E> filter) {
         if (filter == null) throw new NullPointerException();
+        return bulkRemove(filter);
+    }
+
+    // A tiny bit set implementation
+
+    private static long[] nBits(int n) {
+        return new long[((n - 1) >> 6) + 1];
+    }
+    private static void setBit(long[] bits, int i) {
+        bits[i >> 6] |= 1L << i;
+    }
+    private static boolean isClear(long[] bits, int i) {
+        return (bits[i >> 6] & (1L << i)) == 0;
+    }
+
+    private boolean bulkRemove(Predicate<? super E> filter) {
         synchronized (lock) {
-            final Object[] elements = getArray();
-            final int len = elements.length;
-            int i;
-            for (i = 0; i < len; i++) {
-                @SuppressWarnings("unchecked") E e = (E) elements[i];
-                if (filter.test(e)) {
-                    int newlen = i;
-                    final Object[] newElements = new Object[len - 1];
-                    System.arraycopy(elements, 0, newElements, 0, newlen);
-                    for (i++; i < len; i++) {
-                        @SuppressWarnings("unchecked") E x = (E) elements[i];
-                        if (!filter.test(x))
-                            newElements[newlen++] = x;
-                    }
-                    setArray((newlen == len - 1)
-                             ? newElements // one match => one copy
-                             : Arrays.copyOf(newElements, newlen));
-                    return true;
+            return bulkRemove(filter, 0, getArray().length);
+        }
+    }
+
+    boolean bulkRemove(Predicate<? super E> filter, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray();
+        // Optimize for initial run of survivors
+        for (; i < end && !filter.test(elementAt(es, i)); i++)
+            ;
+        if (i < end) {
+            final int beg = i;
+            final long[] deathRow = nBits(end - beg);
+            int deleted = 1;
+            deathRow[0] = 1L;   // set bit 0
+            for (i = beg + 1; i < end; i++)
+                if (filter.test(elementAt(es, i))) {
+                    setBit(deathRow, i - beg);
+                    deleted++;
                 }
-            }
-            return false;       // zero matches => zero copies
+            // Did filter reentrantly modify the list?
+            if (es != getArray())
+                throw new ConcurrentModificationException();
+            final Object[] newElts = Arrays.copyOf(es, es.length - deleted);
+            int w = beg;
+            for (i = beg; i < end; i++)
+                if (isClear(deathRow, i - beg))
+                    newElts[w++] = es[i];
+            System.arraycopy(es, i, newElts, w, es.length - i);
+            setArray(newElts);
+            return true;
+        } else {
+            if (es != getArray())
+                throw new ConcurrentModificationException();
+            return false;
         }
     }
 
     public void replaceAll(UnaryOperator<E> operator) {
         if (operator == null) throw new NullPointerException();
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            Object[] newElements = Arrays.copyOf(elements, len);
-            for (int i = 0; i < len; ++i) {
-                @SuppressWarnings("unchecked") E e = (E) elements[i];
-                newElements[i] = operator.apply(e);
-            }
-            setArray(newElements);
+            replaceAll(operator, 0, getArray().length);
         }
     }
 
+    void replaceAll(UnaryOperator<E> operator, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray().clone();
+        for (; i < end; i++)
+            es[i] = operator.apply(elementAt(es, i));
+        setArray(es);
+    }
+
     public void sort(Comparator<? super E> c) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            Object[] newElements = Arrays.copyOf(elements, elements.length);
-            @SuppressWarnings("unchecked") E[] es = (E[])newElements;
-            Arrays.sort(es, c);
-            setArray(newElements);
+            sort(c, 0, getArray().length);
         }
     }
 
+    @SuppressWarnings("unchecked")
+    void sort(Comparator<? super E> c, int i, int end) {
+        // assert Thread.holdsLock(lock);
+        final Object[] es = getArray().clone();
+        Arrays.sort(es, i, end, (Comparator<Object>)c);
+        setArray(es);
+    }
+
     /**
      * Saves this list to a stream (that is, serializes it).
      *
@@ -1167,18 +1166,6 @@
 
     /**
      * Sublist for CopyOnWriteArrayList.
-     * This class extends AbstractList merely for convenience, to
-     * avoid having to define addAll, etc. This doesn't hurt, but
-     * is wasteful.  This class does not need or use modCount
-     * mechanics in AbstractList, but does need to check for
-     * concurrent modification using similar mechanics.  On each
-     * operation, the array that we expect the backing list to use
-     * is checked and updated.  Since we do this for all of the
-     * base operations invoked by those defined in AbstractList,
-     * all is well.  While inefficient, this is not worth
-     * improving.  The kinds of list operations inherited from
-     * AbstractList are already so slow on COW sublists that
-     * adding a bit more space/time doesn't seem even noticeable.
      */
     private static class COWSubList<E>
         extends AbstractList<E>
@@ -1206,6 +1193,14 @@
                 throw new ConcurrentModificationException();
         }
 
+        private Object[] getArrayChecked() {
+            // assert Thread.holdsLock(l.lock);
+            Object[] a = l.getArray();
+            if (a != expectedArray)
+                throw new ConcurrentModificationException();
+            return a;
+        }
+
         // only call this holding l's lock
         private void rangeCheck(int index) {
             // assert Thread.holdsLock(l.lock);
@@ -1217,7 +1212,7 @@
             synchronized (l.lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E x = l.set(index+offset, element);
+                E x = l.set(offset + index, element);
                 expectedArray = l.getArray();
                 return x;
             }
@@ -1227,7 +1222,7 @@
             synchronized (l.lock) {
                 rangeCheck(index);
                 checkForComodification();
-                return l.get(index+offset);
+                return l.get(offset + index);
             }
         }
 
@@ -1238,22 +1233,41 @@
             }
         }
 
+        public boolean add(E element) {
+            synchronized (l.lock) {
+                checkForComodification();
+                l.add(offset + size, element);
+                expectedArray = l.getArray();
+                size++;
+            }
+            return true;
+        }
+
         public void add(int index, E element) {
             synchronized (l.lock) {
                 checkForComodification();
                 if (index < 0 || index > size)
                     throw new IndexOutOfBoundsException
                         (outOfBounds(index, size));
-                l.add(index+offset, element);
+                l.add(offset + index, element);
                 expectedArray = l.getArray();
                 size++;
             }
         }
 
+        public boolean addAll(Collection<? extends E> c) {
+            synchronized (l.lock) {
+                final Object[] oldArray = getArrayChecked();
+                boolean modified = l.addAll(offset + size, c);
+                size += (expectedArray = l.getArray()).length - oldArray.length;
+                return modified;
+            }
+        }
+
         public void clear() {
             synchronized (l.lock) {
                 checkForComodification();
-                l.removeRange(offset, offset+size);
+                l.removeRange(offset, offset + size);
                 expectedArray = l.getArray();
                 size = 0;
             }
@@ -1263,7 +1277,7 @@
             synchronized (l.lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E result = l.remove(index+offset);
+                E result = l.remove(offset + index);
                 expectedArray = l.getArray();
                 size--;
                 return result;
@@ -1271,11 +1285,14 @@
         }
 
         public boolean remove(Object o) {
-            int index = indexOf(o);
-            if (index == -1)
-                return false;
-            remove(index);
-            return true;
+            synchronized (l.lock) {
+                checkForComodification();
+                int index = indexOf(o);
+                if (index == -1)
+                    return false;
+                remove(index);
+                return true;
+            }
         }
 
         public Iterator<E> iterator() {
@@ -1307,174 +1324,63 @@
 
         public void forEach(Consumer<? super E> action) {
             if (action == null) throw new NullPointerException();
-            int lo = offset;
-            int hi = offset + size;
-            Object[] a = expectedArray;
-            if (l.getArray() != a)
-                throw new ConcurrentModificationException();
-            if (lo < 0 || hi > a.length)
-                throw new IndexOutOfBoundsException();
-            for (int i = lo; i < hi; ++i) {
-                @SuppressWarnings("unchecked") E e = (E) a[i];
-                action.accept(e);
+            int i, end; final Object[] es;
+            synchronized (l.lock) {
+                es = getArrayChecked();
+                i = offset;
+                end = i + size;
             }
+            for (; i < end; i++)
+                action.accept(elementAt(es, i));
         }
 
         public void replaceAll(UnaryOperator<E> operator) {
             if (operator == null) throw new NullPointerException();
             synchronized (l.lock) {
-                int lo = offset;
-                int hi = offset + size;
-                Object[] elements = expectedArray;
-                if (l.getArray() != elements)
-                    throw new ConcurrentModificationException();
-                int len = elements.length;
-                if (lo < 0 || hi > len)
-                    throw new IndexOutOfBoundsException();
-                Object[] newElements = Arrays.copyOf(elements, len);
-                for (int i = lo; i < hi; ++i) {
-                    @SuppressWarnings("unchecked") E e = (E) elements[i];
-                    newElements[i] = operator.apply(e);
-                }
-                l.setArray(expectedArray = newElements);
+                checkForComodification();
+                l.replaceAll(operator, offset, offset + size);
+                expectedArray = l.getArray();
             }
         }
 
         public void sort(Comparator<? super E> c) {
             synchronized (l.lock) {
-                int lo = offset;
-                int hi = offset + size;
-                Object[] elements = expectedArray;
-                if (l.getArray() != elements)
-                    throw new ConcurrentModificationException();
-                int len = elements.length;
-                if (lo < 0 || hi > len)
-                    throw new IndexOutOfBoundsException();
-                Object[] newElements = Arrays.copyOf(elements, len);
-                @SuppressWarnings("unchecked") E[] es = (E[])newElements;
-                Arrays.sort(es, lo, hi, c);
-                l.setArray(expectedArray = newElements);
+                checkForComodification();
+                l.sort(c, offset, offset + size);
+                expectedArray = l.getArray();
             }
         }
 
         public boolean removeAll(Collection<?> c) {
-            if (c == null) throw new NullPointerException();
-            boolean removed = false;
-            synchronized (l.lock) {
-                int n = size;
-                if (n > 0) {
-                    int lo = offset;
-                    int hi = offset + n;
-                    Object[] elements = expectedArray;
-                    if (l.getArray() != elements)
-                        throw new ConcurrentModificationException();
-                    int len = elements.length;
-                    if (lo < 0 || hi > len)
-                        throw new IndexOutOfBoundsException();
-                    int newSize = 0;
-                    Object[] temp = new Object[n];
-                    for (int i = lo; i < hi; ++i) {
-                        Object element = elements[i];
-                        if (!c.contains(element))
-                            temp[newSize++] = element;
-                    }
-                    if (newSize != n) {
-                        Object[] newElements = new Object[len - n + newSize];
-                        System.arraycopy(elements, 0, newElements, 0, lo);
-                        System.arraycopy(temp, 0, newElements, lo, newSize);
-                        System.arraycopy(elements, hi, newElements,
-                                         lo + newSize, len - hi);
-                        size = newSize;
-                        removed = true;
-                        l.setArray(expectedArray = newElements);
-                    }
-                }
-            }
-            return removed;
+            Objects.requireNonNull(c);
+            return bulkRemove(e -> c.contains(e));
         }
 
         public boolean retainAll(Collection<?> c) {
-            if (c == null) throw new NullPointerException();
-            boolean removed = false;
-            synchronized (l.lock) {
-                int n = size;
-                if (n > 0) {
-                    int lo = offset;
-                    int hi = offset + n;
-                    Object[] elements = expectedArray;
-                    if (l.getArray() != elements)
-                        throw new ConcurrentModificationException();
-                    int len = elements.length;
-                    if (lo < 0 || hi > len)
-                        throw new IndexOutOfBoundsException();
-                    int newSize = 0;
-                    Object[] temp = new Object[n];
-                    for (int i = lo; i < hi; ++i) {
-                        Object element = elements[i];
-                        if (c.contains(element))
-                            temp[newSize++] = element;
-                    }
-                    if (newSize != n) {
-                        Object[] newElements = new Object[len - n + newSize];
-                        System.arraycopy(elements, 0, newElements, 0, lo);
-                        System.arraycopy(temp, 0, newElements, lo, newSize);
-                        System.arraycopy(elements, hi, newElements,
-                                         lo + newSize, len - hi);
-                        size = newSize;
-                        removed = true;
-                        l.setArray(expectedArray = newElements);
-                    }
-                }
-            }
-            return removed;
+            Objects.requireNonNull(c);
+            return bulkRemove(e -> !c.contains(e));
         }
 
         public boolean removeIf(Predicate<? super E> filter) {
-            if (filter == null) throw new NullPointerException();
-            boolean removed = false;
+            Objects.requireNonNull(filter);
+            return bulkRemove(filter);
+        }
+
+        private boolean bulkRemove(Predicate<? super E> filter) {
             synchronized (l.lock) {
-                int n = size;
-                if (n > 0) {
-                    int lo = offset;
-                    int hi = offset + n;
-                    Object[] elements = expectedArray;
-                    if (l.getArray() != elements)
-                        throw new ConcurrentModificationException();
-                    int len = elements.length;
-                    if (lo < 0 || hi > len)
-                        throw new IndexOutOfBoundsException();
-                    int newSize = 0;
-                    Object[] temp = new Object[n];
-                    for (int i = lo; i < hi; ++i) {
-                        @SuppressWarnings("unchecked") E e = (E) elements[i];
-                        if (!filter.test(e))
-                            temp[newSize++] = e;
-                    }
-                    if (newSize != n) {
-                        Object[] newElements = new Object[len - n + newSize];
-                        System.arraycopy(elements, 0, newElements, 0, lo);
-                        System.arraycopy(temp, 0, newElements, lo, newSize);
-                        System.arraycopy(elements, hi, newElements,
-                                         lo + newSize, len - hi);
-                        size = newSize;
-                        removed = true;
-                        l.setArray(expectedArray = newElements);
-                    }
-                }
+                final Object[] oldArray = getArrayChecked();
+                boolean modified = l.bulkRemove(filter, offset, offset + size);
+                size += (expectedArray = l.getArray()).length - oldArray.length;
+                return modified;
             }
-            return removed;
         }
 
         public Spliterator<E> spliterator() {
-            int lo = offset;
-            int hi = offset + size;
-            Object[] a = expectedArray;
-            if (l.getArray() != a)
-                throw new ConcurrentModificationException();
-            if (lo < 0 || hi > a.length)
-                throw new IndexOutOfBoundsException();
-            return Spliterators.spliterator
-                (a, lo, hi, Spliterator.IMMUTABLE | Spliterator.ORDERED);
+            synchronized (l.lock) {
+                return Spliterators.spliterator(
+                        getArrayChecked(), offset, offset + size,
+                        Spliterator.IMMUTABLE | Spliterator.ORDERED);
+            }
         }
 
     }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CyclicBarrier.java	Thu Dec 01 21:39:49 2016 +0000
@@ -82,8 +82,7 @@
  *   public Solver(float[][] matrix) {
  *     data = matrix;
  *     N = matrix.length;
- *     Runnable barrierAction =
- *       new Runnable() { public void run() { mergeRows(...); }};
+ *     Runnable barrierAction = () -> mergeRows(...);
  *     barrier = new CyclicBarrier(N, barrierAction);
  *
  *     List<Thread> threads = new ArrayList<>(N);
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Executor.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Executor.java	Thu Dec 01 21:39:49 2016 +0000
@@ -87,14 +87,12 @@
  *     this.executor = executor;
  *   }
  *
- *   public synchronized void execute(final Runnable r) {
- *     tasks.add(new Runnable() {
- *       public void run() {
- *         try {
- *           r.run();
- *         } finally {
- *           scheduleNext();
- *         }
+ *   public synchronized void execute(Runnable r) {
+ *     tasks.add(() -> {
+ *       try {
+ *         r.run();
+ *       } finally {
+ *         scheduleNext();
  *       }
  *     });
  *     if (active == null) {
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java	Thu Dec 01 21:39:49 2016 +0000
@@ -80,7 +80,7 @@
  *   List<Future<Result>> futures = new ArrayList<>(n);
  *   Result result = null;
  *   try {
- *     solvers.forEach((solver) -> futures.add(cs.submit(solver)));
+ *     solvers.forEach(solver -> futures.add(cs.submit(solver)));
  *     for (int i = n; i > 0; i--) {
  *       try {
  *         Result r = cs.take().get();
@@ -91,7 +91,7 @@
  *       } catch (ExecutionException ignore) {}
  *     }
  *   } finally {
- *     futures.forEach((future) -> future.cancel(true));
+ *     futures.forEach(future -> future.cancel(true));
  *   }
  *
  *   if (result != null)
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Executors.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Executors.java	Thu Dec 01 21:39:49 2016 +0000
@@ -650,7 +650,7 @@
         public Thread newThread(final Runnable r) {
             return super.newThread(new Runnable() {
                 public void run() {
-                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                    AccessController.doPrivileged(new PrivilegedAction<>() {
                         public Void run() {
                             Thread.currentThread().setContextClassLoader(ccl);
                             r.run();
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Thu Dec 01 21:39:49 2016 +0000
@@ -38,8 +38,10 @@
 import java.lang.Thread.UncaughtExceptionHandler;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
+import java.security.AccessController;
 import java.security.AccessControlContext;
 import java.security.Permissions;
+import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -64,7 +66,8 @@
  * tasks are submitted to the pool from external clients.  Especially
  * when setting <em>asyncMode</em> to true in constructors, {@code
  * ForkJoinPool}s may also be appropriate for use with event-style
- * tasks that are never joined.
+ * tasks that are never joined. All worker threads are initialized
+ * with {@link Thread#isDaemon} set {@code true}.
  *
  * <p>A static {@link #commonPool()} is available and appropriate for
  * most applications. The common pool is used by any ForkJoinTask that
@@ -3224,10 +3227,9 @@
             new DefaultForkJoinWorkerThreadFactory();
         modifyThreadPermission = new RuntimePermission("modifyThread");
 
-        common = java.security.AccessController.doPrivileged
-            (new java.security.PrivilegedAction<ForkJoinPool>() {
-                    public ForkJoinPool run() {
-                        return new ForkJoinPool((byte)0); }});
+        common = AccessController.doPrivileged(new PrivilegedAction<>() {
+            public ForkJoinPool run() {
+                return new ForkJoinPool((byte)0); }});
 
         COMMON_PARALLELISM = Math.max(common.mode & SMASK, 1);
     }
@@ -3256,12 +3258,11 @@
         }
 
         public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
-            return java.security.AccessController.doPrivileged(
-                new java.security.PrivilegedAction<ForkJoinWorkerThread>() {
-                    public ForkJoinWorkerThread run() {
-                        return new ForkJoinWorkerThread.
-                            InnocuousForkJoinWorkerThread(pool);
-                    }}, INNOCUOUS_ACC);
+            return AccessController.doPrivileged(new PrivilegedAction<>() {
+                public ForkJoinWorkerThread run() {
+                    return new ForkJoinWorkerThread.
+                        InnocuousForkJoinWorkerThread(pool);
+                }}, INNOCUOUS_ACC);
         }
     }
 
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Thu Dec 01 21:39:49 2016 +0000
@@ -419,7 +419,7 @@
 
     /** Reference queue of stale exceptionally completed tasks. */
     private static final ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue
-        = new ReferenceQueue<ForkJoinTask<?>>();
+        = new ReferenceQueue<>();
 
     /**
      * Key-value nodes for exception table.  The chained hash table
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Future.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Future.java	Thu Dec 01 21:39:49 2016 +0000
@@ -50,8 +50,7 @@
  * declare types of the form {@code Future<?>} and
  * return {@code null} as a result of the underlying task.
  *
- * <p>
- * <b>Sample Usage</b> (Note that the following classes are all
+ * <p><b>Sample Usage</b> (Note that the following classes are all
  * made-up.)
  *
  * <pre> {@code
@@ -59,13 +58,9 @@
  * class App {
  *   ExecutorService executor = ...
  *   ArchiveSearcher searcher = ...
- *   void showSearch(final String target)
- *       throws InterruptedException {
- *     Future<String> future
- *       = executor.submit(new Callable<String>() {
- *         public String call() {
- *             return searcher.search(target);
- *         }});
+ *   void showSearch(String target) throws InterruptedException {
+ *     Callable<String> task = () -> searcher.search(target);
+ *     Future<String> future = executor.submit(task);
  *     displayOtherThings(); // do other things while searching
  *     try {
  *       displayText(future.get()); // use future
@@ -77,11 +72,7 @@
  * implements {@code Runnable}, and so may be executed by an {@code Executor}.
  * For example, the above construction with {@code submit} could be replaced by:
  * <pre> {@code
- * FutureTask<String> future =
- *   new FutureTask<>(new Callable<String>() {
- *     public String call() {
- *       return searcher.search(target);
- *   }});
+ * FutureTask<String> future = new FutureTask<>(task);
  * executor.execute(future);}</pre>
  *
  * <p>Memory consistency effects: Actions taken by the asynchronous computation
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedBlockingDeque.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1127,40 +1127,35 @@
     }
 
     /** A customized variant of Spliterators.IteratorSpliterator */
-    static final class LBDSpliterator<E> implements Spliterator<E> {
+    private final class LBDSpliterator implements Spliterator<E> {
         static final int MAX_BATCH = 1 << 25;  // max batch array size;
-        final LinkedBlockingDeque<E> queue;
         Node<E> current;    // current node; null until initialized
         int batch;          // batch size for splits
         boolean exhausted;  // true when no more nodes
         long est;           // size estimate
-        LBDSpliterator(LinkedBlockingDeque<E> queue) {
-            this.queue = queue;
-            this.est = queue.size();
-        }
+
+        LBDSpliterator() { est = size(); }
 
         public long estimateSize() { return est; }
 
         public Spliterator<E> trySplit() {
             Node<E> h;
-            final LinkedBlockingDeque<E> q = this.queue;
             int b = batch;
             int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
             if (!exhausted &&
-                ((h = current) != null || (h = q.first) != null) &&
-                h.next != null) {
+                (((h = current) != null && h != h.next)
+                 || (h = first) != null)
+                && h.next != null) {
                 Object[] a = new Object[n];
-                final ReentrantLock lock = q.lock;
+                final ReentrantLock lock = LinkedBlockingDeque.this.lock;
                 int i = 0;
                 Node<E> p = current;
                 lock.lock();
                 try {
-                    if (p != null || (p = q.first) != null) {
-                        do {
-                            if ((a[i] = p.item) != null)
-                                ++i;
-                        } while ((p = p.next) != null && i < n);
-                    }
+                    if (((p != null && p != p.next) || (p = first) != null)
+                        && p.item != null)
+                        for (; p != null && i < n; p = p.next)
+                            a[i++] = p.item;
                 } finally {
                     lock.unlock();
                 }
@@ -1183,64 +1178,55 @@
 
         public void forEachRemaining(Consumer<? super E> action) {
             if (action == null) throw new NullPointerException();
-            final LinkedBlockingDeque<E> q = this.queue;
-            final ReentrantLock lock = q.lock;
-            if (!exhausted) {
-                exhausted = true;
-                Node<E> p = current;
-                do {
-                    E e = null;
-                    lock.lock();
-                    try {
-                        if (p == null)
-                            p = q.first;
-                        while (p != null) {
-                            e = p.item;
-                            p = p.next;
-                            if (e != null)
-                                break;
-                        }
-                    } finally {
-                        lock.unlock();
+            if (exhausted)
+                return;
+            exhausted = true;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            Node<E> p = current;
+            current = null;
+            do {
+                E e = null;
+                lock.lock();
+                try {
+                    if ((p != null && p != p.next) || (p = first) != null) {
+                        e = p.item;
+                        p = p.next;
                     }
-                    if (e != null)
-                        action.accept(e);
-                } while (p != null);
-            }
+                } finally {
+                    lock.unlock();
+                }
+                if (e != null)
+                    action.accept(e);
+            } while (p != null);
         }
 
         public boolean tryAdvance(Consumer<? super E> action) {
             if (action == null) throw new NullPointerException();
-            final LinkedBlockingDeque<E> q = this.queue;
-            final ReentrantLock lock = q.lock;
-            if (!exhausted) {
-                E e = null;
-                lock.lock();
-                try {
-                    if (current == null)
-                        current = q.first;
-                    while (current != null) {
-                        e = current.item;
-                        current = current.next;
-                        if (e != null)
-                            break;
-                    }
-                } finally {
-                    lock.unlock();
+            if (exhausted)
+                return false;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            Node<E> p = current;
+            E e = null;
+            lock.lock();
+            try {
+                if ((p != null && p != p.next) || (p = first) != null) {
+                    e = p.item;
+                    p = p.next;
                 }
-                if (current == null)
-                    exhausted = true;
-                if (e != null) {
-                    action.accept(e);
-                    return true;
-                }
+            } finally {
+                lock.unlock();
             }
-            return false;
+            exhausted = ((current = p) == null);
+            if (e == null)
+                return false;
+            action.accept(e);
+            return true;
         }
 
         public int characteristics() {
-            return Spliterator.ORDERED | Spliterator.NONNULL |
-                Spliterator.CONCURRENT;
+            return (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT);
         }
     }
 
@@ -1261,7 +1247,7 @@
      * @since 1.8
      */
     public Spliterator<E> spliterator() {
-        return new LBDSpliterator<E>(this);
+        return new LBDSpliterator();
     }
 
     /**
@@ -1312,4 +1298,14 @@
         }
     }
 
+    void checkInvariants() {
+        // assert lock.isHeldByCurrentThread();
+        // Nodes may get self-linked or lose their item, but only
+        // after being unlinked and becoming unreachable from first.
+        for (Node<E> p = first; p != null; p = p.next) {
+            // assert p.next != p;
+            // assert p.item != null;
+        }
+    }
+
 }
--- a/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java	Thu Dec 01 21:39:49 2016 +0000
@@ -95,8 +95,8 @@
      * *** Overview of Dual Queues with Slack ***
      *
      * Dual Queues, introduced by Scherer and Scott
-     * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are
-     * (linked) queues in which nodes may represent either data or
+     * (http://www.cs.rochester.edu/~scott/papers/2004_DISC_dual_DS.pdf)
+     * are (linked) queues in which nodes may represent either data or
      * requests.  When a thread tries to enqueue a data node, but
      * encounters a request node, it instead "matches" and removes it;
      * and vice versa for enqueuing requests. Blocking Dual Queues
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Phaser.java	Thu Dec 01 21:39:49 2016 +0000
@@ -154,49 +154,46 @@
  * <p>A {@code Phaser} may be used instead of a {@code CountDownLatch}
  * to control a one-shot action serving a variable number of parties.
  * The typical idiom is for the method setting this up to first
- * register, then start the actions, then deregister, as in:
+ * register, then start all the actions, then deregister, as in:
  *
  * <pre> {@code
  * void runTasks(List<Runnable> tasks) {
- *   final Phaser phaser = new Phaser(1); // "1" to register self
+ *   Phaser startingGate = new Phaser(1); // "1" to register self
  *   // create and start threads
- *   for (final Runnable task : tasks) {
- *     phaser.register();
- *     new Thread() {
- *       public void run() {
- *         phaser.arriveAndAwaitAdvance(); // await all creation
- *         task.run();
- *       }
- *     }.start();
+ *   for (Runnable task : tasks) {
+ *     startingGate.register();
+ *     new Thread(() -> {
+ *       startingGate.arriveAndAwaitAdvance();
+ *       task.run();
+ *     }).start();
  *   }
  *
- *   // allow threads to start and deregister self
- *   phaser.arriveAndDeregister();
+ *   // deregister self to allow threads to proceed
+ *   startingGate.arriveAndDeregister();
  * }}</pre>
  *
  * <p>One way to cause a set of threads to repeatedly perform actions
  * for a given number of iterations is to override {@code onAdvance}:
  *
  * <pre> {@code
- * void startTasks(List<Runnable> tasks, final int iterations) {
- *   final Phaser phaser = new Phaser() {
+ * void startTasks(List<Runnable> tasks, int iterations) {
+ *   Phaser phaser = new Phaser() {
  *     protected boolean onAdvance(int phase, int registeredParties) {
  *       return phase >= iterations || registeredParties == 0;
  *     }
  *   };
  *   phaser.register();
- *   for (final Runnable task : tasks) {
+ *   for (Runnable task : tasks) {
  *     phaser.register();
- *     new Thread() {
- *       public void run() {
- *         do {
- *           task.run();
- *           phaser.arriveAndAwaitAdvance();
- *         } while (!phaser.isTerminated());
- *       }
- *     }.start();
+ *     new Thread(() -> {
+ *       do {
+ *         task.run();
+ *         phaser.arriveAndAwaitAdvance();
+ *       } while (!phaser.isTerminated());
+ *     }).start();
  *   }
- *   phaser.arriveAndDeregister(); // deregister self, don't wait
+ *   // allow threads to proceed; don't wait for them
+ *   phaser.arriveAndDeregister();
  * }}</pre>
  *
  * If the main task must later await termination, it
--- a/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Thu Dec 01 21:39:49 2016 +0000
@@ -933,8 +933,9 @@
         }
     }
 
-    // Similar to Collections.ArraySnapshotSpliterator but avoids
-    // commitment to toArray until needed
+    /**
+     * Immutable snapshot spliterator that binds to elements "late".
+     */
     static final class PBQSpliterator<E> implements Spliterator<E> {
         final PriorityBlockingQueue<E> queue;
         Object[] array;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledExecutorService.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ScheduledExecutorService.java	Thu Dec 01 21:39:49 2016 +0000
@@ -77,14 +77,11 @@
  *     Executors.newScheduledThreadPool(1);
  *
  *   public void beepForAnHour() {
- *     final Runnable beeper = new Runnable() {
- *       public void run() { System.out.println("beep"); }
- *     };
- *     final ScheduledFuture<?> beeperHandle =
+ *     Runnable beeper = () -> System.out.println("beep");
+ *     ScheduledFuture<?> beeperHandle =
  *       scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
- *     scheduler.schedule(new Runnable() {
- *       public void run() { beeperHandle.cancel(true); }
- *     }, 60 * 60, SECONDS);
+ *     Runnable canceller = () -> beeperHandle.cancel(true);
+ *     scheduler.schedule(canceller, 1, HOURS);
  *   }
  * }}</pre>
  *
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Semaphore.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Semaphore.java	Thu Dec 01 21:39:49 2016 +0000
@@ -631,9 +631,12 @@
     }
 
     /**
-     * Acquires and returns all permits that are immediately available.
+     * Acquires and returns all permits that are immediately
+     * available, or if negative permits are available, releases them.
+     * Upon return, zero permits are available.
      *
-     * @return the number of permits acquired
+     * @return the number of permits acquired or, if negative, the
+     * number released
      */
     public int drainPermits() {
         return sync.drainPermits();
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Thu Dec 01 21:39:49 2016 +0000
@@ -197,9 +197,17 @@
         return r;
     }
 
-    // We must define this, but never use it.
+    /**
+     * Generates a pseudorandom number with the indicated number of
+     * low-order bits.  Because this class has no subclasses, this
+     * method cannot be invoked or overridden.
+     *
+     * @param  bits random bits
+     * @return the next pseudorandom value from this random number
+     *         generator's sequence
+     */
     protected int next(int bits) {
-        return (int)(mix64(nextSeed()) >>> (64 - bits));
+        return nextInt() >>> (32 - bits);
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Thu Dec 01 21:39:49 2016 +0000
@@ -60,6 +60,10 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
@@ -105,8 +109,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean compareAndSet(T obj, int expect, int update);
 
@@ -125,8 +127,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean weakCompareAndSet(T obj, int expect, int update);
 
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Thu Dec 01 21:39:49 2016 +0000
@@ -60,6 +60,10 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
@@ -108,8 +112,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean compareAndSet(T obj, long expect, long update);
 
@@ -128,8 +130,6 @@
      * @param expect the expected value
      * @param update the new value
      * @return {@code true} if successful
-     * @throws ClassCastException if {@code obj} is not an instance
-     * of the class possessing the field established in the constructor
      */
     public abstract boolean weakCompareAndSet(T obj, long expect, long update);
 
@@ -510,8 +510,8 @@
 
         LockedUpdater(final Class<T> tclass, final String fieldName,
                       final Class<?> caller) {
-            Field field = null;
-            int modifiers = 0;
+            final Field field;
+            final int modifiers;
             try {
                 field = AccessController.doPrivileged(
                     new PrivilegedExceptionAction<Field>() {
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Thu Dec 01 21:39:49 2016 +0000
@@ -77,6 +77,10 @@
  * guarantee atomicity only with respect to other invocations of
  * {@code compareAndSet} and {@code set} on the same updater.
  *
+ * <p>Object arguments for parameters of type {@code T} that are not
+ * instances of the class passed to {@link #newUpdater} will result in
+ * a {@link ClassCastException} being thrown.
+ *
  * @since 1.5
  * @author Doug Lea
  * @param <T> The type of the object holding the updatable field
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/package-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/package-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -60,21 +60,9 @@
  *   }
  * }}</pre>
  *
- * <p>It is straightforward to define new utility functions that, like
- * {@code getAndIncrement}, apply a function to a value atomically.
- * For example, given some transformation
- * <pre> {@code long transform(long input)}</pre>
- *
- * write your utility method as follows:
- * <pre> {@code
- * long getAndTransform(AtomicLong var) {
- *   long prev, next;
- *   do {
- *     prev = var.get();
- *     next = transform(prev);
- *   } while (!var.compareAndSet(prev, next));
- *   return prev; // return next; for transformAndGet
- * }}</pre>
+ * <p>Arbitrary transformations of the contained value are provided both
+ * by low-level read-modify-write operations such as {@code compareAndSet}
+ * and by higher-level methods such as {@code getAndUpdate}.
  *
  * <p>These classes are not general purpose replacements for {@code
  * java.lang.Integer} and related classes.  They do <em>not</em>
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Thu Dec 01 21:39:49 2016 +0000
@@ -572,7 +572,7 @@
      * before acquiring the lock
      */
     @ReservedStackAccess
-        public long readLockInterruptibly() throws InterruptedException {
+    public long readLockInterruptibly() throws InterruptedException {
         long s, next;
         if (!Thread.interrupted()
             // bypass acquireRead on common uncontended case
--- a/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/package-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -200,7 +200,7 @@
  * concurrent collection is thread-safe, but not governed by a
  * single exclusion lock.  In the particular case of
  * ConcurrentHashMap, it safely permits any number of
- * concurrent reads as well as a tunable number of concurrent
+ * concurrent reads as well as a large number of concurrent
  * writes.  "Synchronized" classes can be useful when you need
  * to prevent all access to a collection via a single lock, at
  * the expense of poorer scalability.  In other cases in which
--- a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,37 +25,47 @@
 
 package java.util.spi;
 
+import jdk.internal.misc.JavaUtilResourceBundleAccess;
+import jdk.internal.misc.SharedSecrets;
+
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.UncheckedIOException;
 import java.lang.reflect.Module;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Locale;
+import java.util.PropertyResourceBundle;
 import java.util.ResourceBundle;
-import sun.util.locale.provider.ResourceBundleProviderSupport;
 import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
 
-
 /**
- * {@code AbstractResourceBundleProvider} is an abstract class for helping
- * implement the {@link ResourceBundleProvider} interface.
+ * {@code AbstractResourceBundleProvider} is an abstract class that provides
+ * the basic support for a provider implementation class for
+ * {@link ResourceBundleProvider}.
  *
  * <p>
- * Resource bundles can be packaged in a named module separated from
- * the <em>caller module</em> loading the resource bundle, i.e. the module
- * calling {@link ResourceBundle#getBundle(String)}.  For the caller module
- * to load a resource bundle "{@code com.example.app.MyResources}"
- * from another module and a service interface named
- * "{@code com.example.app.MyResourcesProvider}",
- * the <em>bundle provider module</em> can provide the implementation class
+ * Resource bundles can be packaged in one or more
+ * named modules, <em>bundle modules</em>.  The <em>consumer</em> of the
+ * resource bundle is the one calling {@link ResourceBundle#getBundle(String)}.
+ * In order for the consumer module to load a resource bundle
+ * "{@code com.example.app.MyResources}" provided by another module,
+ * it will use the {@linkplain java.util.ServiceLoader service loader}
+ * mechanism.  A service interface named "{@code com.example.app.MyResourcesProvider}"
+ * must be defined and a <em>bundle provider module</em> will provide an
+ * implementation class of "{@code com.example.app.MyResourcesProvider}"
  * as follows:
  *
  * <pre><code>
  * import com.example.app.MyResourcesProvider;
  * class MyResourcesProviderImpl extends AbstractResourceBundleProvider
  *     implements MyResourcesProvider
- * {</code>
- *     {@code @Override
+ * {
+ *     protected String toBundleName(String baseName, Locale locale) {
+ *         // return the bundle name per the naming of the resource bundle
+ *         :
+ *     }
+ *
  *     public ResourceBundle getBundle(String baseName, Locale locale) {
  *         // this module only provides bundles in french
  *         if (locale.equals(Locale.FRENCH)) {
@@ -63,7 +73,7 @@
  *         }
  *         return null;
  *     }
- * }}</pre>
+ * }</code></pre>
  *
  * @see <a href="../ResourceBundle.html#bundleprovider">
  *     Resource Bundles in Named Modules</a>
@@ -73,6 +83,9 @@
  * @since 9
  */
 public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider {
+    private static final JavaUtilResourceBundleAccess RB_ACCESS =
+        SharedSecrets.getJavaUtilResourceBundleAccess();
+
     private static final String FORMAT_CLASS = "java.class";
     private static final String FORMAT_PROPERTIES = "java.properties";
 
@@ -112,7 +125,23 @@
 
     /**
      * Returns the bundle name for the given {@code baseName} and {@code
-     * locale}.  This method is called from the default implementation of the
+     * locale} that this provider provides.
+     *
+     * @apiNote
+     * A resource bundle provider may package its resource bundles in the
+     * same package as the base name of the resource bundle if the package
+     * is not split among other named modules.  If there are more than one
+     * bundle providers providing the resource bundle of a given base name,
+     * the resource bundles can be packaged with per-language grouping
+     * or per-region grouping to eliminate the split packages.
+     *
+     * <p>For example, if {@code baseName} is {@code "p.resources.Bundle"} then
+     * the resource bundle name of {@code "p.resources.Bundle"} of
+     * {@code Locale("ja",&nbsp;"",&nbsp;"XX")} and {@code Locale("en")}
+     * could be {@code "p.resources.ja.Bundle_ja_&thinsp;_XX"} and
+     * {@code p.resources.Bundle_en"} respectively
+     *
+     * <p> This method is called from the default implementation of the
      * {@link #getBundle(String, Locale)} method.
      *
      * @implNote The default implementation of this method is the same as the
@@ -126,27 +155,28 @@
      */
     protected String toBundleName(String baseName, Locale locale) {
         return ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT)
-                   .toBundleName(baseName, locale);
+            .toBundleName(baseName, locale);
     }
 
     /**
      * Returns a {@code ResourceBundle} for the given {@code baseName} and
-     * {@code locale}. This method calls the
-     * {@link #toBundleName(String, Locale) toBundleName} method to get the
-     * bundle name for the {@code baseName} and {@code locale}. The formats
-     * specified by the constructor will be searched to find the resource
-     * bundle.
+     * {@code locale}.
      *
      * @implNote
-     * The default implementation of this method will find the resource bundle
-     * local to the module of this provider.
+     * The default implementation of this method calls the
+     * {@link #toBundleName(String, Locale) toBundleName} method to get the
+     * bundle name for the {@code baseName} and {@code locale} and finds the
+     * resource bundle of the bundle name local in the module of this provider.
+     * It will only search the formats specified when this provider was
+     * constructed.
      *
      * @param baseName the base bundle name of the resource bundle, a fully
      *                 qualified class name.
      * @param locale the locale for which the resource bundle should be instantiated
-     * @return {@code ResourceBundle} of the given {@code baseName} and {@code locale},
-     *         or null if no resource bundle is found
-     * @throws NullPointerException if {@code baseName} or {@code locale} is null
+     * @return {@code ResourceBundle} of the given {@code baseName} and
+     *         {@code locale}, or {@code null} if no resource bundle is found
+     * @throws NullPointerException if {@code baseName} or {@code locale} is
+     *         {@code null}
      * @throws UncheckedIOException if any IO exception occurred during resource
      *         bundle loading
      */
@@ -159,13 +189,9 @@
         for (String format : formats) {
             try {
                 if (FORMAT_CLASS.equals(format)) {
-                    PrivilegedAction<ResourceBundle> pa = () ->
-                                    ResourceBundleProviderSupport
-                                         .loadResourceBundle(module, bundleName);
-                    bundle = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+                    bundle = loadResourceBundle(module, bundleName);
                 } else if (FORMAT_PROPERTIES.equals(format)) {
-                    bundle = ResourceBundleProviderSupport
-                                 .loadPropertyResourceBundle(module, bundleName);
+                    bundle = loadPropertyResourceBundle(module, bundleName);
                 }
                 if (bundle != null) {
                     break;
@@ -176,4 +202,61 @@
         }
         return bundle;
     }
+
+    /*
+     * Returns the ResourceBundle of .class format if found in the module
+     * of this provider.
+     */
+    private static ResourceBundle loadResourceBundle(Module module, String bundleName)
+    {
+        PrivilegedAction<Class<?>> pa = () -> Class.forName(module, bundleName);
+        Class<?> c = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION);
+        if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
+            @SuppressWarnings("unchecked")
+            Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
+            return RB_ACCESS.newResourceBundle(bundleClass);
+        }
+        return null;
+    }
+
+    /*
+     * Returns the ResourceBundle of .property format if found in the module
+     * of this provider.
+     */
+    private static ResourceBundle loadPropertyResourceBundle(Module module,
+                                                             String bundleName)
+        throws IOException
+    {
+        String resourceName = toResourceName(bundleName, "properties");
+        if (resourceName == null) {
+            return null;
+        }
+
+        PrivilegedAction<InputStream> pa = () -> {
+            try {
+                return module.getResourceAsStream(resourceName);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        };
+        try (InputStream stream = AccessController.doPrivileged(pa)) {
+            if (stream != null) {
+                return new PropertyResourceBundle(stream);
+            } else {
+                return null;
+            }
+        } catch (UncheckedIOException e) {
+            throw e.getCause();
+        }
+    }
+
+    private static String toResourceName(String bundleName, String suffix) {
+        if (bundleName.contains("://")) {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
+        sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
+        return sb.toString();
+    }
+
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -115,7 +115,7 @@
     private FileSystem newFileSystem(String targetHome, URI uri, Map<String, ?> env)
             throws IOException {
         Objects.requireNonNull(targetHome);
-        Path jrtfs = FileSystems.getDefault().getPath(targetHome, JRT_FS_JAR);
+        Path jrtfs = FileSystems.getDefault().getPath(targetHome, "lib", JRT_FS_JAR);
         if (Files.notExists(jrtfs)) {
             throw new IOException(jrtfs.toString() + " not exist");
         }
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImage.java	Thu Dec 01 21:39:49 2016 +0000
@@ -113,12 +113,16 @@
         if (cs == null)
             return System.getProperty("java.home");
 
-        // assume loaded from $TARGETJDK/jrt-fs.jar
+        // assume loaded from $TARGETJDK/lib/jrt-fs.jar
         URL url = cs.getLocation();
         if (!url.getProtocol().equalsIgnoreCase("file"))
-            throw new RuntimeException(url + " loaded in unexpected way");
+            throw new InternalError(url + " loaded in unexpected way");
         try {
-            return Paths.get(url.toURI()).getParent().toString();
+            Path lib = Paths.get(url.toURI()).getParent();
+            if (!lib.getFileName().toString().equals("lib"))
+                throw new InternalError(url + " unexpected path");
+
+            return lib.getParent().toString();
         } catch (URISyntaxException e) {
             throw new InternalError(e);
         }
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Thu Dec 01 21:39:49 2016 +0000
@@ -71,8 +71,8 @@
     private static final ServicesCatalog SERVICES_CATALOG = ServicesCatalog.create();
 
     // ClassLoaderValue map for boot class loader
-    private static final ConcurrentHashMap<?, ?> CLASS_LOADER_VALUE_MAP =
-        new ConcurrentHashMap<>();
+    private static final ConcurrentHashMap<?, ?> CLASS_LOADER_VALUE_MAP
+        = new ConcurrentHashMap<>();
 
     /**
      * Returns the unnamed module for the boot loader.
@@ -111,14 +111,27 @@
     }
 
     /**
-     * Returns a URL to a resource in a named module defined to the boot loader.
+     * Loads the Class object with the given name in the given module
+     * defined to the boot loader. Returns {@code null} if not found.
+     */
+    public static Class<?> loadClass(Module module, String name) {
+        Class<?> c = loadClassOrNull(name);
+        if (c != null && c.getModule() == module) {
+            return c;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns a URL to a resource in a module defined to the boot loader.
      */
     public static URL findResource(String mn, String name) throws IOException {
         return ClassLoaders.bootLoader().findResource(mn, name);
     }
 
     /**
-     * Returns an input stream to a resource in a named module defined to the
+     * Returns an input stream to a resource in a module defined to the
      * boot loader.
      */
     public static InputStream findResourceAsStream(String mn, String name)
@@ -128,9 +141,8 @@
     }
 
     /**
-     * Returns the URL to the given resource if the resource can be located
-     * on the boot class path. This method does not locate a resource in any
-     * of the named modules defined to the boot loader.
+     * Returns the URL to the given resource in any of the modules
+     * defined to the boot loader and the boot class path.
      */
     public static URL findResource(String name) {
         return ClassLoaders.bootLoader().findResource(name);
@@ -138,8 +150,7 @@
 
     /**
      * Returns an Iterator to iterate over the resources of the given name
-     * on the boot class path. This method does not locate resources in any
-     * of the named modules defined to the boot loader.
+     * in any of the modules defined to the boot loader.
      */
     public static Enumeration<URL> findResources(String name) throws IOException {
         return ClassLoaders.bootLoader().findResources(name);
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,8 +29,10 @@
 import java.io.FilePermission;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleReference;
 import java.lang.module.ModuleReader;
+import java.lang.ref.SoftReference;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URL;
@@ -91,7 +93,7 @@
 {
     static {
         if (!ClassLoader.registerAsParallelCapable())
-            throw new InternalError();
+            throw new InternalError("Unable to register as parallel capable");
     }
 
     // parent ClassLoader
@@ -117,7 +119,7 @@
             if (mref.location().isPresent()) {
                 try {
                     url = mref.location().get().toURL();
-                } catch (MalformedURLException e) { }
+                } catch (MalformedURLException | IllegalArgumentException e) { }
             }
             this.loader = loader;
             this.mref = mref;
@@ -141,6 +143,9 @@
     // maps a module reference to a module reader
     private final Map<ModuleReference, ModuleReader> moduleToReader;
 
+    // cache of resource name -> list of URLs.
+    // used only for resources that are not in module packages
+    private volatile SoftReference<Map<String, List<URL>>> resourceCache;
 
     /**
      * Create a new instance.
@@ -161,6 +166,8 @@
      * the types in the module visible.
      */
     public void loadModule(ModuleReference mref) {
+        assert !VM.isModuleSystemInited();
+
         String mn = mref.descriptor().name();
         if (nameToModule.putIfAbsent(mn, mref) != null) {
             throw new InternalError(mn + " already defined to this loader");
@@ -195,32 +202,20 @@
      */
     @Override
     public URL findResource(String mn, String name) throws IOException {
-        ModuleReference mref = nameToModule.get(mn);
-        if (mref == null)
-            return null;   // not defined to this class loader
-
-        URL url;
+        URL url = null;
 
-        try {
-            url = AccessController.doPrivileged(
-                new PrivilegedExceptionAction<URL>() {
-                    @Override
-                    public URL run() throws IOException {
-                        URI u = moduleReaderFor(mref).find(name).orElse(null);
-                        if (u != null) {
-                            try {
-                                return u.toURL();
-                            } catch (MalformedURLException e) { }
-                        }
-                        return null;
-                    }
-                });
-        } catch (PrivilegedActionException pae) {
-            throw (IOException) pae.getCause();
+        if (mn != null) {
+            // find in module
+            ModuleReference mref = nameToModule.get(mn);
+            if (mref != null) {
+                url = findResource(mref, name);
+            }
+        } else {
+            // find on class path
+            url = findResourceOnClassPath(name);
         }
 
-        // check access to the URL
-        return checkURL(url);
+        return checkURL(url);  // check access before returning
     }
 
     /**
@@ -232,70 +227,234 @@
     {
         // Need URL to resource when running with a security manager so that
         // the right permission check is done.
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-
+        if (System.getSecurityManager() != null || mn == null) {
             URL url = findResource(mn, name);
             return (url != null) ? url.openStream() : null;
-
-        } else {
-
-            ModuleReference mref = nameToModule.get(mn);
-            if (mref == null)
-                return null;   // not defined to this class loader
+        }
 
-            try {
-                return AccessController.doPrivileged(
-                    new PrivilegedExceptionAction<InputStream>() {
-                        @Override
-                        public InputStream run() throws IOException {
-                            return moduleReaderFor(mref).open(name).orElse(null);
-                        }
-                    });
-            } catch (PrivilegedActionException pae) {
-                throw (IOException) pae.getCause();
-            }
-        }
-    }
-
-    /**
-     * Finds the resource with the given name on the class path of this class
-     * loader.
-     */
-    @Override
-    public URL findResource(String name) {
-        if (ucp != null) {
-            PrivilegedAction<URL> pa = () -> ucp.findResource(name, false);
-            URL url = AccessController.doPrivileged(pa);
-            return checkURL(url);
+        // find in module defined to this loader, no security manager
+        ModuleReference mref = nameToModule.get(mn);
+        if (mref != null) {
+            return moduleReaderFor(mref).open(name).orElse(null);
         } else {
             return null;
         }
     }
 
     /**
+     * Finds a resource with the given name in the modules defined to this
+     * class loader or its class path.
+     */
+    @Override
+    public URL findResource(String name) {
+        String pn = ResourceHelper.getPackageName(name);
+        LoadedModule module = packageToModule.get(pn);
+        if (module != null) {
+
+            // resource is in a package of a module defined to this loader
+            if (module.loader() == this
+                && (name.endsWith(".class") || isOpen(module.mref(), pn))) {
+                try {
+                    return findResource(module.name(), name); // checks URL
+                } catch (IOException ioe) {
+                    return null;
+                }
+            }
+
+        } else {
+
+            // not in a module package but may be in module defined to this loader
+            try {
+                List<URL> urls = findMiscResource(name);
+                if (!urls.isEmpty()) {
+                    URL url = urls.get(0);
+                    if (url != null) {
+                        return checkURL(url); // check access before returning
+                    }
+                }
+            } catch (IOException ioe) {
+                return null;
+            }
+
+        }
+
+        // search class path
+        URL url = findResourceOnClassPath(name);
+        return checkURL(url);
+    }
+
+    /**
      * Returns an enumeration of URL objects to all the resources with the
-     * given name on the class path of this class loader.
+     * given name in modules defined to this class loader or on the class
+     * path of this loader.
      */
     @Override
     public Enumeration<URL> findResources(String name) throws IOException {
-        if (ucp != null) {
-            List<URL> result = new ArrayList<>();
-            PrivilegedAction<Enumeration<URL>> pa = () -> ucp.findResources(name, false);
-            Enumeration<URL> e = AccessController.doPrivileged(pa);
-            while (e.hasMoreElements()) {
-                URL url = checkURL(e.nextElement());
+        List<URL> checked = new ArrayList<>();  // list of checked URLs
+
+        String pn = ResourceHelper.getPackageName(name);
+        LoadedModule module = packageToModule.get(pn);
+        if (module != null) {
+
+            // resource is in a package of a module defined to this loader
+            if (module.loader() == this
+                && (name.endsWith(".class") || isOpen(module.mref(), pn))) {
+                URL url = findResource(module.name(), name);  // checks URL
                 if (url != null) {
-                    result.add(url);
+                    checked.add(url);
+                }
+            }
+
+        } else {
+            // not in a package of a module defined to this loader
+            for (URL url : findMiscResource(name)) {
+                url = checkURL(url);
+                if (url != null) {
+                    checked.add(url);
                 }
             }
-            return Collections.enumeration(result); // checked URLs
+        }
+
+        // search class path
+        Enumeration<URL> e = findResourcesOnClassPath(name);
+        while (e.hasMoreElements()) {
+            URL url = checkURL(e.nextElement());
+            if (url != null) {
+                checked.add(url);
+            }
+        }
+
+        return Collections.enumeration(checked);
+    }
+
+    /**
+     * Returns the list of URLs to a "miscellaneous" resource in modules
+     * defined to this loader. A miscellaneous resource is not in a module
+     * package, e.g. META-INF/services/p.S.
+     *
+     * The cache used by this method avoids repeated searching of all modules.
+     */
+    private List<URL> findMiscResource(String name) throws IOException {
+        SoftReference<Map<String, List<URL>>> ref = this.resourceCache;
+        Map<String, List<URL>> map = (ref != null) ? ref.get() : null;
+        if (map != null) {
+            List<URL> urls = map.get(name);
+            if (urls != null)
+                return urls;
+        }
+
+        // search all modules for the resource
+        List<URL> urls;
+        try {
+            urls = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<>() {
+                    @Override
+                    public List<URL> run() throws IOException {
+                        List<URL> result = new ArrayList<>();
+                        for (ModuleReference mref : nameToModule.values()) {
+                            URI u = moduleReaderFor(mref).find(name).orElse(null);
+                            if (u != null) {
+                                try {
+                                    result.add(u.toURL());
+                                } catch (MalformedURLException |
+                                         IllegalArgumentException e) {
+                                }
+                            }
+                        }
+                        return result;
+                    }
+                });
+        } catch (PrivilegedActionException pae) {
+            throw (IOException) pae.getCause();
+        }
+
+        // only cache resources after all modules have been defined
+        if (VM.isModuleSystemInited()) {
+            if (map == null) {
+                map = new ConcurrentHashMap<>();
+                this.resourceCache = new SoftReference<>(map);
+            }
+            if (urls.isEmpty())
+                urls = Collections.emptyList();
+            map.putIfAbsent(name, urls);
+        }
+        return urls;
+    }
+
+    /**
+     * Returns the URL to a resource in a module or {@code null} if not found.
+     */
+    private URL findResource(ModuleReference mref, String name) throws IOException {
+        URI u;
+        if (System.getSecurityManager() == null) {
+            u = moduleReaderFor(mref).find(name).orElse(null);
         } else {
+            try {
+                u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () {
+                    @Override
+                    public URI run() throws IOException {
+                        return moduleReaderFor(mref).find(name).orElse(null);
+                    }
+                });
+            } catch (PrivilegedActionException pae) {
+                throw (IOException) pae.getCause();
+            }
+        }
+        if (u != null) {
+            try {
+                return u.toURL();
+            } catch (MalformedURLException | IllegalArgumentException e) { }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the URL to a resource in a module. Returns {@code null} if not found
+     * or an I/O error occurs.
+     */
+    private URL findResourceOrNull(ModuleReference mref, String name) {
+        try {
+            return findResource(mref, name);
+        } catch (IOException ignore) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns a URL to a resource on the class path.
+     */
+    private URL findResourceOnClassPath(String name) {
+        if (ucp != null) {
+            if (System.getSecurityManager() == null) {
+                return ucp.findResource(name, false);
+            } else {
+                PrivilegedAction<URL> pa = () -> ucp.findResource(name, false);
+                return AccessController.doPrivileged(pa);
+            }
+        } else {
+            // no class path
+            return null;
+        }
+    }
+
+    /**
+     * Returns the URLs of all resources of the given name on the class path.
+     */
+    private Enumeration<URL> findResourcesOnClassPath(String name) {
+        if (ucp != null) {
+            if (System.getSecurityManager() == null) {
+                return ucp.findResources(name, false);
+            } else {
+                PrivilegedAction<Enumeration<URL>> pa;
+                pa = () -> ucp.findResources(name, false);
+                return AccessController.doPrivileged(pa);
+            }
+        } else {
+            // no class path
             return Collections.emptyEnumeration();
         }
     }
 
-
     // -- finding/loading classes
 
     /**
@@ -335,24 +494,30 @@
     }
 
     /**
-     * Finds the class with the specified binary name in a given module.
-     * This method returns {@code null} if the class cannot be found.
+     * Finds the class with the specified binary name in a module.
+     * This method returns {@code null} if the class cannot be found
+     * or not defined in the specified module.
      */
     @Override
     protected Class<?> findClass(String mn, String cn) {
-        ModuleReference mref = nameToModule.get(mn);
-        if (mref == null)
-            return null;   // not defined to this class loader
+        if (mn != null) {
+            // find the candidate module for this class
+            LoadedModule loadedModule = findLoadedModule(mn, cn);
+            if (loadedModule == null) {
+                return null;
+            }
 
-        // find the candidate module for this class
-        LoadedModule loadedModule = findLoadedModule(cn);
-        if (loadedModule == null || !loadedModule.name().equals(mn)) {
-            return null;   // module name does not match
+            // attempt to load class in module defined to this loader
+            assert loadedModule.loader() == this;
+            return findClassInModuleOrNull(loadedModule, cn);
         }
 
-        // attempt to load class in module defined to this loader
-        assert loadedModule.loader() == this;
-        return findClassInModuleOrNull(loadedModule, cn);
+        // search class path
+        if (ucp != null) {
+            return findClassOnClassPathOrNull(cn);
+        }
+
+        return null;
     }
 
     /**
@@ -441,14 +606,33 @@
     }
 
     /**
+     * Find the candidate loaded module for the given class name
+     * in the named module.  Returns {@code null} if the named module
+     * is not defined to this class loader or does not contain
+     * the API package for the class.
+     */
+    private LoadedModule findLoadedModule(String mn, String cn) {
+        LoadedModule loadedModule = findLoadedModule(cn);
+        if (loadedModule != null && mn.equals(loadedModule.name())) {
+            return loadedModule;
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * Finds the class with the specified binary name if in a module
      * defined to this ClassLoader.
      *
      * @return the resulting Class or {@code null} if not found
      */
     private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) {
-        PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule);
-        return AccessController.doPrivileged(pa);
+        if (System.getSecurityManager() == null) {
+            return defineClass(cn, loadedModule);
+        } else {
+            PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule);
+            return AccessController.doPrivileged(pa);
+        }
     }
 
     /**
@@ -457,10 +641,21 @@
      * @return the resulting Class or {@code null} if not found
      */
     private Class<?> findClassOnClassPathOrNull(String cn) {
-        return AccessController.doPrivileged(
-            new PrivilegedAction<Class<?>>() {
+        String path = cn.replace('.', '/').concat(".class");
+        if (System.getSecurityManager() == null) {
+            Resource res = ucp.getResource(path, false);
+            if (res != null) {
+                try {
+                    return defineClass(cn, res);
+                } catch (IOException ioe) {
+                    // TBD on how I/O errors should be propagated
+                }
+            }
+            return null;
+        } else {
+            // avoid use of lambda here
+            PrivilegedAction<Class<?>> pa = new PrivilegedAction<>() {
                 public Class<?> run() {
-                    String path = cn.replace('.', '/').concat(".class");
                     Resource res = ucp.getResource(path, false);
                     if (res != null) {
                         try {
@@ -471,7 +666,9 @@
                     }
                     return null;
                 }
-            });
+            };
+            return AccessController.doPrivileged(pa);
+        }
     }
 
     /**
@@ -662,13 +859,13 @@
                 sealBase = url;
         }
         return definePackage(pn,
-                             specTitle,
-                             specVersion,
-                             specVendor,
-                             implTitle,
-                             implVersion,
-                             implVendor,
-                             sealBase);
+                specTitle,
+                specVersion,
+                specVendor,
+                implTitle,
+                implVersion,
+                implVendor,
+                sealBase);
     }
 
     /**
@@ -760,6 +957,27 @@
     };
 
     /**
+     * Returns true if the given module opens the given package
+     * unconditionally.
+     *
+     * @implNote This method currently iterates over each of the open
+     * packages. This will be replaced once the ModuleDescriptor.Opens
+     * API is updated.
+     */
+    private boolean isOpen(ModuleReference mref, String pn) {
+        ModuleDescriptor descriptor = mref.descriptor();
+        if (descriptor.isOpen())
+            return true;
+        for (ModuleDescriptor.Opens opens : descriptor.opens()) {
+            String source = opens.source();
+            if (!opens.isQualified() && source.equals(pn)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Checks access to the given URL. We use URLClassPath for consistent
      * checking with java.net.URLClassLoader.
      */
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java	Thu Dec 01 21:39:49 2016 +0000
@@ -48,13 +48,19 @@
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.security.SecureClassLoader;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Stream;
 
+import jdk.internal.misc.SharedSecrets;
+
 
 /**
  * A class loader that loads classes and resources from a collection of
@@ -119,7 +125,7 @@
             if (mref.location().isPresent()) {
                 try {
                     url = mref.location().get().toURL();
-                } catch (MalformedURLException e) { }
+                } catch (MalformedURLException | IllegalArgumentException e) { }
             }
             this.mref = mref;
             this.url = url;
@@ -141,7 +147,7 @@
                   LoaderPool pool,
                   ClassLoader parent)
     {
-        super(parent);
+        super("Loader-" + resolvedModule.name(), parent);
 
         this.pool = pool;
         this.parent = parent;
@@ -200,12 +206,12 @@
      * @param cf the Configuration containing at least modules to be defined to
      *           this class loader
      *
-     * @param parentLayer the parent Layer
+     * @param parentLayers the parent Layers
      */
-    public Loader initRemotePackageMap(Configuration cf, Layer parentLayer) {
-
+    public Loader initRemotePackageMap(Configuration cf,
+                                       List<Layer> parentLayers)
+    {
         for (String name : nameToModule.keySet()) {
-
             ResolvedModule resolvedModule = cf.findModule(name).get();
             assert resolvedModule.configuration() == cf;
 
@@ -228,17 +234,15 @@
 
                 } else {
 
-                    // find the layer contains the module that is read
-                    Layer layer = parentLayer;
-                    while (layer != null) {
-                        if (layer.configuration() == other.configuration()) {
-                            break;
-                        }
-                        layer = layer.parent().orElse(null);
-                    }
-                    assert layer != null;
+                    // find the layer for the target module
+                    Layer layer = parentLayers.stream()
+                        .map(parent -> findLayer(parent, other.configuration()))
+                        .flatMap(Optional::stream)
+                        .findAny()
+                        .orElseThrow(() ->
+                            new InternalError("Unable to find parent layer"));
 
-                    // find the class loader for the module in the layer
+                    // find the class loader for the module
                     // For now we use the platform loader for modules defined to the
                     // boot loader
                     assert layer.findModule(mn).isPresent();
@@ -268,7 +272,6 @@
                             throw new IllegalArgumentException("Package "
                                 + pn + " cannot be imported from multiple loaders");
                         }
-
                     }
                 }
             }
@@ -279,6 +282,17 @@
     }
 
     /**
+     * Find the layer corresponding to the given configuration in the tree
+     * of layers rooted at the given parent.
+     */
+    private Optional<Layer> findLayer(Layer parent, Configuration cf) {
+        return SharedSecrets.getJavaLangReflectModuleAccess().layers(parent)
+                .filter(l -> l.configuration() == cf)
+                .findAny();
+    }
+
+
+    /**
      * Returns the loader pool that this loader is in or {@code null} if this
      * loader is not in a loader pool.
      */
@@ -296,12 +310,14 @@
      */
     @Override
     protected URL findResource(String mn, String name) throws IOException {
-        ModuleReference mref = nameToModule.get(mn);
+        ModuleReference mref = (mn != null) ? nameToModule.get(mn) : null;
         if (mref == null)
             return null;   // not defined to this class loader
 
+        // locate resource
+        URL url = null;
         try {
-            return AccessController.doPrivileged(
+            url = AccessController.doPrivileged(
                 new PrivilegedExceptionAction<URL>() {
                     @Override
                     public URL run() throws IOException {
@@ -309,16 +325,89 @@
                         if (ouri.isPresent()) {
                             try {
                                 return ouri.get().toURL();
-                            } catch (MalformedURLException e) { }
+                            } catch (MalformedURLException |
+                                     IllegalArgumentException e) { }
                         }
                         return null;
                     }
-                }, acc);
+                });
         } catch (PrivilegedActionException pae) {
             throw (IOException) pae.getCause();
-        } catch (SecurityException se) {
-            return null;
+        }
+
+        // check access with permissions restricted by ACC
+        if (url != null && System.getSecurityManager() != null) {
+            try {
+                URL urlToCheck = url;
+                url = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<URL>() {
+                        @Override
+                        public URL run() throws IOException {
+                            return URLClassPath.checkURL(urlToCheck);
+                        }
+                    }, acc);
+            } catch (PrivilegedActionException pae) {
+                url = null;
+            }
         }
+
+        return url;
+    }
+
+    @Override
+    public URL findResource(String name) {
+        URL url = null;
+        String pn = ResourceHelper.getPackageName(name);
+        LoadedModule module = localPackageToModule.get(pn);
+        if (module != null) {
+            if (name.endsWith(".class") || isOpen(module.mref(), pn)) {
+                try {
+                    url = findResource(module.name(), name);
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+        } else {
+            for (ModuleReference mref : nameToModule.values()) {
+                try {
+                    url = findResource(mref.descriptor().name(), name);
+                    if (url != null)
+                        break;
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+        }
+        return url;
+    }
+
+    @Override
+    public Enumeration<URL> findResources(String name) throws IOException {
+        List<URL> urls = new ArrayList<>();
+        String pn = ResourceHelper.getPackageName(name);
+        LoadedModule module = localPackageToModule.get(pn);
+        if (module != null) {
+            if (name.endsWith(".class") || isOpen(module.mref(), pn)) {
+                try {
+                    URL url = findResource(module.name(), name);
+                    if (url != null)
+                        urls.add(url);
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+        } else {
+            for (ModuleReference mref : nameToModule.values()) {
+                try {
+                    URL url = findResource(mref.descriptor().name(), name);
+                    if (url != null)
+                        urls.add(url);
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+        }
+        return Collections.enumeration(urls);
     }
 
 
@@ -544,4 +633,24 @@
         }
     }
 
+    /**
+     * Returns true if the given module opens the given package
+     * unconditionally.
+     *
+     * @implNote This method currently iterates over each of the open
+     * packages. This will be replaced once the ModuleDescriptor.Opens
+     * API is updated.
+     */
+    private boolean isOpen(ModuleReference mref, String pn) {
+        ModuleDescriptor descriptor = mref.descriptor();
+        if (descriptor.isOpen())
+            return true;
+        for (ModuleDescriptor.Opens opens : descriptor.opens()) {
+            String source = opens.source();
+            if (!opens.isQualified() && source.equals(pn)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,10 +26,10 @@
 package jdk.internal.loader;
 
 import java.lang.module.Configuration;
-import java.lang.module.ModuleReference;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.stream.Stream;
 
@@ -51,7 +51,7 @@
      * created with the given parent class loader as its parent.
      */
     public LoaderPool(Configuration cf,
-                      Layer parentLayer,
+                      List<Layer> parentLayers,
                       ClassLoader parentLoader)
     {
         Map<String, Loader> loaders = new HashMap<>();
@@ -63,7 +63,7 @@
         this.loaders = loaders;
 
         // complete the initialization
-        loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayer));
+        loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayers));
     }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,64 @@
+/*
+ * 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.loader;
+
+import jdk.internal.module.Checks;
+
+/**
+ * Helper class for Class#getResource, Module#getResourceAsStream, and other
+ * methods that locate a resource in a module.
+ */
+public final class ResourceHelper {
+    private ResourceHelper() { }
+
+    /**
+     * Returns the <em>package name</em> for a resource.
+     */
+    public static String getPackageName(String name) {
+        int index = name.lastIndexOf('/');
+        if (index != -1) {
+            return name.substring(0, index).replace("/", ".");
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Returns true if the resource is a <em>simple resource</em> that can
+     * never be encapsulated. Resources ending in "{@code .class}" or where
+     * the package name is not a Java identifier are resources that can
+     * never be encapsulated.
+     */
+    public static boolean isSimpleResource(String name) {
+        int len = name.length();
+        if (len > 6 && name.endsWith(".class")) {
+            return true;
+        }
+        if (!Checks.isJavaIdentifier(getPackageName(name))) {
+            return true;
+        }
+        return false;
+    }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Executable;
 import java.lang.reflect.Layer;
+import java.lang.reflect.Method;
 import java.lang.reflect.Module;
 import java.net.URL;
 import java.security.AccessControlContext;
@@ -36,12 +37,19 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Stream;
 
-import jdk.internal.module.ServicesCatalog;
 import jdk.internal.reflect.ConstantPool;
 import sun.reflect.annotation.AnnotationType;
 import sun.nio.ch.Interruptible;
 
 public interface JavaLangAccess {
+
+    /**
+     * Returns a {@code Method} object that reflects the specified public
+     * member method of the given class. Returns {@code null} if the
+     * method is not defined.
+     */
+    Method getMethodOrNull(Class<?> klass, String name, Class<?>... parameterTypes);
+
     /** Return the constant pool for a class. */
     ConstantPool getConstantPool(Class<?> klass);
 
@@ -136,17 +144,6 @@
     Layer getBootLayer();
 
     /**
-     * Returns the ServicesCatalog for the given class loader.
-     */
-    ServicesCatalog getServicesCatalog(ClassLoader cl);
-
-    /**
-     * Returns the ServicesCatalog for the given class loader, creating it
-     * if doesn't already exist.
-     */
-    ServicesCatalog createOrGetServicesCatalog(ClassLoader cl);
-
-    /**
      * Returns the ConcurrentHashMap used as a storage for ClassLoaderValue(s)
      * associated with the given class loader, creating it if it doesn't already exist.
      */
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,24 +27,26 @@
 
 import java.io.PrintStream;
 import java.lang.module.Configuration;
-import jdk.internal.module.ModuleHashes;
-
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Version;
 import java.lang.module.ModuleFinder;
-import java.util.Collection;
 import java.lang.module.ModuleReader;
 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;
 
+import jdk.internal.module.ModuleHashes;
+
 /**
  * Provides access to non-public methods in java.lang.module.
  */
@@ -52,28 +54,59 @@
 public interface JavaLangModuleAccess {
 
     /**
-     * Returns {@code ModuleDescriptor.Requires} of the given modifier
+     * Creates a builder for building a module with the given module name.
+     *
+     * @param strict
+     *        Indicates whether module names are checked or not
+     */
+    ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict);
+
+    /**
+     * Creates a builder for building an open module with the given module name.
+     *
+     * @param strict
+     *        Indicates whether module names are checked or not
+     */
+    ModuleDescriptor.Builder newOpenModuleBuilder(String mn, boolean strict);
+
+    /**
+     * Returns a {@code ModuleDescriptor.Requires} of the given modifiers
      * and module name.
      */
     Requires newRequires(Set<Requires.Modifier> ms, String mn);
 
     /**
      * Returns an unqualified {@code ModuleDescriptor.Exports}
-     * of the given package name.
+     * of the given modifiers and package name source.
      */
-    Exports newExports(String source);
+    Exports newExports(Set<Exports.Modifier> ms,
+                       String source);
 
     /**
      * Returns a qualified {@code ModuleDescriptor.Exports}
-     * of the given package name and targets.
+     * of the given modifiers, package name source and targets.
      */
-    Exports newExports(String source, Set<String> targets);
+    Exports newExports(Set<Exports.Modifier> ms,
+                       String source,
+                       Set<String> targets);
+
+    /**
+     * Returns an unqualified {@code ModuleDescriptor.Opens}
+     * of the given modifiers and package name source.
+     */
+    Opens newOpens(Set<Opens.Modifier> ms, String source);
+
+    /**
+     * Returns a qualified {@code ModuleDescriptor.Opens}
+     * of the given modifiers, package name source and targets.
+     */
+    Opens newOpens(Set<Opens.Modifier> ms, String source, Set<String> targets);
 
     /**
      * Returns a {@code ModuleDescriptor.Provides}
      * of the given service name and providers.
      */
-    Provides newProvides(String service, Set<String> providers);
+    Provides newProvides(String service, List<String> providers);
 
     /**
      * Returns a {@code ModuleDescriptor.Version} of the given version.
@@ -89,19 +122,22 @@
      * Returns a new {@code ModuleDescriptor} instance.
      */
     ModuleDescriptor newModuleDescriptor(String name,
+                                         boolean open,
                                          boolean automatic,
                                          boolean synthetic,
                                          Set<Requires> requires,
+                                         Set<Exports> exports,
+                                         Set<Opens> opens,
                                          Set<String> uses,
-                                         Set<Exports> exports,
-                                         Map<String, Provides> provides,
+                                         Set<Provides> provides,
                                          Version version,
                                          String mainClass,
                                          String osName,
                                          String osArch,
                                          String osVersion,
                                          Set<String> packages,
-                                         ModuleHashes hashes);
+                                         ModuleHashes hashes,
+                                         int hashCode);
 
     /**
      * Returns the object with the hashes of other modules
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.net.URI;
+import java.util.stream.Stream;
 
 import jdk.internal.module.ServicesCatalog;
 
@@ -71,16 +72,37 @@
     void addExports(Module m1, String pkg, Module m2);
 
     /**
+     * Updates module m1 to open a package to module m2. Opening the
+     * package does not result in a strong reference to m2 (m2 can be GC'ed).
+     */
+    void addOpens(Module m1, String pkg, Module m2);
+
+    /**
      * Updates a module m to export a package to all modules.
      */
     void addExportsToAll(Module m, String pkg);
 
     /**
+     * Updates a module m to open a package to all modules.
+     */
+    void addOpensToAll(Module m, String pkg);
+
+    /**
      * Updates a module m to export a package to all unnamed modules.
      */
     void addExportsToAllUnnamed(Module m, String pkg);
 
     /**
+     * Updates a module m to open a package to all unnamed modules.
+     */
+    void addOpensToAllUnnamed(Module m, String pkg);
+
+    /**
+     * Updates a module m to use a service.
+     */
+    void addUses(Module m, Class<?> service);
+
+    /**
      * Add a package to the given module.
      */
     void addPackage(Module m, String pkg);
@@ -90,4 +112,15 @@
      */
     ServicesCatalog getServicesCatalog(Layer layer);
 
+    /**
+     * Returns an ordered stream of layers. The first element is is the
+     * given layer, the remaining elements are its parents, in DFS order.
+     */
+    Stream<Layer> layers(Layer layer);
+
+    /**
+     * Returns a stream of the layers that have modules defined to the
+     * given class loader.
+     */
+    Stream<Layer> layers(ClassLoader loader);
 }
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
 
 package jdk.internal.misc;
 
+import java.lang.reflect.Module;
 import java.util.Locale;
 import java.util.ResourceBundle;
 
@@ -51,4 +52,16 @@
      * Sets the bundle's base name to the given name.
      */
     void setName(ResourceBundle bundle, String name);
+
+    /**
+     * Returns a {@code ResourceBundle} of the given baseName and locale
+     * loaded on behalf of the given module with no caller module
+     * access check.
+     */
+    ResourceBundle getBundle(String baseName, Locale locale, Module module);
+
+    /**
+     * Instantiates a {@code ResourceBundle} of the given bundle class.
+     */
+    ResourceBundle newResourceBundle(Class<? extends ResourceBundle> bundleClass);
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,7 @@
 package jdk.internal.misc;
 
 import java.lang.module.ModuleDescriptor;
+import java.util.ResourceBundle;
 import java.util.jar.JarFile;
 import java.io.Console;
 import java.io.FileDescriptor;
@@ -294,6 +295,8 @@
     }
 
     public static JavaUtilResourceBundleAccess getJavaUtilResourceBundleAccess() {
+        if (javaUtilResourceBundleAccess == null)
+            unsafe.ensureClassInitialized(ResourceBundle.class);
         return javaUtilResourceBundleAccess;
     }
 
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,12 +26,14 @@
 
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 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.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -40,7 +42,7 @@
 
 /**
  * This builder is optimized for reconstituting ModuleDescriptor
- * for installed modules.  The validation should be done at jlink time.
+ * for system modules.  The validation should be done at jlink time.
  *
  * 1. skip name validation
  * 2. ignores dependency hashes.
@@ -53,66 +55,137 @@
     private static final JavaLangModuleAccess jlma =
         SharedSecrets.getJavaLangModuleAccess();
 
-    private static final Set<Requires.Modifier> MANDATED =
-        Collections.singleton(Requires.Modifier.MANDATED);
-    private static final Set<Requires.Modifier> PUBLIC =
-        Collections.singleton(Requires.Modifier.PUBLIC);
-
     // Static cache of the most recently seen Version to cheaply deduplicate
     // most Version objects.  JDK modules have the same version.
     static Version cachedVersion;
 
+    /**
+     * Returns a {@link Requires} for a dependence on a module
+     * with the given (and possibly empty) set of modifiers.
+     */
+    public static Requires newRequires(Set<Requires.Modifier> mods,
+                                       String mn)
+    {
+        return jlma.newRequires(mods, mn);
+    }
+
+    /**
+     * Returns a {@link Exports} for a qualified export, with
+     * the given (and possibly empty) set of modifiers,
+     * to a set of target modules.
+     */
+    public static Exports newExports(Set<Exports.Modifier> ms,
+                                     String pn,
+                                     Set<String> targets) {
+        return jlma.newExports(ms, pn, targets);
+    }
+
+    /**
+     * Returns an {@link Opens} for an unqualified open with a given set of
+     * modifiers.
+     */
+    public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
+        return jlma.newOpens(ms, pn);
+    }
+
+    /**
+     * Returns an {@link Opens} for a qualified opens, with
+     * the given (and possibly empty) set of modifiers,
+     * to a set of target modules.
+     */
+    public static Opens newOpens(Set<Opens.Modifier> ms,
+                                 String pn,
+                                 Set<String> targets) {
+        return jlma.newOpens(ms, pn, targets);
+    }
+
+    /**
+     * Returns a {@link Exports} for an unqualified export with a given set
+     * of modifiers.
+     */
+    public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
+        return jlma.newExports(ms, pn);
+    }
+
+    /**
+     * Returns a {@link Provides} for a service with a given list of
+     * implementation classes.
+     */
+    public static Provides newProvides(String st, List<String> pcs) {
+        return jlma.newProvides(st, pcs);
+    }
+
     final String name;
-    final Set<Requires> requires;
-    final Set<Exports> exports;
-    final Map<String, Provides> provides;
+    boolean open;
+    boolean automatic;
+    boolean synthetic;
+    Set<Requires> requires;
+    Set<Exports> exports;
+    Set<Opens> opens;
     Set<String> packages;
     Set<String> uses;
+    Set<Provides> provides;
     Version version;
     String mainClass;
     String osName;
     String osArch;
     String osVersion;
     String algorithm;
-    Map<String, String> hashes;
+    Map<String, byte[]> hashes;
 
-    Builder(String name, int reqs, int exports,
-            int provides, int packages) {
+    Builder(String name) {
         this.name = name;
-        this.requires = reqs > 0 ? new HashSet<>(reqs) : Collections.emptySet();
-        this.exports  = exports > 0 ? new HashSet<>(exports) : Collections.emptySet();
-        this.provides = provides > 0 ? new HashMap<>(provides) : Collections.emptyMap();
+        this.requires = Collections.emptySet();
+        this.exports = Collections.emptySet();
+        this.opens = Collections.emptySet();
+        this.provides = Collections.emptySet();
         this.uses = Collections.emptySet();
     }
 
-    /**
-     * Adds a module dependence with the given (and possibly empty) set
-     * of modifiers.
-     */
-    public Builder requires(Set<Requires.Modifier> mods, String mn) {
-        requires.add(jlma.newRequires(Collections.unmodifiableSet(mods), mn));
+    Builder open(boolean value) {
+        this.open = value;
+        return this;
+    }
+
+    Builder automatic(boolean value) {
+        this.automatic = value;
+        return this;
+    }
+
+    Builder synthetic(boolean value) {
+        this.synthetic = value;
         return this;
     }
 
     /**
-     * Adds a module dependence with an empty set of modifiers.
+     * Sets module exports.
      */
-    public Builder requires(String mn) {
-        requires.add(jlma.newRequires(Collections.emptySet(), mn));
+    public Builder exports(Exports[] exports) {
+        this.exports = Set.of(exports);
         return this;
     }
 
     /**
-     * Adds a module dependence with the given modifier.
+     * Sets module opens.
+     */
+    public Builder opens(Opens[] opens) {
+        this.opens = Set.of(opens);
+        return this;
+    }
+
+    /**
+     * Sets module requires.
      */
-    public Builder requires(Requires.Modifier mod, String mn) {
-        if (mod == Requires.Modifier.MANDATED) {
-            requires.add(jlma.newRequires(MANDATED, mn));
-        } else if (mod == Requires.Modifier.PUBLIC) {
-            requires.add(jlma.newRequires(PUBLIC, mn));
-        } else {
-            requires.add(jlma.newRequires(Collections.singleton(mod), mn));
-        }
+    public Builder requires(Requires[] requires) {
+        this.requires = Set.of(requires);
+        return this;
+    }
+
+    /**
+     * Adds a set of (possible empty) packages.
+     */
+    public Builder packages(Set<String> packages) {
+        this.packages = packages;
         return this;
     }
 
@@ -125,51 +198,10 @@
     }
 
     /**
-     * Adds an export to a set of target modules.
-     */
-    public Builder exports(String pn, Set<String> targets) {
-        exports.add(jlma.newExports(pn, targets));
-        return this;
-    }
-
-    /**
-     * Adds an export to a target module.
-     */
-    public Builder exports(String pn, String target) {
-        return exports(pn, Collections.singleton(target));
-    }
-
-    /**
-     * Adds an export.
+     * Sets module provides.
      */
-    public Builder exports(String pn) {
-        exports.add(jlma.newExports(pn));
-        return this;
-    }
-
-    /**
-     * Provides service {@code st} with implementations {@code pcs}.
-     */
-    public Builder provides(String st, Set<String> pcs) {
-        if (provides.containsKey(st))
-            throw new IllegalStateException("Providers of service "
-                    + st + " already declared");
-        provides.put(st, jlma.newProvides(st, pcs));
-        return this;
-    }
-
-    /**
-     * Provides service {@code st} with implementation {@code pc}.
-     */
-    public Builder provides(String st, String pc) {
-        return provides(st, Collections.singleton(pc));
-    }
-
-    /**
-     * Adds a set of (possible empty) packages.
-     */
-    public Builder packages(Set<String> packages) {
-        this.packages = packages;
+    public Builder provides(Provides[] provides) {
+        this.provides = Set.of(provides);
         return this;
     }
 
@@ -253,7 +285,7 @@
     /**
      * Sets the module hash for the given module name
      */
-    public Builder moduleHash(String mn, String hash) {
+    public Builder moduleHash(String mn, byte[] hash) {
         if (hashes == null)
             hashes = new HashMap<>();
 
@@ -264,18 +296,20 @@
     /**
      * Builds a {@code ModuleDescriptor} from the components.
      */
-    public ModuleDescriptor build() {
+    public ModuleDescriptor build(int hashCode) {
         assert name != null;
 
         ModuleHashes moduleHashes =
             hashes != null ? new ModuleHashes(algorithm, hashes) : null;
 
         return jlma.newModuleDescriptor(name,
-                                        false,    // automatic
-                                        false,    // assume not synthetic for now
+                                        open,
+                                        automatic,
+                                        synthetic,
                                         requires,
+                                        exports,
+                                        opens,
                                         uses,
-                                        exports,
                                         provides,
                                         version,
                                         mainClass,
@@ -283,6 +317,7 @@
                                         osArch,
                                         osVersion,
                                         packages,
-                                        moduleHashes);
+                                        moduleHashes,
+                                        hashCode);
     }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,6 @@
 
 package jdk.internal.module;
 
-
 public final class Checks {
 
     private Checks() { }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,17 +27,20 @@
 
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Requires;
-import java.lang.module.ModuleDescriptor.Requires.Modifier;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Version;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.org.objectweb.asm.Attribute;
 import jdk.internal.org.objectweb.asm.ByteVector;
 import jdk.internal.org.objectweb.asm.ClassReader;
@@ -51,7 +54,7 @@
  * class file attributes in a module-info class file.
  */
 
-class ClassFileAttributes {
+public final class ClassFileAttributes {
 
     private ClassFileAttributes() { }
 
@@ -60,16 +63,18 @@
      *   // See lang-vm.html for details.
      * }
      */
-    static class ModuleAttribute extends Attribute {
+    public static class ModuleAttribute extends Attribute {
+        private static final JavaLangModuleAccess JLMA
+            = SharedSecrets.getJavaLangModuleAccess();
 
         private ModuleDescriptor descriptor;
 
-        ModuleAttribute(ModuleDescriptor descriptor) {
+        public ModuleAttribute(ModuleDescriptor descriptor) {
             super(MODULE);
             this.descriptor = descriptor;
         }
 
-        ModuleAttribute() {
+        public ModuleAttribute() {
             super(MODULE);
         }
 
@@ -81,27 +86,43 @@
                                  int codeOff,
                                  Label[] labels)
         {
-            ModuleDescriptor.Builder builder
-                = new ModuleDescriptor.Builder("xyzzy"); // Name never used
             ModuleAttribute attr = new ModuleAttribute();
 
+            // module_name
+            String mn = cr.readUTF8(off, buf).replace('/', '.');
+            off += 2;
+
+            // module_flags
+            int module_flags = cr.readUnsignedShort(off);
+            boolean open = ((module_flags & ACC_OPEN) != 0);
+            off += 2;
+
+            ModuleDescriptor.Builder builder;
+            if (open) {
+                builder = JLMA.newOpenModuleBuilder(mn, false);
+            } else {
+                builder = JLMA.newModuleBuilder(mn, false);
+            }
+
             // 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);
+                String dn = cr.readUTF8(off, buf).replace('/', '.');
                 int flags = cr.readUnsignedShort(off + 2);
-                Set<Modifier> mods;
+                Set<Requires.Modifier> mods;
                 if (flags == 0) {
                     mods = Collections.emptySet();
                 } else {
                     mods = new HashSet<>();
-                    if ((flags & ACC_PUBLIC) != 0)
-                        mods.add(Modifier.PUBLIC);
+                    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(Modifier.SYNTHETIC);
+                        mods.add(Requires.Modifier.SYNTHETIC);
                     if ((flags & ACC_MANDATED) != 0)
-                        mods.add(Modifier.MANDATED);
+                        mods.add(Requires.Modifier.MANDATED);
                 }
                 builder.requires(mods, dn);
                 off += 4;
@@ -113,18 +134,70 @@
             if (exports_count > 0) {
                 for (int i=0; i<exports_count; i++) {
                     String pkg = cr.readUTF8(off, buf).replace('/', '.');
-                    int exports_to_count = cr.readUnsignedShort(off+2);
-                    off += 4;
+                    off += 2;
+
+                    int flags = cr.readUnsignedShort(off);
+                    off += 2;
+                    Set<Exports.Modifier> mods;
+                    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 = cr.readUnsignedShort(off);
+                    off += 2;
                     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);
+                            String t = cr.readUTF8(off, buf).replace('/', '.');
                             off += 2;
                             targets.add(t);
                         }
-                        builder.exports(pkg, targets);
+                        builder.exports(mods, pkg, targets);
                     } else {
-                        builder.exports(pkg);
+                        builder.exports(mods, pkg);
+                    }
+                }
+            }
+
+            // opens_count and opens[opens_count]
+            int open_count = cr.readUnsignedShort(off);
+            off += 2;
+            if (open_count > 0) {
+                for (int i=0; i<open_count; i++) {
+                    String pkg = cr.readUTF8(off, buf).replace('/', '.');
+                    off += 2;
+
+                    int flags = cr.readUnsignedShort(off);
+                    off += 2;
+                    Set<Opens.Modifier> mods;
+                    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 opens_to_count = cr.readUnsignedShort(off);
+                    off += 2;
+                    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('/', '.');
+                            off += 2;
+                            targets.add(t);
+                        }
+                        builder.opens(mods, pkg, targets);
+                    } else {
+                        builder.opens(mods, pkg);
                     }
                 }
             }
@@ -144,15 +217,19 @@
             int provides_count = cr.readUnsignedShort(off);
             off += 2;
             if (provides_count > 0) {
-                Map<String, Set<String>> provides = new HashMap<>();
                 for (int i=0; i<provides_count; i++) {
-                    String sn = cr.readClass(off, buf).replace('/', '.');
-                    String cn = cr.readClass(off + 2, buf).replace('/', '.');
-                    provides.computeIfAbsent(sn, k -> new LinkedHashSet<>()).add(cn);
-                    off += 4;
+                    String service = cr.readClass(off, buf).replace('/', '.');
+                    off += 2;
+                    int with_count = cr.readUnsignedShort(off);
+                    off += 2;
+                    List<String> providers = new ArrayList<>();
+                    for (int j=0; j<with_count; j++) {
+                        String cn = cr.readClass(off, buf).replace('/', '.');
+                        off += 2;
+                        providers.add(cn);
+                    }
+                    builder.provides(service, providers);
                 }
-                provides.entrySet().forEach(e -> builder.provides(e.getKey(),
-                                                                  e.getValue()));
             }
 
             attr.descriptor = builder.build();
@@ -169,6 +246,19 @@
             assert descriptor != null;
             ByteVector attr = new ByteVector();
 
+            // module_name
+            String mn = descriptor.name();
+            int module_name_index = cw.newUTF8(mn.replace('.', '/'));
+            attr.putShort(module_name_index);
+
+            // module_flags
+            int module_flags = 0;
+            if (descriptor.isOpen())
+                module_flags |= ACC_OPEN;
+            if (descriptor.isSynthetic())
+                module_flags |= ACC_SYNTHETIC;
+            attr.putShort(module_flags);
+
             // requires_count
             attr.putShort(descriptor.requires().size());
 
@@ -176,32 +266,61 @@
             for (Requires md : descriptor.requires()) {
                 String dn = md.name();
                 int flags = 0;
-                if (md.modifiers().contains(Modifier.PUBLIC))
-                    flags |= ACC_PUBLIC;
-                if (md.modifiers().contains(Modifier.SYNTHETIC))
+                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(Modifier.MANDATED))
+                if (md.modifiers().contains(Requires.Modifier.MANDATED))
                     flags |= ACC_MANDATED;
-                int index = cw.newUTF8(dn);
+                int index = cw.newUTF8(dn.replace('.', '/'));
                 attr.putShort(index);
                 attr.putShort(flags);
             }
 
             // exports_count and exports[exports_count];
-            if (descriptor.exports().isEmpty()) {
-                attr.putShort(0);
-            } else {
-                attr.putShort(descriptor.exports().size());
-                for (Exports e : descriptor.exports()) {
-                    String pkg = e.source().replace('.', '/');
-                    attr.putShort(cw.newUTF8(pkg));
-                    if (e.isQualified()) {
-                        Set<String> ts = e.targets();
-                        attr.putShort(ts.size());
-                        ts.forEach(t -> attr.putShort(cw.newUTF8(t)));
-                    } else {
-                        attr.putShort(0);
-                    }
+            attr.putShort(descriptor.exports().size());
+            for (Exports e : descriptor.exports()) {
+                String pkg = e.source().replace('.', '/');
+                attr.putShort(cw.newUTF8(pkg));
+
+                int flags = 0;
+                if (e.modifiers().contains(Exports.Modifier.SYNTHETIC))
+                    flags |= ACC_SYNTHETIC;
+                if (e.modifiers().contains(Exports.Modifier.MANDATED))
+                    flags |= ACC_MANDATED;
+                attr.putShort(flags);
+
+                if (e.isQualified()) {
+                    Set<String> ts = e.targets();
+                    attr.putShort(ts.size());
+                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                } 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));
+
+                int flags = 0;
+                if (obj.modifiers().contains(Opens.Modifier.SYNTHETIC))
+                    flags |= ACC_SYNTHETIC;
+                if (obj.modifiers().contains(Opens.Modifier.MANDATED))
+                    flags |= ACC_MANDATED;
+                attr.putShort(flags);
+
+                if (obj.isQualified()) {
+                    Set<String> ts = obj.targets();
+                    attr.putShort(ts.size());
+                    ts.forEach(t -> attr.putShort(cw.newUTF8(t.replace('.', '/'))));
+                } else {
+                    attr.putShort(0);
                 }
             }
 
@@ -221,14 +340,13 @@
             if (descriptor.provides().isEmpty()) {
                 attr.putShort(0);
             } else {
-                int count = descriptor.provides().values()
-                    .stream().mapToInt(ps -> ps.providers().size()).sum();
-                attr.putShort(count);
-                for (Provides p : descriptor.provides().values()) {
+                attr.putShort(descriptor.provides().size());
+                for (Provides p : descriptor.provides()) {
                     String service = p.service().replace('.', '/');
-                    int index = cw.newClass(service);
+                    attr.putShort(cw.newClass(service));
+                    int with_count = p.providers().size();
+                    attr.putShort(with_count);
                     for (String provider : p.providers()) {
-                        attr.putShort(index);
                         attr.putShort(cw.newClass(provider.replace('.', '/')));
                     }
                 }
@@ -239,44 +357,13 @@
     }
 
     /**
-     * Synthetic attribute.
-     */
-    static class SyntheticAttribute extends Attribute {
-        SyntheticAttribute() {
-            super(SYNTHETIC);
-        }
-
-        @Override
-        protected Attribute read(ClassReader cr,
-                                 int off,
-                                 int len,
-                                 char[] buf,
-                                 int codeOff,
-                                 Label[] labels)
-        {
-            return new SyntheticAttribute();
-        }
-
-        @Override
-        protected ByteVector write(ClassWriter cw,
-                                   byte[] code,
-                                   int len,
-                                   int maxStack,
-                                   int maxLocals)
-        {
-            ByteVector attr = new ByteVector();
-            return attr;
-        }
-    }
-
-    /**
-     * ConcealedPackages attribute.
+     * ModulePackages attribute.
      *
      * <pre> {@code
      *
-     * ConcealedPackages_attribute {
+     * ModulePackages_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "ConcealedPackages"
+     *   // the string "ModulePackages"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -288,15 +375,15 @@
      *
      * }</pre>
      */
-    static class ConcealedPackagesAttribute extends Attribute {
+    public static class ModulePackagesAttribute extends Attribute {
         private final Set<String> packages;
 
-        ConcealedPackagesAttribute(Set<String> packages) {
-            super(CONCEALED_PACKAGES);
+        public ModulePackagesAttribute(Set<String> packages) {
+            super(MODULE_PACKAGES);
             this.packages = packages;
         }
 
-        ConcealedPackagesAttribute() {
+        public ModulePackagesAttribute() {
             this(null);
         }
 
@@ -320,7 +407,7 @@
                 off += 2;
             }
 
-            return new ConcealedPackagesAttribute(packages);
+            return new ModulePackagesAttribute(packages);
         }
 
         @Override
@@ -348,13 +435,13 @@
     }
 
     /**
-     * Version attribute.
+     * ModuleVersion attribute.
      *
      * <pre> {@code
      *
-     * Version_attribute {
+     * ModuleVersion_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "Version"
+     *   // the string "ModuleVersion"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -364,15 +451,15 @@
      *
      * } </pre>
      */
-    static class VersionAttribute extends Attribute {
+    public static class ModuleVersionAttribute extends Attribute {
         private final Version version;
 
-        VersionAttribute(Version version) {
-            super(VERSION);
+        public ModuleVersionAttribute(Version version) {
+            super(MODULE_VERSION);
             this.version = version;
         }
 
-        VersionAttribute() {
+        public ModuleVersionAttribute() {
             this(null);
         }
 
@@ -385,7 +472,7 @@
                                  Label[] labels)
         {
             String value = cr.readUTF8(off, buf);
-            return new VersionAttribute(Version.parse(value));
+            return new ModuleVersionAttribute(Version.parse(value));
         }
 
         @Override
@@ -403,13 +490,13 @@
     }
 
     /**
-     * MainClass attribute.
+     * ModuleMainClass attribute.
      *
      * <pre> {@code
      *
      * MainClass_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "MainClass"
+     *   // the string "ModuleMainClass"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -419,15 +506,15 @@
      *
      * } </pre>
      */
-    static class MainClassAttribute extends Attribute {
+    public static class ModuleMainClassAttribute extends Attribute {
         private final String mainClass;
 
-        MainClassAttribute(String mainClass) {
-            super(MAIN_CLASS);
+        public ModuleMainClassAttribute(String mainClass) {
+            super(MODULE_MAIN_CLASS);
             this.mainClass = mainClass;
         }
 
-        MainClassAttribute() {
+        public ModuleMainClassAttribute() {
             this(null);
         }
 
@@ -440,7 +527,7 @@
                                  Label[] labels)
         {
             String value = cr.readClass(off, buf);
-            return new MainClassAttribute(value);
+            return new ModuleMainClassAttribute(value);
         }
 
         @Override
@@ -458,13 +545,13 @@
     }
 
     /**
-     * TargetPlatform attribute.
+     * ModuleTarget attribute.
      *
      * <pre> {@code
      *
      * TargetPlatform_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "TargetPlatform"
+     *   // the string "ModuleTarget"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
@@ -478,19 +565,19 @@
      *
      * } </pre>
      */
-    static class TargetPlatformAttribute extends Attribute {
+    public static class ModuleTargetAttribute extends Attribute {
         private final String osName;
         private final String osArch;
         private final String osVersion;
 
-        TargetPlatformAttribute(String osName, String osArch, String osVersion) {
-            super(TARGET_PLATFORM);
+        public ModuleTargetAttribute(String osName, String osArch, String osVersion) {
+            super(MODULE_TARGET);
             this.osName = osName;
             this.osArch = osArch;
             this.osVersion = osVersion;
         }
 
-        TargetPlatformAttribute() {
+        public ModuleTargetAttribute() {
             this(null, null, null);
         }
 
@@ -522,7 +609,7 @@
                 osVersion = cr.readUTF8(off, buf);
             off += 2;
 
-            return new TargetPlatformAttribute(osName, osArch, osVersion);
+            return new ModuleTargetAttribute(osName, osArch, osVersion);
         }
 
         @Override
@@ -554,39 +641,37 @@
     }
 
     /**
-     * Hashes attribute.
+     * ModuleHashes attribute.
      *
      * <pre> {@code
      *
-     * Hashes_attribute {
+     * ModuleHashes_attribute {
      *   // index to CONSTANT_utf8_info structure in constant pool representing
-     *   // the string "Hashes"
+     *   // the string "ModuleHashes"
      *   u2 attribute_name_index;
      *   u4 attribute_length;
      *
-     *   // index to CONSTANT_CONSTANT_utf8_info structure with algorithm name
+     *   // index to CONSTANT_utf8_info structure with algorithm name
      *   u2 algorithm_index;
      *
      *   // the number of entries in the hashes table
-     *   u2 hash_count;
-     *   {   u2 requires_index
-     *       u2 hash_index;
-     *   } hashes[hash_count];
+     *   u2 hashes_count;
+     *   {   u2 module_name_index
+     *       u2 hash_length;
+     *       u1 hash[hash_length];
+     *   } hashes[hashes_count];
      *
      * } </pre>
-     *
-     * @apiNote For now the hash is stored in base64 as a UTF-8 string, an
-     * alternative is to store it as an array of u1.
      */
-    static class HashesAttribute extends Attribute {
+    static class ModuleHashesAttribute extends Attribute {
         private final ModuleHashes hashes;
 
-        HashesAttribute(ModuleHashes hashes) {
-            super(HASHES);
+        ModuleHashesAttribute(ModuleHashes hashes) {
+            super(MODULE_HASHES);
             this.hashes = hashes;
         }
 
-        HashesAttribute() {
+        ModuleHashesAttribute() {
             this(null);
         }
 
@@ -601,21 +686,28 @@
             String algorithm = cr.readUTF8(off, buf);
             off += 2;
 
-            int hash_count = cr.readUnsignedShort(off);
+            int hashes_count = cr.readUnsignedShort(off);
             off += 2;
 
-            Map<String, String> map = new HashMap<>();
-            for (int i=0; i<hash_count; i++) {
-                String dn = cr.readUTF8(off, buf);
+            Map<String, byte[]> map = new HashMap<>();
+            for (int i=0; i<hashes_count; i++) {
+                String mn = cr.readUTF8(off, buf).replace('/', '.');
+                off += 2;
+
+                int hash_length = cr.readUnsignedShort(off);
                 off += 2;
-                String hash = cr.readUTF8(off, buf);
-                off += 2;
-                map.put(dn, hash);
+                byte[] hash = new byte[hash_length];
+                for (int j=0; j<hash_length; j++) {
+                    hash[j] = (byte) (0xff & cr.readByte(off+j));
+                }
+                off += hash_length;
+
+                map.put(mn, hash);
             }
 
             ModuleHashes hashes = new ModuleHashes(algorithm, map);
 
-            return new HashesAttribute(hashes);
+            return new ModuleHashesAttribute(hashes);
         }
 
         @Override
@@ -633,11 +725,15 @@
             Set<String> names = hashes.names();
             attr.putShort(names.size());
 
-            for (String dn : names) {
-                String hash = hashes.hashFor(dn);
+            for (String mn : names) {
+                byte[] hash = hashes.hashFor(mn);
                 assert hash != null;
-                attr.putShort(cw.newUTF8(dn));
-                attr.putShort(cw.newUTF8(hash));
+                attr.putShort(cw.newUTF8(mn.replace('.', '/')));
+
+                attr.putShort(hash.length);
+                for (byte b: hash) {
+                    attr.putByte(b);
+                }
             }
 
             return attr;
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Thu Dec 01 21:39:49 2016 +0000
@@ -35,19 +35,20 @@
     // Attribute names
     public static final String MODULE             = "Module";
     public static final String SOURCE_FILE        = "SourceFile";
-    public static final String SYNTHETIC          = "Synthetic";
     public static final String SDE                = "SourceDebugExtension";
 
-    public static final String CONCEALED_PACKAGES = "ConcealedPackages";
-    public static final String VERSION            = "Version";
-    public static final String MAIN_CLASS         = "MainClass";
-    public static final String TARGET_PLATFORM    = "TargetPlatform";
-    public static final String HASHES             = "Hashes";
+    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";
 
-    // access and requires flags
-    public static final int ACC_MODULE       = 0x8000;
-    public static final int ACC_PUBLIC       = 0x0020;
-    public static final int ACC_SYNTHETIC    = 0x1000;
-    public static final int ACC_MANDATED     = 0x8000;
+    // access, requires, exports, and opens flags
+    public static final int ACC_MODULE        = 0x8000;
+    public static final int ACC_OPEN          = 0x0020;
+    public static final int ACC_TRANSITIVE    = 0x0010;
+    public static final int ACC_STATIC_PHASE  = 0x0020;
+    public static final int ACC_SYNTHETIC     = 0x1000;
+    public static final int ACC_MANDATED      = 0x8000;
 
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Thu Dec 01 21:39:49 2016 +0000
@@ -37,9 +37,11 @@
 import java.net.URI;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
@@ -81,10 +83,20 @@
     // the token for "all modules on the module path"
     private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
 
+    // The ModulePatcher for the initial configuration
+    private static final ModulePatcher patcher = initModulePatcher();
+
     // ModuleFinder for the initial configuration
     private static ModuleFinder initialFinder;
 
     /**
+     * Returns the ModulePatcher for the initial configuration.
+     */
+    public static ModulePatcher patcher() {
+        return patcher;
+    }
+
+    /**
      * Returns the ModuleFinder for the initial configuration
      */
     public static ModuleFinder finder() {
@@ -101,7 +113,7 @@
 
         long t0 = System.nanoTime();
 
-        // system modules
+        // system modules (may be patched)
         ModuleFinder systemModules = ModuleFinder.ofSystem();
 
         PerfCounters.systemModulesTime.addElapsedTimeFrom(t0);
@@ -247,7 +259,7 @@
         if (baseUri.getScheme().equals("jrt")   // toLowerCase not needed here
                 && (upgradeModulePath == null)
                 && (appModulePath == null)
-                && (!ModulePatcher.isBootLayerPatched())) {
+                && (patcher.isEmpty())) {
             needPostResolutionChecks = false;
         }
 
@@ -314,9 +326,9 @@
         PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
 
 
-        // --add-reads and --add-exports
+        // --add-reads, -add-exports/-add-opens
         addExtraReads(bootLayer);
-        addExtraExports(bootLayer);
+        addExtraExportsAndOpens(bootLayer);
 
         // total time to initialize
         PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
@@ -389,6 +401,18 @@
         }
     }
 
+
+    /**
+     * Initialize the module patcher for the initial configuration passed on the
+     * value of the --patch-module options.
+     */
+    private static ModulePatcher initModulePatcher() {
+        Map<String, List<String>> map = decode("jdk.module.patch.",
+                                               File.pathSeparator,
+                                               false);
+        return new ModulePatcher(map);
+    }
+
     /**
      * Returns the set of module names specified via --add-modules options
      * on the command line
@@ -408,7 +432,6 @@
             for (String s : value.split(",")) {
                 if (s.length() > 0) modules.add(s);
             }
-
             index++;
             value = getAndRemoveProperty(prefix + index);
         }
@@ -423,9 +446,11 @@
     private static void addExtraReads(Layer bootLayer) {
 
         // decode the command line options
-        Map<String, Set<String>> map = decode("jdk.module.addreads.");
+        Map<String, List<String>> map = decode("jdk.module.addreads.");
+        if (map.isEmpty())
+            return;
 
-        for (Map.Entry<String, Set<String>> e : map.entrySet()) {
+        for (Map.Entry<String, List<String>> e : map.entrySet()) {
 
             // the key is $MODULE
             String mn = e.getKey();
@@ -448,22 +473,36 @@
                         warn("Unknown module: " + name);
                     }
                 }
-
             }
         }
     }
 
-
     /**
-     * Process the --add-exports options to add any additional read edges that
-     * are specified on the command-line.
+     * Process the --add-exports and --add-opens options to export/open
+     * additional packages specified on the command-line.
      */
-    private static void addExtraExports(Layer bootLayer) {
+    private static void addExtraExportsAndOpens(Layer bootLayer) {
+
+        // --add-exports
+        String prefix = "jdk.module.addexports.";
+        Map<String, List<String>> extraExports = decode(prefix);
+        if (!extraExports.isEmpty()) {
+            addExtraExportsOrOpens(bootLayer, extraExports, false);
+        }
 
-        // decode the command line options
-        Map<String, Set<String>> map = decode("jdk.module.addexports.");
+        // --add-opens
+        prefix = "jdk.module.addopens.";
+        Map<String, List<String>> extraOpens = decode(prefix);
+        if (!extraOpens.isEmpty()) {
+            addExtraExportsOrOpens(bootLayer, extraOpens, true);
+        }
+    }
 
-        for (Map.Entry<String, Set<String>> e : map.entrySet()) {
+    private static void addExtraExportsOrOpens(Layer bootLayer,
+                                               Map<String, List<String>> map,
+                                               boolean opens)
+    {
+        for (Map.Entry<String, List<String>> e : map.entrySet()) {
 
             // the key is $MODULE/$PACKAGE
             String key = e.getKey();
@@ -507,28 +546,40 @@
                     }
                 }
                 if (allUnnamed) {
-                    Modules.addExportsToAllUnnamed(m, pn);
+                    if (opens) {
+                        Modules.addOpensToAllUnnamed(m, pn);
+                    } else {
+                        Modules.addExportsToAllUnnamed(m, pn);
+                    }
                 } else {
-                    Modules.addExports(m, pn, other);
+                    if (opens) {
+                        Modules.addOpens(m, pn, other);
+                    } else {
+                        Modules.addExports(m, pn, other);
+                    }
                 }
+
             }
         }
     }
 
-
     /**
-     * Decodes the values of --add-reads or --add-exports options
+     * Decodes the values of --add-reads, -add-exports, --add-opens or
+     * --patch-modules options that are encoded in system properties.
      *
-     * The format of the options is: $KEY=$MODULE(,$MODULE)*
+     * @param prefix the system property prefix
+     * @praam regex the regex for splitting the RHS of the option value
      */
-    private static Map<String, Set<String>> decode(String prefix) {
+    private static Map<String, List<String>> decode(String prefix,
+                                                    String regex,
+                                                    boolean allowDuplicates) {
         int index = 0;
         // the system property is removed after decoding
         String value = getAndRemoveProperty(prefix + index);
         if (value == null)
             return Collections.emptyMap();
 
-        Map<String, Set<String>> map = new HashMap<>();
+        Map<String, List<String>> map = new HashMap<>();
 
         while (value != null) {
 
@@ -545,8 +596,11 @@
             if (rhs.isEmpty())
                 fail("Unable to parse: " + value);
 
-            Set<String> values = map.computeIfAbsent(key, k -> new HashSet<>());
-            for (String s : rhs.split(",")) {
+            // value is <module>(,<module>)* or <file>(<pathsep><file>)*
+            if (!allowDuplicates && map.containsKey(key))
+                fail(key + " specified more than once");
+            List<String> values = map.computeIfAbsent(key, k -> new ArrayList<>());
+            for (String s : rhs.split(regex)) {
                 if (s.length() > 0) values.add(s);
             }
 
@@ -558,6 +612,14 @@
     }
 
     /**
+     * Decodes the values of --add-reads, -add-exports or --add-opens
+     * which use the "," to separate the RHS of the option value.
+     */
+    private static Map<String, List<String>> decode(String prefix) {
+        return decode(prefix, ",", true);
+    }
+
+    /**
      * Gets and remove the named system property
      */
     private static String getAndRemoveProperty(String key) {
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	Thu Dec 01 21:39:49 2016 +0000
@@ -32,7 +32,6 @@
 import java.nio.file.Path;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
-import java.util.Base64;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -45,23 +44,23 @@
 public final class ModuleHashes {
 
     /**
-     * A supplier of an encoded message digest.
+     * A supplier of a message digest.
      */
     public static interface HashSupplier {
-        String generate(String algorithm);
+        byte[] generate(String algorithm);
     }
 
 
     private final String algorithm;
-    private final Map<String, String> nameToHash;
+    private final Map<String, byte[]> nameToHash;
 
     /**
      * Creates a {@code ModuleHashes}.
      *
      * @param algorithm   the algorithm used to create the hashes
-     * @param nameToHash  the map of module name to hash value (in string form)
+     * @param nameToHash  the map of module name to hash value
      */
-    public ModuleHashes(String algorithm, Map<String, String> nameToHash) {
+    public ModuleHashes(String algorithm, Map<String, byte[]> nameToHash) {
         this.algorithm = algorithm;
         this.nameToHash = Collections.unmodifiableMap(nameToHash);
     }
@@ -81,28 +80,28 @@
     }
 
     /**
-     * Returns the hash string for the given module name, {@code null}
+     * Returns the hash for the given module name, {@code null}
      * if there is no hash recorded for the module.
      */
-    public String hashFor(String mn) {
+    public byte[] hashFor(String mn) {
         return nameToHash.get(mn);
     }
 
     /**
-     * Returns unmodifiable map of module name to hash string.
+     * Returns unmodifiable map of module name to hash
      */
-    public Map<String, String> hashes() {
+    public Map<String, byte[]> hashes() {
         return nameToHash;
     }
 
     /**
      * Computes the hash for the given file with the given message digest
-     * algorithm. Returns the results a base64-encoded String.
+     * algorithm.
      *
      * @throws UncheckedIOException if an I/O error occurs
      * @throws RuntimeException if the algorithm is not available
      */
-    public static String computeHashAsString(Path file, String algorithm) {
+    public static byte[] computeHash(Path file, String algorithm) {
         try {
             MessageDigest md = MessageDigest.getInstance(algorithm);
 
@@ -118,8 +117,7 @@
                 }
             }
 
-            byte[] bytes = md.digest();
-            return Base64.getEncoder().encodeToString(bytes);
+            return md.digest();
         } catch (NoSuchAlgorithmException e) {
             throw new RuntimeException(e);
         } catch (IOException ioe) {
@@ -133,14 +131,14 @@
      * the entry name, typically the module name. The map value is the file
      * path to the entry (module artifact).
      *
-     * @return ModuleHashes encapsulate the hashes
+     * @return ModuleHashes that encapsulates the hashes
      */
     public static ModuleHashes generate(Map<String, Path> map, String algorithm) {
-        Map<String, String> nameToHash = new HashMap<>();
+        Map<String, byte[]> nameToHash = new HashMap<>();
         for (Map.Entry<String, Path> entry: map.entrySet()) {
             String name = entry.getKey();
             Path path = entry.getValue();
-            nameToHash.put(name, computeHashAsString(path, algorithm));
+            nameToHash.put(name, computeHash(path, algorithm));
         }
         return new ModuleHashes(algorithm, nameToHash);
     }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Thu Dec 01 21:39:49 2016 +0000
@@ -53,8 +53,8 @@
     // the input stream to read the original module-info.class
     private final InputStream in;
 
-    // the packages in the ConcealedPackages attribute
-    private Set<String> conceals;
+    // the packages in the Packages attribute
+    private Set<String> packages;
 
     // the value of the Version attribute
     private Version version;
@@ -75,10 +75,10 @@
     }
 
     /**
-     * Sets the set of packages for the ConcealedPackages attribute
+     * Sets the set of packages for the Packages attribute
      */
-    public ModuleInfoExtender conceals(Set<String> packages) {
-        this.conceals = Collections.unmodifiableSet(packages);
+    public ModuleInfoExtender packages(Set<String> packages) {
+        this.packages = Collections.unmodifiableSet(packages);
         return this;
     }
 
@@ -181,26 +181,26 @@
 
         ClassReader cr = new ClassReader(in);
 
-        if (conceals != null)
-            cv.addAttribute(new ConcealedPackagesAttribute(conceals));
+        if (packages != null)
+            cv.addAttribute(new ModulePackagesAttribute(packages));
         if (version != null)
-            cv.addAttribute(new VersionAttribute(version));
+            cv.addAttribute(new ModuleVersionAttribute(version));
         if (mainClass != null)
-            cv.addAttribute(new MainClassAttribute(mainClass));
+            cv.addAttribute(new ModuleMainClassAttribute(mainClass));
         if (osName != null || osArch != null || osVersion != null)
-            cv.addAttribute(new TargetPlatformAttribute(osName, osArch, osVersion));
+            cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
         if (hashes != null)
-            cv.addAttribute(new HashesAttribute(hashes));
+            cv.addAttribute(new ModuleHashesAttribute(hashes));
 
         List<Attribute> attrs = new ArrayList<>();
 
         // prototypes of attributes that should be parsed
         attrs.add(new ModuleAttribute());
-        attrs.add(new ConcealedPackagesAttribute());
-        attrs.add(new VersionAttribute());
-        attrs.add(new MainClassAttribute());
-        attrs.add(new TargetPlatformAttribute());
-        attrs.add(new HashesAttribute());
+        attrs.add(new ModulePackagesAttribute());
+        attrs.add(new ModuleVersionAttribute());
+        attrs.add(new ModuleMainClassAttribute());
+        attrs.add(new ModuleTargetAttribute());
+        attrs.add(new ModuleHashesAttribute());
 
         cr.accept(cv, attrs.toArray(new Attribute[0]), 0);
 
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,9 +27,8 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Version;
 import java.nio.ByteBuffer;
-import java.util.Optional;
+import java.util.stream.Stream;
 
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.Opcodes;
@@ -52,31 +51,28 @@
     private static byte[] toModuleInfo(ModuleDescriptor md) {
 
         ClassWriter cw = new ClassWriter(0);
-
-        String name = md.name().replace('.', '/') + "/module-info";
-        cw.visit(Opcodes.V1_9, ACC_MODULE, name, null, null, null);
-
+        cw.visit(Opcodes.V1_9, ACC_MODULE, null, null, null, null);
         cw.visitAttribute(new ModuleAttribute(md));
 
-        // for tests: write the ConcealedPackages attribute when there are non-exported packages
-        long nExportedPackages = md.exports().stream()
-                .map(ModuleDescriptor.Exports::source)
-                .distinct()
-                .count();
-        if (md.packages().size() > nExportedPackages)
-            cw.visitAttribute(new ConcealedPackagesAttribute(md.packages()));
+        // for tests: write the Packages 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()
+                .map(ModuleDescriptor.Opens::source);
+        long exportedOrOpen = Stream.concat(exported, open).distinct().count();
+        if (md.packages().size() > exportedOrOpen)
+            cw.visitAttribute(new ModulePackagesAttribute(md.packages()));
 
-        md.version().ifPresent(v -> cw.visitAttribute(new VersionAttribute(v)));
-        md.mainClass().ifPresent(mc -> cw.visitAttribute(new MainClassAttribute(mc)));
+        md.version().ifPresent(v -> cw.visitAttribute(new ModuleVersionAttribute(v)));
+        md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
 
         // write the TargetPlatform 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);
         if (osName != null || osArch != null || osVersion != null) {
-            cw.visitAttribute(new TargetPlatformAttribute(osName,
-                                                          osArch,
-                                                          osVersion));
+            cw.visitAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
         }
 
         cw.visitEnd();
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Thu Dec 01 21:39:49 2016 +0000
@@ -50,6 +50,7 @@
 import java.util.Set;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import jdk.internal.loader.Resource;
@@ -59,7 +60,7 @@
 
 
 /**
- * Provides support for patching modules in the boot layer with --patch-module.
+ * Provides support for patching modules, mostly the boot layer.
  */
 
 public final class ModulePatcher {
@@ -67,89 +68,46 @@
     private static final JavaLangModuleAccess JLMA
         = SharedSecrets.getJavaLangModuleAccess();
 
-    // the prefix of the system properties that encode the value of --patch-module
-    private static final String PATCH_PROPERTY_PREFIX = "jdk.module.patch.";
-
     // module name -> sequence of patches (directories or JAR files)
-    private static final Map<String, List<Path>> PATCH_MAP = decodeProperties();
-
-    private ModulePatcher() { }
+    private final Map<String, List<Path>> map;
 
     /**
-     * Decodes the values of --patch-module options, returning a Map of module
-     * name to list of file paths.
-     *
-     * @throws IllegalArgumentException if the the module name is missing or
-     *         --patch-module is used more than once to patch the same module
+     * Initialize the module patcher with the given map. The map key is
+     * the module name, the value is a list of path strings.
      */
-    private static Map<String, List<Path>> decodeProperties() {
-
-        int index = 0;
-        String value = getAndRemoveProperty(PATCH_PROPERTY_PREFIX + index);
-        if (value == null)
-            return Collections.emptyMap();  // --patch-module not specified
-
-        Map<String, List<Path>> map = new HashMap<>();
-        while (value != null) {
-
-            // <module>=<file>(:<file>)*
-
-            int pos = value.indexOf('=');
-            if (pos == -1)
-                throwIAE("Unable to parse: " + value);
-            if (pos == 0)
-                throwIAE("Missing module name: " + value);
-
-            String mn = value.substring(0, pos);
-            List<Path> list = map.get(mn);
-            if (list != null)
-                throwIAE("Module " + mn + " specified more than once");
-            list = new ArrayList<>();
-            map.put(mn, list);
-
-            String paths = value.substring(pos+1);
-            for (String path : paths.split(File.pathSeparator)) {
-                if (!path.isEmpty()) {
-                    list.add(Paths.get(path));
-                }
+    public ModulePatcher(Map<String, List<String>> input) {
+        if (input.isEmpty()) {
+            this.map = Collections.emptyMap();
+        } else {
+            Map<String, List<Path>> map = new HashMap<>();
+            for (Map.Entry<String, List<String>> e : input.entrySet()) {
+                String mn = e.getKey();
+                List<Path> paths = e.getValue().stream()
+                        .map(Paths::get)
+                        .collect(Collectors.toList());
+                map.put(mn, paths);
             }
-
-            index++;
-            value = getAndRemoveProperty(PATCH_PROPERTY_PREFIX + index);
+            this.map = map;
         }
-
-        return map;
-    }
-
-
-    /**
-     * Returns {@code true} is --patch-module is specified to patch modules
-     * in the boot layer.
-     */
-    static boolean isBootLayerPatched() {
-        return !PATCH_MAP.isEmpty();
     }
 
     /**
      * Returns a module reference that interposes on the given module if
      * needed. If there are no patches for the given module then the module
      * reference is simply returned. Otherwise the patches for the module
-     * are scanned (to find any new concealed packages) and a new module
-     * reference is returned.
+     * are scanned (to find any new packages) and a new module reference is
+     * returned.
      *
      * @throws UncheckedIOException if an I/O error is detected
      */
-    public static ModuleReference interposeIfNeeded(ModuleReference mref) {
-
+    public ModuleReference patchIfNeeded(ModuleReference mref) {
+        // if there are no patches for the module then nothing to do
         ModuleDescriptor descriptor = mref.descriptor();
         String mn = descriptor.name();
-
-        // if there are no patches for the module then nothing to do
-        List<Path> paths = PATCH_MAP.get(mn);
+        List<Path> paths = map.get(mn);
         if (paths == null)
             return mref;
 
-
         // scan the JAR file or directory tree to get the set of packages
         Set<String> packages = new HashSet<>();
         try {
@@ -197,6 +155,13 @@
 
     }
 
+    /**
+     * Returns true is this module patcher has no patches.
+     */
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
 
     /**
      * A ModuleReader that reads resources from a patched module.
@@ -569,13 +534,6 @@
     }
 
     /**
-     * Gets and remove the named system property
-     */
-    private static String getAndRemoveProperty(String key) {
-        return (String)System.getProperties().remove(key);
-    }
-
-    /**
      * Derives a package name from the name of an entry in a JAR file.
      */
     private static String toPackageName(Path file, JarEntry entry) {
@@ -593,9 +551,4 @@
             System.err.println("WARNING: " + e + " ignored in patch: " + file);
         return "";
     }
-
-    private static void throwIAE(String msg) {
-        throw new IllegalArgumentException(msg);
-    }
-
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,8 +26,11 @@
 package jdk.internal.module;
 
 import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.net.URI;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Set;
 
 import jdk.internal.loader.BootLoader;
@@ -35,7 +38,6 @@
 import jdk.internal.misc.JavaLangReflectModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 
-
 /**
  * A helper class to allow JDK classes create dynamic modules and to update
  * modules, exports and the readability graph. It is also invoked by the VM
@@ -53,7 +55,6 @@
     private static final JavaLangReflectModuleAccess JLRMA
         = SharedSecrets.getJavaLangReflectModuleAccess();
 
-
     /**
      * Creates a new Module. The module has the given ModuleDescriptor and
      * is defined to the given class loader.
@@ -72,7 +73,7 @@
 
     /**
      * Define a new module to the VM. The module has the given set of
-     * concealed packages and is defined to the given class loader.
+     * packages and is defined to the given class loader.
      *
      * The resulting Module is in a larval state in that it does not not read
      * any other module and does not have any exports.
@@ -81,8 +82,9 @@
                                       String name,
                                       Set<String> packages)
     {
-        ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder(name).conceals(packages).build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module(name)
+                .contains(packages)
+                .build();
 
         return JLRMA.defineModule(loader, descriptor, null);
     }
@@ -104,13 +106,21 @@
 
     /**
      * Updates module m1 to export a package to module m2.
-     * Same as m1.addExports(pkg, m2) but without a caller check.
+     * Same as m1.addExports(pn, m2) but without a caller check.
      */
     public static void addExports(Module m1, String pn, Module m2) {
         JLRMA.addExports(m1, pn, m2);
     }
 
     /**
+     * Updates module m1 to open a package to module m2.
+     * Same as m1.addOpens(pn, m2) but without a caller check.
+     */
+    public static void addOpens(Module m1, String pn, Module m2) {
+        JLRMA.addOpens(m1, pn, m2);
+    }
+
+    /**
      * Updates a module m to export a package to all modules.
      */
     public static void addExportsToAll(Module m, String pn) {
@@ -118,6 +128,13 @@
     }
 
     /**
+     * Updates a module m to open a package to all modules.
+     */
+    public static void addOpensToAll(Module m, String pn) {
+        JLRMA.addOpensToAll(m, pn);
+    }
+
+    /**
      * Updates module m to export a package to all unnamed modules.
      */
     public static void addExportsToAllUnnamed(Module m, String pn) {
@@ -125,6 +142,47 @@
     }
 
     /**
+     * Updates module m to open a package to all unnamed modules.
+     */
+    public static void addOpensToAllUnnamed(Module m, String pn) {
+        JLRMA.addOpensToAllUnnamed(m, pn);
+    }
+
+    /**
+     * Updates module m to use a service
+     */
+    public static void addUses(Module m, Class<?> service) {
+        JLRMA.addUses(m, service);
+    }
+
+    /**
+     * Updates module m to provide a service
+     */
+    public static void addProvides(Module m, Class<?> service, Class<?> impl) {
+        Layer layer = m.getLayer();
+
+        if (layer == null || layer == Layer.boot()) {
+            // update ClassLoader catalog
+            PrivilegedAction<ClassLoader> pa = m::getClassLoader;
+            ClassLoader loader = AccessController.doPrivileged(pa);
+            ServicesCatalog catalog;
+            if (loader == null) {
+                catalog = BootLoader.getServicesCatalog();
+            } else {
+                catalog = ServicesCatalog.getServicesCatalog(loader);
+            }
+            catalog.addProvider(m, service, impl);
+        }
+
+        if (layer != null) {
+            // update Layer catalog
+            SharedSecrets.getJavaLangReflectModuleAccess()
+                    .getServicesCatalog(layer)
+                    .addProvider(m, service, impl);
+        }
+    }
+
+    /**
      * Adds a package to a module's content.
      *
      * This method is a no-op if the module already contains the package.
@@ -142,5 +200,4 @@
         addReads(m, BootLoader.getUnnamedModule());
         addReads(m, ClassLoaders.appClassLoader().getUnnamedModule());
     }
-
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,20 +28,24 @@
 import java.lang.reflect.Module;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Provides;
+import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import jdk.internal.loader.ClassLoaderValue;
 
 /**
  * A <em>services catalog</em>. Each {@code ClassLoader} and {@code Layer} has
  * an optional {@code ServicesCatalog} for modules that provide services.
  *
- * @see java.util.ServiceLoader
+ * @apiNote This class will be replaced once the ServiceLoader is further
+ *          specified
  */
-public interface ServicesCatalog {
+public final class ServicesCatalog {
 
     /**
      * Represents a service provider in the services catalog.
@@ -78,56 +82,98 @@
         }
     }
 
-    /**
-     * Registers the providers in the given module in this services catalog.
-     *
-     * @throws UnsupportedOperationException
-     *         If this services catalog is immutable
-     */
-    void register(Module module);
+    // service name -> list of providers
+    private final Map<String, List<ServiceProvider>> map = new ConcurrentHashMap<>();
 
-    /**
-     * Returns the (possibly empty) set of service providers that implement the
-     * given service type.
-     */
-    Set<ServiceProvider> findServices(String service);
+    private ServicesCatalog() { }
 
     /**
      * Creates a ServicesCatalog that supports concurrent registration and
-     * and lookup.
+     * and lookup
+     */
+    public static ServicesCatalog create() {
+        return new ServicesCatalog();
+    }
+
+    /**
+     * Returns the list of service provides for the given service type
+     * name, creating it if needed.
      */
-    static ServicesCatalog create() {
-        return new ServicesCatalog() {
-
-            private Map<String, Set<ServiceProvider>> map = new ConcurrentHashMap<>();
+    private List<ServiceProvider> providers(String service) {
+        // avoid computeIfAbsent here
+        List<ServiceProvider> list = map.get(service);
+        if (list == null) {
+            list = new CopyOnWriteArrayList<>();
+            List<ServiceProvider> prev = map.putIfAbsent(service, list);
+            if (prev != null)
+                list = prev;  // someone else got there
+        }
+        return list;
+    }
 
-            @Override
-            public void register(Module m) {
-                ModuleDescriptor descriptor = m.getDescriptor();
-
-                for (Provides provides : descriptor.provides().values()) {
-                    String service = provides.service();
-                    Set<String> providerNames = provides.providers();
+    /**
+     * Registers the providers in the given module in this services catalog.
+     */
+    public void register(Module module) {
+        ModuleDescriptor descriptor = module.getDescriptor();
+        for (Provides provides : descriptor.provides()) {
+            String service = provides.service();
+            List<String> providerNames = provides.providers();
+            int count = providerNames.size();
+            if (count == 1) {
+                String pn = providerNames.get(0);
+                providers(service).add(new ServiceProvider(module, pn));
+            } else {
+                List<ServiceProvider> list = new ArrayList<>(count);
+                for (String pn : providerNames) {
+                    list.add(new ServiceProvider(module, pn));
+                }
+                providers(service).addAll(list);
+            }
+        }
+    }
 
-                    // create a new set to replace the existing
-                    Set<ServiceProvider> result = new HashSet<>();
-                    Set<ServiceProvider> providers = map.get(service);
-                    if (providers != null) {
-                        result.addAll(providers);
-                    }
-                    for (String pn : providerNames) {
-                        result.add(new ServiceProvider(m, pn));
-                    }
-                    map.put(service, Collections.unmodifiableSet(result));
-                }
+    /**
+     * Add a provider in the given module to this services catalog
+     *
+     * @apiNote This method is for use by java.lang.instrument
+     */
+    public void addProvider(Module module, Class<?> service, Class<?> impl) {
+        List<ServiceProvider> list = providers(service.getName());
+        list.add(new ServiceProvider(module, impl.getName()));
+    }
+
+    /**
+     * Returns the (possibly empty) list of service providers that implement
+     * the given service type.
+     */
+    public List<ServiceProvider> findServices(String service) {
+        return map.getOrDefault(service, Collections.emptyList());
+    }
 
-            }
+    /**
+     * Returns the ServicesCatalog for the given class loader or {@code null}
+     * if there is none.
+     */
+    public static ServicesCatalog getServicesCatalogOrNull(ClassLoader loader) {
+        return CLV.get(loader);
+    }
 
-            @Override
-            public Set<ServiceProvider> findServices(String service) {
-                return map.getOrDefault(service, Collections.emptySet());
-            }
+    /**
+     * Returns the ServicesCatalog for the given class loader, creating it if
+     * needed.
+     */
+    public static ServicesCatalog getServicesCatalog(ClassLoader loader) {
+        // CLV.computeIfAbsent(loader, (cl, clv) -> create());
+        ServicesCatalog catalog = CLV.get(loader);
+        if (catalog == null) {
+            catalog = create();
+            ServicesCatalog previous = CLV.putIfAbsent(loader, catalog);
+            if (previous != null) catalog = previous;
+        }
+        return catalog;
+    }
 
-        };
-    }
+    // the ServicesCatalog registered to a class loader
+    private static final ClassLoaderValue<ServicesCatalog> CLV = new ClassLoaderValue<>();
 }
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Thu Dec 01 21:39:49 2016 +0000
@@ -51,7 +51,7 @@
     /**
      * Hash of system modules.
      */
-    public static String[] MODULES_TO_HASH = new String[0];
+    public static byte[][] MODULES_TO_HASH = new byte[0][];
 
     /**
      * Number of packages in the boot layer from the installed modules.
--- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java	Thu Dec 01 21:39:49 2016 +0000
@@ -695,7 +695,7 @@
             final String[] interfaces) {
         this.version = version;
         this.access = access;
-        this.name = newClass(name);
+        this.name = (name == null) ? 0 : newClass(name);
         thisName = name;
         if (ClassReader.SIGNATURES && signature != null) {
             this.signature = newUTF8(signature);
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Thu Dec 01 21:39:49 2016 +0000
@@ -112,10 +112,13 @@
         }
     }
 
-    private static boolean verifyMemberAccess(Class<?> currentClass,
-                                              Class<?> memberClass,
-                                              Class<?> targetClass,
-                                              int modifiers)
+    /**
+     * Verify access to a member, returning {@code false} if no access
+     */
+    public static boolean verifyMemberAccess(Class<?> currentClass,
+                                             Class<?> memberClass,
+                                             Class<?> targetClass,
+                                             int modifiers)
     {
         // Verify that currentClass can access a field, method, or
         // constructor of memberClass, where that member's access bits are
--- a/jdk/src/java.base/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -115,16 +115,16 @@
     // additional qualified exports may be inserted at build time
     // see make/gensrc/GenModuleInfo.gmk
 
-    // CORBA serialization needs reflective access
-    exports sun.util.calendar to
-        java.corba;
-
     exports com.sun.security.ntlm to
         java.security.sasl;
     exports jdk.internal.jimage to
         jdk.jlink;
     exports jdk.internal.jimage.decompressor to
         jdk.jlink;
+    exports jdk.internal.loader to
+        java.instrument,
+        java.logging,
+        jdk.jlink;
     exports jdk.internal.jmod to
         jdk.compiler,
         jdk.jlink;
@@ -146,9 +146,6 @@
         jdk.scripting.nashorn;
     exports jdk.internal.org.objectweb.asm.signature to
         jdk.scripting.nashorn;
-    exports jdk.internal.loader to
-        java.instrument,
-        java.logging;
     exports jdk.internal.math to
         java.desktop;
     exports jdk.internal.module to
@@ -307,6 +304,7 @@
     // JDK-internal service types
     uses jdk.internal.logger.DefaultLoggerFinder;
     uses sun.security.ssl.ClientKeyExchangeService;
+    uses sun.security.util.AuthResourcesProvider;
     uses sun.util.spi.CalendarProvider;
     uses sun.util.locale.provider.LocaleDataMetaInfo;
     uses sun.util.resources.LocaleData.CommonResourceBundleProvider;
@@ -317,4 +315,6 @@
 
     provides java.nio.file.spi.FileSystemProvider with
         jdk.internal.jrtfs.JrtFileSystemProvider;
+    provides sun.security.util.AuthResourcesProvider with
+        sun.security.util.AuthResourcesProviderImpl;
 }
--- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Thu Dec 01 21:39:49 2016 +0000
@@ -48,6 +48,7 @@
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Method;
@@ -62,24 +63,29 @@
 import java.nio.file.Path;
 import java.text.Normalizer;
 import java.text.MessageFormat;
-import java.util.ResourceBundle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Locale.Category;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Properties;
-import java.util.Map;
+import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.jar.Attributes;
 import java.util.jar.JarFile;
 import java.util.jar.Manifest;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 import jdk.internal.misc.VM;
+import jdk.internal.module.Modules;
 
 
 public final class LauncherHelper {
@@ -95,6 +101,8 @@
     private static final String JAVAFX_FXHELPER_CLASS_NAME_SUFFIX =
             "sun.launcher.LauncherHelper$FXHelper";
     private static final String MAIN_CLASS = "Main-Class";
+    private static final String ADD_EXPORTS = "Add-Exports";
+    private static final String ADD_OPENS = "Add-Opens";
 
     private static StringBuilder outBuf = new StringBuilder();
 
@@ -413,11 +421,23 @@
             if (mainAttrs == null) {
                 abort(null, "java.launcher.jar.error3", jarname);
             }
+
+            // Main-Class
             mainValue = mainAttrs.getValue(MAIN_CLASS);
             if (mainValue == null) {
                 abort(null, "java.launcher.jar.error3", jarname);
             }
 
+            // Add-Exports and Add-Opens to break encapsulation
+            String exports = mainAttrs.getValue(ADD_EXPORTS);
+            if (exports != null) {
+                addExportsOrOpens(exports, false);
+            }
+            String opens = mainAttrs.getValue(ADD_OPENS);
+            if (opens != null) {
+                addExportsOrOpens(opens, true);
+            }
+
             /*
              * Hand off to FXHelper if it detects a JavaFX application
              * This must be done after ensuring a Main-Class entry
@@ -436,6 +456,29 @@
         return null;
     }
 
+    /**
+     * Process the Add-Exports or Add-Opens value. The value is
+     * {@code <module>/<package> ( <module>/<package>)*}.
+     */
+    static void addExportsOrOpens(String value, boolean open) {
+        for (String moduleAndPackage : value.split(" ")) {
+            String[] s = moduleAndPackage.trim().split("/");
+            if (s.length == 2) {
+                String mn = s[0];
+                String pn = s[1];
+                Layer.boot().findModule(mn).ifPresent(m -> {
+                    if (m.getDescriptor().packages().contains(pn)) {
+                        if (open) {
+                            Modules.addOpensToAllUnnamed(m, pn);
+                        } else {
+                            Modules.addExportsToAllUnnamed(m, pn);
+                        }
+                    }
+                });
+            }
+        }
+    }
+
     // From src/share/bin/java.c:
     //   enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR, LM_MODULE }
 
@@ -904,12 +947,26 @@
             for (String name: names) {
                 ModuleReference mref = finder.find(name).orElse(null);
                 if (mref == null) {
-                    // not found
+                    System.err.format("%s not observable!%n", name);
                     continue;
                 }
 
                 ModuleDescriptor md = mref.descriptor();
-                ostream.println(midAndLocation(md, mref.location()));
+                if (md.isOpen())
+                    ostream.print("open ");
+                if (md.isAutomatic())
+                    ostream.print("automatic ");
+                ostream.println("module " + midAndLocation(md, mref.location()));
+
+                // unqualified exports (sorted by package)
+                Set<Exports> exports = new TreeSet<>(Comparator.comparing(Exports::source));
+                md.exports().stream().filter(e -> !e.isQualified()).forEach(exports::add);
+                for (Exports e : exports) {
+                    String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
+                            Stream.of(e.source()))
+                            .collect(Collectors.joining(" "));
+                    ostream.format("  exports %s%n", modsAndSource);
+                }
 
                 for (Requires d : md.requires()) {
                     ostream.format("  requires %s%n", d);
@@ -918,31 +975,51 @@
                     ostream.format("  uses %s%n", s);
                 }
 
-                // sorted exports
-                Set<Exports> exports = new TreeSet<>(Comparator.comparing(Exports::source));
-                exports.addAll(md.exports());
-                for (Exports e : exports) {
-                    ostream.format("  exports %s", e.source());
+                for (Provides ps : md.provides()) {
+                    ostream.format("  provides %s with %s%n", ps.service(),
+                            ps.providers().stream().collect(Collectors.joining(", ")));
+                }
+
+                // qualified exports
+                for (Exports e : md.exports()) {
                     if (e.isQualified()) {
+                        String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
+                                Stream.of(e.source()))
+                                .collect(Collectors.joining(" "));
+                        ostream.format("  exports %s", modsAndSource);
                         formatCommaList(ostream, " to", e.targets());
-                    } else {
-                        ostream.println();
                     }
                 }
 
-                // concealed packages
-                new TreeSet<>(md.conceals())
-                    .forEach(p -> ostream.format("  conceals %s%n", p));
+                // open packages
+                for (Opens obj: md.opens()) {
+                    String modsAndSource = Stream.concat(toStringStream(obj.modifiers()),
+                            Stream.of(obj.source()))
+                            .collect(Collectors.joining(" "));
+                    ostream.format("  opens %s", modsAndSource);
+                    if (obj.isQualified())
+                        formatCommaList(ostream, " to", obj.targets());
+                    else
+                        ostream.println();
+                }
 
-                Map<String, Provides> provides = md.provides();
-                for (Provides ps : provides.values()) {
-                    for (String impl : ps.providers())
-                        ostream.format("  provides %s with %s%n", ps.service(), impl);
-                }
+                // non-exported/non-open packages
+                Set<String> concealed = new TreeSet<>(md.packages());
+                md.exports().stream().map(Exports::source).forEach(concealed::remove);
+                md.opens().stream().map(Opens::source).forEach(concealed::remove);
+                concealed.forEach(p -> ostream.format("  contains %s%n", p));
             }
         }
     }
 
+    static <T> String toString(Set<T> s) {
+        return toStringStream(s).collect(Collectors.joining(" "));
+    }
+
+    static <T> Stream<String> toStringStream(Set<T> s) {
+        return s.stream().map(e -> e.toString().toLowerCase());
+    }
+
     static String midAndLocation(ModuleDescriptor md, Optional<URI> location ) {
         URI loc = location.orElse(null);
         if (loc == null || loc.getScheme().equalsIgnoreCase("jrt"))
--- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -28,8 +28,8 @@
 \           (to execute a class)\n   or  {0} [options] -jar jarfile [args...]\n\
 \           (to execute a jar file)\n\
 \   or  {0} [options] -p <modulepath> -m <modulename>[/<mainclass>] [args...]\n\
-\           (to execute the main class in a module)\n\
-where options include:\n
+\           (to execute the main class in a module)\n\n\
+where options include:\n\n
 
 java.launcher.opt.datamodel  =\    -d{0}\t  Deprecated, will be removed in a future release\n
 java.launcher.opt.vmselect   =\    {0}\t  to select the "{1}" VM\n
@@ -68,11 +68,16 @@
 \                  set a system property\n\
 \    -verbose:[class|gc|jni]\n\
 \                  enable verbose output\n\
-\    -version      print product version and exit\n\
-\    -showversion  print product version and continue\n\
-\    -? -help --help\n\
-\                  print this help message\n\
-\    -X            print help on non-standard options\n\
+\    -version      print product version to the error stream and exit\n\
+\    --version     print product version to the output stream and exit\n\
+\    -showversion  print product version to the error stream and continue\n\
+\    --show-version\n\
+\                  print product version to the output stream and continue\n\
+\    -? -h -help\n\
+\                  print this help message to the error stream\n\
+\    --help        print this help message to the output stream\n\
+\    -X            print help on extra options to the error stream\n\
+\    --help-extra  print help on extra options to the output stream\n\
 \    -ea[:<packagename>...|:<classname>]\n\
 \    -enableassertions[:<packagename>...|:<classname>]\n\
 \                  enable assertions with specified granularity\n\
@@ -98,14 +103,12 @@
 \                  The most appropriate scaled image provided will be picked up\n\
 \                  automatically.\n\
 \                  See the SplashScreen API documentation for more information.\n\
-\    @<filepath>   read options from the specified file\n\
+\    @<filepath>   read options from the specified file\n\n\
 \To specify an argument for a long option, you can use --<name>=<value> or\n\
-\--<name> <value>.\n\
-
-See http://www.oracle.com/technetwork/java/javase/documentation/index.html for more details.
+\--<name> <value>.\n
 
 # Translators please note do not translate the options themselves
-java.launcher.X.usage=\
+java.launcher.X.usage=\n\
 \    -Xbatch           disable background compilation\n\
 \    -Xbootclasspath/a:<directories and zip/jar files separated by {0}>\n\
 \                      append to end of bootstrap class path\n\
@@ -152,10 +155,13 @@
 \                      regardless of module declaration.\n\
 \                      <target-module> can be ALL-UNNAMED to export to all\n\
 \                      unnamed modules.\n\
+\    --add-opens <module>/<package>=<target-module>(,<target-module>)*\n\
+\                      updates <module> to open <package> to\n\
+\                      <target-module>, regardless of module declaration.\n\
 \    --patch-module <module>=<file>({0}<file>)*\n\
 \                      Override or augment a module with classes and resources\n\
 \                      in JAR files or directories.\n\n\
-These options are non-standard and subject to change without notice.\n
+These extra options are subject to change without notice.\n
 
 # Translators please note do not translate the options themselves
 java.launcher.X.macosx.usage=\
--- a/jdk/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/reflect/generics/parser/SignatureParser.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, 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
@@ -64,8 +64,9 @@
     // invalid, the parser should flag an error in accordance
     // with its logic.
 
-    private char[] input; // the input signature
-    private int index = 0; // index into the input
+    private String input; // the input signature
+    private int index;    // index into the input
+    private int mark;     // index of mark
     // used to mark end of input
     private static final char EOI = ':';
     private static final boolean DEBUG = false;
@@ -73,6 +74,12 @@
     // private constructor - enforces use of static factory
     private SignatureParser(){}
 
+    // prepares parser for new parsing session
+    private void init(String s) {
+        input = s;
+        mark = index = 0;
+    }
+
     // Utility methods.
 
     // Most parsing routines use the following routines to access the
@@ -80,39 +87,32 @@
     // This makes it easy to adapt the parser to operate on streams
     // of various kinds as well as strings.
 
-    // returns current element of the input and advances the input
-    private char getNext(){
-        assert(index <= input.length);
-        try {
-            return input[index++];
-        } catch (ArrayIndexOutOfBoundsException e) { return EOI;}
-    }
-
     // returns current element of the input
     private char current(){
-        assert(index <= input.length);
-        try {
-            return input[index];
-        } catch (ArrayIndexOutOfBoundsException e) { return EOI;}
+        assert(index <= input.length());
+        return index < input.length() ? input.charAt(index) : EOI;
     }
 
     // advance the input
     private void advance(){
-        assert(index <= input.length);
-        index++;
+        assert(index <= input.length());
+        if (index < input.length()) index++;
+    }
+
+    // mark current position
+    private void mark() {
+        mark = index;
     }
 
     // For debugging, prints current character to the end of the input.
     private String remainder() {
-        return new String(input, index, input.length-index);
+        return input.substring(index);
     }
 
-    // Match c against a "set" of characters
-    private boolean matches(char c, char... set) {
-        for (char e : set) {
-            if (c == e) return true;
-        }
-        return false;
+    // returns a substring of input from mark (inclusive)
+    // to current position (exclusive)
+    private String markToCurrent() {
+        return input.substring(mark, index);
     }
 
     // Error handling routine. Encapsulates error handling.
@@ -152,7 +152,7 @@
      */
     public ClassSignature parseClassSig(String s) {
         if (DEBUG) System.out.println("Parsing class sig:" + s);
-        input = s.toCharArray();
+        init(s);
         return parseClassSignature();
     }
 
@@ -167,7 +167,7 @@
      */
     public MethodTypeSignature parseMethodSig(String s) {
         if (DEBUG) System.out.println("Parsing method sig:" + s);
-        input = s.toCharArray();
+        init(s);
         return parseMethodTypeSignature();
     }
 
@@ -184,13 +184,13 @@
      */
     public TypeSignature parseTypeSig(String s) {
         if (DEBUG) System.out.println("Parsing type sig:" + s);
-        input = s.toCharArray();
+        init(s);
         return parseTypeSignature();
     }
 
     // Parsing routines.
     // As a rule, the parsing routines access the input using the
-    // utilities current(), getNext() and/or advance().
+    // utilities current() and advance().
     // The convention is that when a parsing routine is invoked
     // it expects the current input to be the first character it should parse
     // and when it completes parsing, it leaves the input at the first
@@ -251,28 +251,22 @@
         return FormalTypeParameter.make(id, bs);
     }
 
-    private String parseIdentifier(){
-        StringBuilder result = new StringBuilder();
-        while (!Character.isWhitespace(current())) {
-            char c = current();
-            switch(c) {
-            case ';':
-            case '.':
-            case '/':
-            case '[':
-            case ':':
-            case '>':
-            case '<':
-                return result.toString();
-            default:{
-                result.append(c);
-                advance();
-            }
+    private String parseIdentifier() {
+        mark();
+        skipIdentifier();
+        return markToCurrent();
+    }
 
-            }
+    private void skipIdentifier() {
+        char c = current();
+        while (c != ';' && c != '.' && c != '/' &&
+               c != '[' && c != ':' && c != '>' &&
+               c != '<' && !Character.isWhitespace(c)) {
+            advance();
+            c = current();
         }
-        return result.toString();
     }
+
     /**
      * FieldTypeSignature:
      *     ClassTypeSignature
@@ -325,18 +319,13 @@
         // Parse both any optional leading PackageSpecifier as well as
         // the following SimpleClassTypeSignature.
 
-        String id = parseIdentifier();
-
-        if (current() == '/') { // package name
-            StringBuilder idBuild = new StringBuilder(id);
-
-            while(current() == '/') {
-                advance();
-                idBuild.append(".");
-                idBuild.append(parseIdentifier());
-            }
-            id = idBuild.toString();
+        mark();
+        skipIdentifier();
+        while (current() == '/') {
+            advance();
+            skipIdentifier();
         }
+        String id = markToCurrent().replace('/', '.');
 
         switch (current()) {
         case ';':
@@ -379,11 +368,6 @@
         }
     }
 
-    private TypeArgument[] parseTypeArgumentsOpt() {
-        if (current() == '<') {return parseTypeArguments();}
-        else {return new TypeArgument[0];}
-    }
-
     /**
      * TypeArguments:
      *     "<" TypeArgument+ ">"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProvider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * 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 sun.security.util;
+
+public interface AuthResourcesProvider extends java.util.spi.ResourceBundleProvider {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/util/AuthResourcesProviderImpl.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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 sun.security.util;
+
+import java.util.spi.AbstractResourceBundleProvider;
+
+public final class AuthResourcesProviderImpl extends AbstractResourceBundleProvider
+       implements AuthResourcesProvider {
+    public AuthResourcesProviderImpl() {
+        super("java.class");
+    }
+}
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +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 sun.util.locale.provider;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Module;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.PropertyResourceBundle;
-import java.util.ResourceBundle;
-
-/**
- * ResourceBundleProviderSupport provides convenience methods for loading
- * resource bundles.
- */
-public class ResourceBundleProviderSupport {
-    /**
-     * Loads a {@code ResourceBundle} of the given {@code bundleName} local to
-     * the given {@code module}.
-     *
-     * @apiNote
-     * {@link Class#forName(Module, String)} does a stack-based permission check.
-     * Caller of this method is responsible for doing an appropriate permission
-     * on behalf of the caller before calling this method.
-     *
-     * @param module     the module from which the {@code ResourceBundle} is loaded
-     * @param bundleName the bundle name for the {@code ResourceBundle} class,
-     *                   such as "com.example.app.MyResources_fr"
-     * @return the {@code ResourceBundle}, or null if no {@code ResourceBundle} is found
-     * @throws SecurityException
-     *         if a security manager exists, it denies loading the class given by
-     *         {@code bundleName} from the given {@code module}.
-     *         If the given module is "java.base", this method will not do security check.
-     * @throws NullPointerException
-     *         if {@code module} or {@code bundleName) is null
-     * @see Class#forName(Module, String)
-     */
-    public static ResourceBundle loadResourceBundle(Module module, String bundleName)
-    {
-        Class<?> c = Class.forName(module, bundleName);
-        if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
-            try {
-                @SuppressWarnings("unchecked")
-                Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
-                Constructor<ResourceBundle> ctor = bundleClass.getConstructor();
-                if (!Modifier.isPublic(ctor.getModifiers())) {
-                    return null;
-                }
-                // java.base may not be able to read the bundleClass's module.
-                PrivilegedAction<Void> pa1 = () -> { ctor.setAccessible(true); return null; };
-                AccessController.doPrivileged(pa1);
-                try {
-                    return ctor.newInstance((Object[]) null);
-                } catch (InvocationTargetException e) {
-                    uncheckedThrow(e);
-                } catch (InstantiationException | IllegalAccessException e) {
-                    throw new InternalError(e);
-                }
-            } catch (NoSuchMethodException e) {
-            }
-        }
-        return null;
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
-       if (t != null)
-            throw (T)t;
-       else
-            throw new Error("Unknown Exception");
-    }
-
-    /**
-     * Loads properties of the given {@code bundleName} local to the given
-     * {@code module} and returns a {@code ResourceBundle} produced from the
-     * loaded properties.
-     *
-     * @apiNote This method is intended for internal use.  Need to refactor.
-     *
-     * @param module     the module from which the properties are loaded
-     * @param bundleName the bundle name of the properties,
-     *                   such as "com.example.app.MyResources_de"
-     * @return the {@code ResourceBundle} produced from the loaded properties,
-     *         or null if no properties are found
-     * @see PropertyResourceBundle
-     */
-    public static ResourceBundle loadPropertyResourceBundle(Module module, String bundleName)
-            throws IOException
-    {
-        String resourceName = toResourceName(bundleName, "properties");
-        if (resourceName == null) {
-            return null;
-        }
-
-        PrivilegedAction<InputStream> pa = () -> {
-            try {
-                return module.getResourceAsStream(resourceName);
-            } catch (IOException e) {
-                throw new UncheckedIOException(e);
-            }
-        };
-        try (InputStream stream = AccessController.doPrivileged(pa)) {
-            if (stream != null) {
-                return new PropertyResourceBundle(stream);
-            } else {
-                return null;
-            }
-        } catch (UncheckedIOException e) {
-            throw e.getCause();
-        }
-    }
-
-    private static String toResourceName(String bundleName, String suffix) {
-        if (bundleName.contains("://")) {
-            return null;
-        }
-        StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
-        sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
-        return sb.toString();
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java	Thu Dec 01 21:39:49 2016 +0000
@@ -58,8 +58,6 @@
 import java.util.spi.ResourceBundleProvider;
 import jdk.internal.misc.JavaUtilResourceBundleAccess;
 import jdk.internal.misc.SharedSecrets;
-import sun.util.locale.provider.ResourceBundleProviderSupport;
-
 
 /**
  */
@@ -203,9 +201,13 @@
                 bundle = loadBundleFromProviders(baseName, targetLocale, providers, cacheKey);
             } else {
                 try {
-                    bundle = ResourceBundleProviderSupport
-                                 .loadResourceBundle(Bundles.class.getModule(),
-                                      strategy.toBundleName(baseName, targetLocale));
+                    String bundleName = strategy.toBundleName(baseName, targetLocale);
+                    Class<?> c = Class.forName(Bundles.class.getModule(), bundleName);
+                    if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
+                        @SuppressWarnings("unchecked")
+                        Class<ResourceBundle> bundleClass = (Class<ResourceBundle>) c;
+                        bundle = bundleAccess.newResourceBundle(bundleClass);
+                    }
                 } catch (Exception e) {
                     cacheKey.setCause(e);
                 }
--- a/jdk/src/java.base/share/native/include/jni.h	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/native/include/jni.h	Thu Dec 01 21:39:49 2016 +0000
@@ -770,12 +770,6 @@
 
     jobject (JNICALL *GetModule)
        (JNIEnv* env, jclass clazz);
-
-    void (JNICALL *AddModuleReads)
-        (JNIEnv* env, jobject m1, jobject m2);
-
-    jboolean (JNICALL *CanReadModule)
-        (JNIEnv* env, jobject m1, jobject m2);
 };
 
 /*
@@ -1874,14 +1868,6 @@
         return functions->GetModule(this, clazz);
     }
 
-    void AddModuleReads(jobject m1, jobject m2) {
-        functions->AddModuleReads(this, m1, m2);
-    }
-
-    jboolean CanReadModule(jobject m1, jobject m2) {
-        return functions->CanReadModule(this, m1, m2);
-    }
-
 #endif /* __cplusplus */
 };
 
--- a/jdk/src/java.base/share/native/include/jvm.h	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/native/include/jvm.h	Thu Dec 01 21:39:49 2016 +0000
@@ -402,8 +402,8 @@
  */
 
 JNIEXPORT void JNICALL
-JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location,
-                 jobjectArray packages);
+JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version,
+                 jstring location, jobjectArray packages);
 
 JNIEXPORT void JNICALL
 JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module);
@@ -411,9 +411,6 @@
 JNIEXPORT void JNICALL
 JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject to_module);
 
-JNIEXPORT jboolean JNICALL
-JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module);
-
 JNIEXPORT void JNICALL
 JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module);
 
@@ -423,9 +420,6 @@
 JNIEXPORT void JNICALL
 JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package);
 
-JNIEXPORT jboolean JNICALL
-JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module);
-
 JNIEXPORT void JNICALL
 JVM_AddModulePackage(JNIEnv* env,  jobject module, jstring package);
 
--- a/jdk/src/java.base/share/native/libjava/Module.c	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/native/libjava/Module.c	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
 
 JNIEXPORT void JNICALL
 Java_java_lang_reflect_Module_defineModule0(JNIEnv *env, jclass cls, jobject module,
-                                            jstring version, jstring location,
-                                            jobjectArray packages)
+                                            jboolean is_open, jstring version,
+                                            jstring location, jobjectArray packages)
 {
-    JVM_DefineModule(env, module, version, location, packages);
+    JVM_DefineModule(env, module, is_open, version, location, packages);
 }
 
 JNIEXPORT void JNICALL
--- a/jdk/src/java.base/share/native/libjli/java.c	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/native/libjli/java.c	Thu Dec 01 21:39:49 2016 +0000
@@ -61,12 +61,13 @@
  * interfaces.
  */
 
-/* we always print to stderr */
-#define USE_STDERR JNI_TRUE
+#define USE_STDERR JNI_TRUE     /* we usually print to stderr */
+#define USE_STDOUT JNI_FALSE
 
 static jboolean printVersion = JNI_FALSE; /* print and exit */
 static jboolean showVersion = JNI_FALSE;  /* print but continue */
 static jboolean printUsage = JNI_FALSE;   /* print and exit*/
+static jboolean printTo = USE_STDERR;     /* where to print version/usage */
 static jboolean printXUsage = JNI_FALSE;  /* print and exit*/
 static jboolean dryRun = JNI_FALSE;       /* initialize VM and exit */
 static char     *showSettings = NULL;     /* print but continue */
@@ -567,6 +568,7 @@
            JLI_StrCmp(name, "--add-modules") == 0 ||
            JLI_StrCmp(name, "--limit-modules") == 0 ||
            JLI_StrCmp(name, "--add-exports") == 0 ||
+           JLI_StrCmp(name, "--add-opens") == 0 ||
            JLI_StrCmp(name, "--add-reads") == 0 ||
            JLI_StrCmp(name, "--patch-module") == 0;
 }
@@ -758,12 +760,15 @@
 
             if (*arg != '-'
                     || JLI_StrCmp(arg, "-version") == 0
+                    || JLI_StrCmp(arg, "--version") == 0
                     || JLI_StrCmp(arg, "-fullversion") == 0
+                    || JLI_StrCmp(arg, "--full-version") == 0
                     || JLI_StrCmp(arg, "-help") == 0
                     || JLI_StrCmp(arg, "--help") == 0
                     || JLI_StrCmp(arg, "-?") == 0
                     || JLI_StrCmp(arg, "-jar") == 0
-                    || JLI_StrCmp(arg, "-X") == 0) {
+                    || JLI_StrCmp(arg, "-X") == 0
+                    || JLI_StrCmp(arg, "--help-extra") == 0) {
                 return;
             }
         }
@@ -1288,6 +1293,7 @@
             } else if (JLI_StrCmp(arg, "--add-modules") == 0 ||
                        JLI_StrCmp(arg, "--limit-modules") == 0 ||
                        JLI_StrCmp(arg, "--add-exports") == 0 ||
+                       JLI_StrCmp(arg, "--add-opens") == 0 ||
                        JLI_StrCmp(arg, "--add-reads") == 0 ||
                        JLI_StrCmp(arg, "--patch-module") == 0) {
                 REPORT_ERROR (has_arg, ARG_ERROR6, arg);
@@ -1295,22 +1301,36 @@
 /*
  * The following cases will cause the argument parsing to stop
  */
-        } else if (JLI_StrCmp(arg, "--help") == 0 ||
-                   JLI_StrCmp(arg, "-help") == 0 ||
+        } else if (JLI_StrCmp(arg, "-help") == 0 ||
                    JLI_StrCmp(arg, "-h") == 0 ||
                    JLI_StrCmp(arg, "-?") == 0) {
             printUsage = JNI_TRUE;
             return JNI_TRUE;
+        } else if (JLI_StrCmp(arg, "--help") == 0) {
+            printUsage = JNI_TRUE;
+            printTo = USE_STDOUT;
+            return JNI_TRUE;
         } else if (JLI_StrCmp(arg, "-version") == 0) {
             printVersion = JNI_TRUE;
             return JNI_TRUE;
+        } else if (JLI_StrCmp(arg, "--version") == 0) {
+            printVersion = JNI_TRUE;
+            printTo = USE_STDOUT;
+            return JNI_TRUE;
         } else if (JLI_StrCmp(arg, "-showversion") == 0) {
             showVersion = JNI_TRUE;
+        } else if (JLI_StrCmp(arg, "--show-version") == 0) {
+            showVersion = JNI_TRUE;
+            printTo = USE_STDOUT;
         } else if (JLI_StrCmp(arg, "--dry-run") == 0) {
             dryRun = JNI_TRUE;
         } else if (JLI_StrCmp(arg, "-X") == 0) {
             printXUsage = JNI_TRUE;
             return JNI_TRUE;
+        } else if (JLI_StrCmp(arg, "--help-extra") == 0) {
+            printXUsage = JNI_TRUE;
+            printTo = USE_STDOUT;
+            return JNI_TRUE;
 /*
  * The following case checks for -XshowSettings OR -XshowSetting:SUBOPT.
  * In the latter case, any SUBOPT value not recognized will default to "all"
@@ -1330,6 +1350,9 @@
         } else if (JLI_StrCmp(arg, "-fullversion") == 0) {
             JLI_ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion());
             return JNI_FALSE;
+        } else if (JLI_StrCmp(arg, "--full-version") == 0) {
+            JLI_ShowMessage("%s %s", _launcher_name, GetFullVersion());
+            return JNI_FALSE;
         } else if (JLI_StrCmp(arg, "-verbosegc") == 0) {
             AddOption("-verbose:gc", NULL);
         } else if (JLI_StrCmp(arg, "-t") == 0) {
@@ -1752,11 +1775,11 @@
     NULL_CHECK(print = (*env)->GetStaticMethodID(env,
                                                  ver,
                                                  (extraLF == JNI_TRUE) ? "println" : "print",
-                                                 "()V"
+                                                 "(Z)V"
                                                  )
               );
 
-    (*env)->CallStaticVoidMethod(env, ver, print);
+    (*env)->CallStaticVoidMethod(env, ver, print, printTo);
 }
 
 /*
@@ -1794,7 +1817,7 @@
             "listModules", "(ZLjava/lang/String;)V"));
     NULL_CHECK(joptString = (*env)->NewStringUTF(env, optString));
     (*env)->CallStaticVoidMethod(env, cls, listModulesID,
-                                 USE_STDERR,
+                                 USE_STDOUT,
                                  joptString);
 }
 
@@ -1812,7 +1835,7 @@
   if (doXUsage) {
     NULL_CHECK(printXUsageMessage = (*env)->GetStaticMethodID(env, cls,
                                         "printXUsageMessage", "(Z)V"));
-    (*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, USE_STDERR);
+    (*env)->CallStaticVoidMethod(env, cls, printXUsageMessage, printTo);
   } else {
     NULL_CHECK(initHelp = (*env)->GetStaticMethodID(env, cls,
                                         "initHelpMessage", "(Ljava/lang/String;)V"));
@@ -1853,7 +1876,7 @@
     }
 
     /* Complete the usage message and print to stderr*/
-    (*env)->CallStaticVoidMethod(env, cls, printHelp, USE_STDERR);
+    (*env)->CallStaticVoidMethod(env, cls, printHelp, printTo);
   }
   return;
 }
@@ -2255,3 +2278,16 @@
     fprintf(stderr, "\n");
     va_end(vl);
 }
+
+/*
+ * A utility procedure to always print to stdout
+ */
+void
+JLI_ShowMessage(const char* fmt, ...)
+{
+    va_list vl;
+    va_start(vl, fmt);
+    vfprintf(stdout, fmt, vl);
+    fprintf(stdout, "\n");
+    va_end(vl);
+}
--- a/jdk/src/java.base/share/native/libjli/java.h	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.base/share/native/libjli/java.h	Thu Dec 01 21:39:49 2016 +0000
@@ -140,6 +140,9 @@
 /* Reports an error message only to stderr. */
 void JLI_ReportMessage(const char * message, ...);
 
+/* Reports a message only to stdout. */
+void JLI_ShowMessage(const char * message, ...);
+
 /*
  * Reports an exception which terminates the vm to stderr or a window
  * as appropriate.
--- a/jdk/src/java.compact1/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.compact1/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,7 +27,7 @@
  * Aggregates {@code java.base}, {@code java.logging}, and {@code java.scripting}.
  */
 module java.compact1 {
-    requires public java.logging;
-    requires public java.scripting;
+    requires transitive java.logging;
+    requires transitive java.scripting;
 }
 
--- a/jdk/src/java.compact2/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.compact2/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,9 +27,9 @@
  * Supplements {@code java.compact1} with JDBC, JAXP, and RMI.
  */
 module java.compact2 {
-    requires public java.compact1;
-    requires public java.rmi;
-    requires public java.sql;
-    requires public java.xml;
+    requires transitive java.compact1;
+    requires transitive java.rmi;
+    requires transitive java.sql;
+    requires transitive java.xml;
 }
 
--- a/jdk/src/java.compact3/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.compact3/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,15 +28,15 @@
  * Instrumentation, Preferences, Security, and XML cryptography APIs.
  */
 module java.compact3 {
-    requires public java.compact2;
-    requires public java.compiler;
-    requires public java.instrument;
-    requires public java.management;
-    requires public java.naming;
-    requires public java.prefs;
-    requires public java.security.jgss;
-    requires public java.security.sasl;
-    requires public java.sql.rowset;
-    requires public java.xml.crypto;
+    requires transitive java.compact2;
+    requires transitive java.compiler;
+    requires transitive java.instrument;
+    requires transitive java.management;
+    requires transitive java.naming;
+    requires transitive java.prefs;
+    requires transitive java.security.jgss;
+    requires transitive java.security.sasl;
+    requires transitive java.sql.rowset;
+    requires transitive java.xml.crypto;
 }
 
--- a/jdk/src/java.desktop/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.desktop/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,8 +28,8 @@
  * accessibility, audio, imaging, printing, and JavaBeans.
  */
 module java.desktop {
-    requires public java.datatransfer;
-    requires public java.xml;
+    requires transitive java.datatransfer;
+    requires transitive java.xml;
     requires java.prefs;
 
     exports java.applet;
@@ -91,6 +91,11 @@
     exports com.sun.awt to
         jdk.desktop;
 
+    opens javax.swing.plaf.basic to
+        jdk.jconsole;
+    opens com.sun.java.swing.plaf.windows to
+        jdk.jconsole;
+
     uses java.awt.im.spi.InputMethodDescriptor;
     uses javax.accessibility.AccessibilityProvider;
     uses javax.imageio.spi.ImageInputStreamSpi;
@@ -113,31 +118,44 @@
     provides java.net.ContentHandlerFactory with sun.awt.www.content.MultimediaContentHandlers;
     provides javax.print.PrintServiceLookup with sun.print.PrintServiceLookupProvider;
     provides javax.print.StreamPrintServiceFactory with sun.print.PSStreamPrinterFactory;
-    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiInDeviceProvider;
-    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiOutDeviceProvider;
-    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.RealTimeSequencerProvider;
-    provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.SoftProvider;
+
+    provides javax.sound.midi.spi.MidiDeviceProvider with
+        com.sun.media.sound.MidiInDeviceProvider,
+        com.sun.media.sound.MidiOutDeviceProvider,
+        com.sun.media.sound.RealTimeSequencerProvider,
+        com.sun.media.sound.SoftProvider;
+
     provides javax.sound.midi.spi.MidiFileReader with com.sun.media.sound.StandardMidiFileReader;
     provides javax.sound.midi.spi.MidiFileWriter with com.sun.media.sound.StandardMidiFileWriter;
-    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.AudioFileSoundbankReader;
-    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.DLSSoundbankReader;
-    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.JARSoundbankReader;
-    provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.SF2SoundbankReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AiffFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AuFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.SoftMidiAudioFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFloatFileReader;
-    provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveExtensibleFileReader;
-    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AiffFileWriter;
-    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AuFileWriter;
-    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFileWriter;
-    provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFloatFileWriter;
-    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AlawCodec;
-    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AudioFloatFormatConverter;
-    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.PCMtoPCMCodec;
-    provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.UlawCodec;
-    provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.DirectAudioDeviceProvider;
-    provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.PortMixerProvider;
+
+    provides javax.sound.midi.spi.SoundbankReader with
+         com.sun.media.sound.AudioFileSoundbankReader,
+         com.sun.media.sound.DLSSoundbankReader,
+         com.sun.media.sound.JARSoundbankReader,
+         com.sun.media.sound.SF2SoundbankReader;
+
+    provides javax.sound.sampled.spi.AudioFileReader with
+        com.sun.media.sound.AiffFileReader,
+        com.sun.media.sound.AuFileReader,
+        com.sun.media.sound.SoftMidiAudioFileReader,
+        com.sun.media.sound.WaveFileReader,
+        com.sun.media.sound.WaveFloatFileReader,
+        com.sun.media.sound.WaveExtensibleFileReader;
+
+    provides javax.sound.sampled.spi.AudioFileWriter with
+        com.sun.media.sound.AiffFileWriter,
+        com.sun.media.sound.AuFileWriter,
+        com.sun.media.sound.WaveFileWriter,
+        com.sun.media.sound.WaveFloatFileWriter;
+
+    provides javax.sound.sampled.spi.FormatConversionProvider with
+        com.sun.media.sound.AlawCodec,
+        com.sun.media.sound.AudioFloatFormatConverter,
+        com.sun.media.sound.PCMtoPCMCodec,
+        com.sun.media.sound.UlawCodec;
+
+    provides javax.sound.sampled.spi.MixerProvider with
+        com.sun.media.sound.DirectAudioDeviceProvider,
+        com.sun.media.sound.PortMixerProvider;
 }
 
--- a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,6 +27,9 @@
 
 import java.lang.reflect.Module;
 import java.security.ProtectionDomain;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.jar.JarFile;
 
 /*
@@ -660,19 +663,62 @@
     setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
 
     /**
-     * Updates a module to read another module.
+     * Redefine a module to expand the set of modules that it reads, the set of
+     * packages that it exports or opens, or the services that it uses or
+     * provides. This method facilitates the instrumentation of code in named
+     * modules where that instrumentation requires changes to the set of modules
+     * that are read, the packages that are exported or open, or the services
+     * that are used or provided.
+     *
+     * <p> This method cannot reduce the set of modules that a module reads, nor
+     * reduce the set of packages that it exports or opens, nor reduce the set
+     * of services that it uses or provides. This method is a no-op when invoked
+     * to redefine an unnamed module. </p>
      *
-     * Agents that instrument code in named modules may need to arrange for the
-     * modules to read other modules. This method is equivalent to code in {@code
-     * module} calling {@link Module#addReads(Module) addReads} to read {@code
-     * other}.
+     * <p> When expanding the services that a module uses or provides then the
+     * onus is on the agent to ensure that the service type will be accessible at
+     * each instrumentation site where the service type is used. This method
+     * does not check if the service type is a member of the module or in a
+     * package exported to the module by another module that it reads. </p>
+     *
+     * <p> The {@code extraExports} parameter is the map of additional packages
+     * to export. The {@code extraOpens} parameter is the map of additional
+     * packages to open. In both cases, the map key is the fully-qualified name
+     * of the package as defined in section 6.5.3 of
+     * <cite>The Java&trade; Language Specification </cite>, for example, {@code
+     * "java.lang"}. The map value is the non-empty set of modules that the
+     * package should be exported or opened to. </p>
      *
-     * @param module the module to update
-     * @param other the module to read
-     * @throws NullPointerException if either module is {@code null}
+     * <p> The {@code extraProvides} parameter is the additional service providers
+     * for the module to provide. The map key is the service type. The map value
+     * is the non-empty list of implementation types, each of which is a member
+     * of the module and an implementation of the service. </p>
+     *
+     * <p> This method is safe for concurrent use and so allows multiple agents
+     * to instrument and update the same module at around the same time. </p>
      *
+     * @param module the module to redefine
+     * @param extraReads the possibly-empty set of additional modules to read
+     * @param extraExports the possibly-empty map of additional packages to export
+     * @param extraOpens the possibly-empty map of additional packages to open
+     * @param extraUses the possibly-empty set of additional services to use
+     * @param extraProvides the possibly-empty map of additional services to provide
+     *
+     * @throws IllegalArgumentException
+     *         If {@code extraExports} or {@code extraOpens} contains a key
+     *         that is not a package in the module; if {@code extraExports} or
+     *         {@code extraOpens} maps a key to an empty set; if a value in the
+     *         {@code extraProvides} map contains a service provider type that
+     *         is not a member of the module or an implementation of the service;
+     *         or {@code extraProvides} maps a key to an empty list
+     * @throws NullPointerException if any of the arguments are {@code null} or
+     *         any of the Sets or Maps contains a {@code null} key or value
      * @since 9
-     * @see Module#canRead(Module)
      */
-    void addModuleReads(Module module, Module other);
+    void redefineModule(Module module,
+                        Set<Module> extraReads,
+                        Map<String, Set<Module>> extraExports,
+                        Map<String, Set<Module>> extraOpens,
+                        Set<Class<?>> extraUses,
+                        Map<Class<?>, List<Class<?>>> extraProvides);
 }
--- a/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html	Thu Dec 01 21:39:49 2016 +0000
@@ -277,15 +277,6 @@
 
 <h3>Instrumenting code in modules</h3>
 
-Agents that instrument code in named modules may need to arrange for the
-modules to read other modules. If code is instrumented to invoke a method
-in a support class in another module, then the module of the instrumented
-code should read the module of the supporting class. Furthermore, the
-supporting class will only be accessible to the instrumented code if
-it is <code>public</code> and in a package that is exported by its module.
-Agents can use {@link Instrumentation#addModuleReads addModuleReads} to update
-a module to read another.
-<p>
 As an aid to agents that deploy supporting classes on the search path of the
 bootstrap class loader, or the search path of the class loader that loads
 the main agent class, the Java virtual machine arranges for the module of
--- a/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,17 +29,22 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Module;
 import java.lang.reflect.AccessibleObject;
-
 import java.lang.instrument.ClassFileTransformer;
 import java.lang.instrument.ClassDefinition;
 import java.lang.instrument.Instrumentation;
-
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
+import java.util.Collections;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarFile;
 
-import java.util.Objects;
-import java.util.jar.JarFile;
+import jdk.internal.module.Modules;
 
 /*
  * Copyright 2003 Wily Technology, Inc.
@@ -228,10 +233,100 @@
     }
 
     @Override
-    public void addModuleReads(Module module, Module other) {
-        Objects.requireNonNull(module);
-        Objects.requireNonNull(other);
-        jdk.internal.module.Modules.addReads(module, other);
+    public void redefineModule(Module module,
+                               Set<Module> extraReads,
+                               Map<String, Set<Module>> extraExports,
+                               Map<String, Set<Module>> extraOpens,
+                               Set<Class<?>> extraUses,
+                               Map<Class<?>, List<Class<?>>> extraProvides)
+    {
+        if (!module.isNamed())
+            return;
+
+        // copy and check reads
+        extraReads = new HashSet<>(extraReads);
+        if (extraReads.contains(null))
+            throw new NullPointerException("'extraReads' contains null");
+
+        // copy and check exports and opens
+        extraExports = cloneAndCheckMap(module, extraExports);
+        extraOpens = cloneAndCheckMap(module, extraOpens);
+
+        // copy and check uses
+        extraUses = new HashSet<>(extraUses);
+        if (extraUses.contains(null))
+            throw new NullPointerException("'extraUses' contains null");
+
+        // copy and check provides
+        Map<Class<?>, List<Class<?>>> tmpProvides = new HashMap<>();
+        for (Map.Entry<Class<?>, List<Class<?>>> e : extraProvides.entrySet()) {
+            Class<?> service = e.getKey();
+            if (service == null)
+                throw new NullPointerException("'extraProvides' contains null");
+            List<Class<?>> providers = new ArrayList<>(e.getValue());
+            if (providers.isEmpty())
+                throw new IllegalArgumentException("list of providers is empty");
+            providers.forEach(p -> {
+                if (p.getModule() != module)
+                    throw new IllegalArgumentException(p + " not in " + module);
+                if (!service.isAssignableFrom(p))
+                    throw new IllegalArgumentException(p + " is not a " + service);
+            });
+            tmpProvides.put(service, providers);
+        }
+        extraProvides = tmpProvides;
+
+
+        // update reads
+        extraReads.forEach(m -> Modules.addReads(module, m));
+
+        // update exports
+        for (Map.Entry<String, Set<Module>> e : extraExports.entrySet()) {
+            String pkg = e.getKey();
+            Set<Module> targets = e.getValue();
+            targets.forEach(m -> Modules.addExports(module, pkg, m));
+        }
+
+        // update opens
+        for (Map.Entry<String, Set<Module>> e : extraOpens.entrySet()) {
+            String pkg = e.getKey();
+            Set<Module> targets = e.getValue();
+            targets.forEach(m -> Modules.addOpens(module, pkg, m));
+        }
+
+        // update uses
+        extraUses.forEach(service -> Modules.addUses(module, service));
+
+        // update provides
+        for (Map.Entry<Class<?>, List<Class<?>>> e : extraProvides.entrySet()) {
+            Class<?> service = e.getKey();
+            List<Class<?>> providers = e.getValue();
+            providers.forEach(p -> Modules.addProvides(module, service, p));
+        }
+    }
+
+    private Map<String, Set<Module>>
+        cloneAndCheckMap(Module module, Map<String, Set<Module>> map)
+    {
+        if (map.isEmpty())
+            return Collections.emptyMap();
+
+        Map<String, Set<Module>> result = new HashMap<>();
+        Set<String> packages = Set.of(module.getPackages());
+        for (Map.Entry<String, Set<Module>> e : map.entrySet()) {
+            String pkg = e.getKey();
+            if (pkg == null)
+                throw new NullPointerException("package cannot be null");
+            if (!packages.contains(pkg))
+                throw new IllegalArgumentException(pkg + " not in module");
+            Set<Module> targets = new HashSet<>(e.getValue());
+            if (targets.isEmpty())
+                throw new IllegalArgumentException("set of targets is empty");
+            if (targets.contains(null))
+                throw new NullPointerException("set of targets cannot include null");
+            result.put(pkg, targets);
+        }
+        return result;
     }
 
 
--- a/jdk/src/java.logging/share/classes/java/util/logging/Level.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.logging/share/classes/java/util/logging/Level.java	Thu Dec 01 21:39:49 2016 +0000
@@ -40,6 +40,8 @@
 import java.util.ResourceBundle;
 import java.util.function.Function;
 import jdk.internal.loader.ClassLoaderValue;
+import jdk.internal.misc.JavaUtilResourceBundleAccess;
+import jdk.internal.misc.SharedSecrets;
 
 /**
  * The Level class defines a set of standard logging levels that
@@ -74,7 +76,11 @@
  */
 
 public class Level implements java.io.Serializable {
-    private static final String defaultBundle = "sun.util.logging.resources.logging";
+    private static final String defaultBundle =
+        "sun.util.logging.resources.logging";
+
+    private static final JavaUtilResourceBundleAccess RB_ACCESS =
+        SharedSecrets.getJavaUtilResourceBundleAccess();
 
     /**
      * @serial  The non-localized name of the level.
@@ -280,7 +286,7 @@
         // or its defining class loader, if it's unnamed module,
         // of this Level instance that can be a custom Level subclass;
         Module module = this.getClass().getModule();
-        ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName,
+        ResourceBundle rb = RB_ACCESS.getBundle(resourceBundleName,
                 newLocale, module);
 
         final String localizedName = rb.getString(name);
--- a/jdk/src/java.logging/share/classes/java/util/logging/Logger.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.logging/share/classes/java/util/logging/Logger.java	Thu Dec 01 21:39:49 2016 +0000
@@ -38,6 +38,9 @@
 import java.util.ResourceBundle;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Supplier;
+
+import jdk.internal.misc.JavaUtilResourceBundleAccess;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import static jdk.internal.logger.DefaultLoggerFinder.isSystem;
@@ -256,8 +259,8 @@
     private static final LoggerBundle NO_RESOURCE_BUNDLE =
             new LoggerBundle(null, null);
 
-    private static final RuntimePermission GET_CLASS_LOADER_PERMISSION =
-            new RuntimePermission("getClassLoader");
+    private static final JavaUtilResourceBundleAccess RB_ACCESS =
+            SharedSecrets.getJavaUtilResourceBundleAccess();
 
     // A value class that holds the logger configuration data.
     // This configuration can be shared between an application logger
@@ -2180,9 +2183,7 @@
         if (!useCallersModule || callerModule == null || !callerModule.isNamed()) {
             try {
                 Module mod = cl.getUnnamedModule();
-                PrivilegedAction<ResourceBundle> pa = () ->
-                    ResourceBundle.getBundle(name, currentLocale, mod);
-                catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION);
+                catalog = RB_ACCESS.getBundle(name, currentLocale, mod);
                 catalogName = name;
                 catalogLocale = currentLocale;
                 return catalog;
@@ -2226,9 +2227,7 @@
             // Try with the caller's module
             try {
                 // Use the caller's module
-                PrivilegedAction<ResourceBundle> pa = () ->
-                    ResourceBundle.getBundle(name, currentLocale, callerModule);
-                catalog = AccessController.doPrivileged(pa, null, GET_CLASS_LOADER_PERMISSION);
+                catalog = RB_ACCESS.getBundle(name, currentLocale, callerModule);
                 catalogName = name;
                 catalogLocale = currentLocale;
                 return catalog;
--- a/jdk/src/java.management/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.management/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,7 +30,7 @@
  * JVM and other components in the Java runtime.
  */
 module java.management {
-    requires public java.rmi;
+    requires transitive java.rmi;
     requires java.logging;
     requires java.naming;
 
--- a/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.management/share/classes/sun/management/MappedMXBeanType.java	Thu Dec 01 21:39:49 2016 +0000
@@ -625,26 +625,6 @@
                 // that has no from method to be embeded in another class.
             }
 
-            // check if a static "toCompositeData" method exists
-            try {
-                toMethod = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
-                    public Method run() throws NoSuchMethodException {
-                        Method m = javaClass.getDeclaredMethod("toCompositeData", javaClass);
-                        if (m != null
-                                && CompositeData.class.isAssignableFrom(m.getReturnType())
-                                && Modifier.isStatic(m.getModifiers())) {
-                            m.setAccessible(true);
-                            return m;
-                        } else {
-                            return null;
-                        }
-                    }
-                });
-            } catch (PrivilegedActionException e) {
-                // ignore NoSuchMethodException since we allow classes
-                // that has no from method to be embeded in another class.
-            }
-
             if (COMPOSITE_DATA_CLASS.isAssignableFrom(c)) {
                 // c implements CompositeData - set openType to null
                 // defer generating the CompositeType
--- a/jdk/src/java.se.ee/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.se.ee/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,16 +29,17 @@
  * This module requires {@code java.se} and supplements it with modules
  * that define CORBA and Java EE APIs. These modules are upgradeable.
  */
+@SuppressWarnings("deprecation")
 module java.se.ee {
 
-    requires public java.se;
+    requires transitive java.se;
 
     // Upgradeable modules for Java EE technologies
-    requires public java.activation;
-    requires public java.annotations.common;
-    requires public java.corba;
-    requires public java.transaction;
-    requires public java.xml.bind;
-    requires public java.xml.ws;
+    requires transitive java.activation;
+    requires transitive java.annotations.common;
+    requires transitive java.corba;
+    requires transitive java.transaction;
+    requires transitive java.xml.bind;
+    requires transitive java.xml.ws;
 
 }
--- a/jdk/src/java.se/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.se/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -31,8 +31,8 @@
  * required by {@code java.se.ee}.
  */
 module java.se {
-    requires public java.compact3;
-    requires public java.datatransfer;
-    requires public java.desktop;
-    requires public java.httpclient;
+    requires transitive java.compact3;
+    requires transitive java.datatransfer;
+    requires transitive java.desktop;
+    requires transitive java.httpclient;
 }
--- a/jdk/src/java.sql.rowset/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.sql.rowset/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,9 +27,9 @@
  * Defines the JDBC RowSet API.
  */
 module java.sql.rowset {
-    requires public java.logging;
-    requires public java.naming;
-    requires public java.sql;
+    requires transitive java.logging;
+    requires transitive java.naming;
+    requires transitive java.sql;
 
     exports javax.sql.rowset;
     exports javax.sql.rowset.serial;
--- a/jdk/src/java.sql/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.sql/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,8 +27,8 @@
  * Defines the JDBC API.
  */
 module java.sql {
-    requires public java.logging;
-    requires public java.xml;
+    requires transitive java.logging;
+    requires transitive java.xml;
 
     exports java.sql;
     exports javax.sql;
--- a/jdk/src/java.transaction/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.transaction/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,7 +30,7 @@
  * exceptions by the 'Java Language to IDL Mapping Specification'.
  */
 module java.transaction {
-    requires public java.rmi;
+    requires transitive java.rmi;
     exports javax.transaction;
 }
 
--- a/jdk/src/java.xml.crypto/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/java.xml.crypto/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,7 +27,7 @@
  * Defines an API for XML cryptography.
  */
 module java.xml.crypto {
-    requires public java.xml;
+    requires transitive java.xml;
     requires java.logging;
 
     exports javax.xml.crypto;
--- a/jdk/src/jdk.accessibility/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.accessibility/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,7 @@
  */
 
 module jdk.accessibility {
-    requires public java.desktop;
+    requires transitive java.desktop;
     exports com.sun.java.accessibility.util;
 }
 
--- a/jdk/src/jdk.attach/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.attach/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Defines the attach API.
+ */
 module jdk.attach {
     requires jdk.jvmstat;
 
--- a/jdk/src/jdk.desktop/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.desktop/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,7 +28,7 @@
  */
 
 module jdk.desktop {
-    requires public java.desktop;
+    requires transitive java.desktop;
 
     exports jdk.awt;
 }
--- a/jdk/src/jdk.internal.le/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.internal.le/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Internal API for line editing
+ */
 module jdk.internal.le {
     exports jdk.internal.jline to
         jdk.scripting.nashorn.shell,
--- a/jdk/src/jdk.internal.opt/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.internal.opt/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Internal option processing API
+ */
 module jdk.internal.opt {
     exports jdk.internal.joptsimple to jdk.jlink, jdk.jshell;
 }
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,6 +30,7 @@
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Version;
 import java.lang.module.ModuleFinder;
@@ -58,6 +59,7 @@
 
 import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Checks;
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleInfoExtender;
 import jdk.internal.util.jar.JarIndex;
@@ -80,7 +82,7 @@
     String fname, mname, ename;
     String zname = "";
     String rootjar = null;
-    Set<String> concealedPackages = new HashSet<>();
+    Set<String> concealedPackages = new HashSet<>(); // used by Validator
 
     private static final int BASE_VERSION = 0;
 
@@ -90,6 +92,13 @@
         final File file;
         final boolean isDir;
 
+        Entry(File file, String basename, String entryname) {
+            this.file = file;
+            this.isDir = file.isDirectory();
+            this.basename = basename;
+            this.entryname = entryname;
+        }
+
         Entry(int version, File file) {
             this.file = file;
             String path = file.getPath();
@@ -105,6 +114,21 @@
             entryname = en.entryName;
         }
 
+        /**
+         * Returns a new Entry that trims the versions directory.
+         *
+         * This entry should be a valid entry matching the given version.
+         */
+        Entry toVersionedEntry(int version) {
+            assert isValidVersionedEntry(this, version);
+
+            if (version == BASE_VERSION)
+                return this;
+
+            EntryName en = new EntryName(trimVersionsDir(basename, version), version);
+            return new Entry(this.file, en.baseName, en.entryName);
+        }
+
         @Override
         public boolean equals(Object o) {
             if (this == o) return true;
@@ -488,7 +512,9 @@
             } else if (printModuleDescriptor) {
                 boolean found;
                 if (fname != null) {
-                    found = printModuleDescriptor(new ZipFile(fname));
+                    try (ZipFile zf = new ZipFile(fname)) {
+                        found = printModuleDescriptor(zf);
+                    }
                 } else {
                     try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) {
                         found = printModuleDescriptor(fin);
@@ -822,21 +848,27 @@
         return true;
     }
 
-    private static String toPackageName(ZipEntry entry) {
-        return toPackageName(entry.getName());
+    /*
+     * Add the package of the given resource name if it's a .class
+     * or a resource in a named package.
+     */
+    boolean addPackageIfNamed(String name) {
+        if (name.startsWith(VERSIONS_DIR)) {
+            throw new InternalError(name);
+        }
+
+        String pn = toPackageName(name);
+        // add if this is a class or resource in a package
+        if (Checks.isJavaIdentifier(pn)) {
+            packages.add(pn);
+            return true;
+        }
+
+        return false;
     }
 
     private static String toPackageName(String path) {
-        assert path.endsWith(".class");
-        int index;
-        if (path.startsWith(VERSIONS_DIR)) {
-            index = path.indexOf('/', VERSIONS_DIR.length());
-            if (index <= 0) {
-                return "";
-            }
-            path = path.substring(index + 1);
-        }
-        index = path.lastIndexOf('/');
+        int index = path.lastIndexOf('/');
         if (index != -1) {
             return path.substring(0, index).replace('/', '.');
         } else {
@@ -844,6 +876,48 @@
         }
     }
 
+    /*
+     * Returns true if the given entry is a valid entry of the given version.
+     */
+    private boolean isValidVersionedEntry(Entry entry, int version) {
+        String name = entry.basename;
+        if (name.startsWith(VERSIONS_DIR) && version != BASE_VERSION) {
+            int i = name.indexOf('/', VERSIONS_DIR.length());
+            // name == -1 -> not a versioned directory, something else
+            if (i == -1)
+                return false;
+            try {
+                String v = name.substring(VERSIONS_DIR.length(), i);
+                return Integer.valueOf(v) == version;
+            } catch (NumberFormatException x) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * Trim META-INF/versions/$version/ from the given name if the
+     * given name is a versioned entry of the given version; or
+     * of any version if the given version is BASE_VERSION
+     */
+    private String trimVersionsDir(String name, int version) {
+        if (name.startsWith(VERSIONS_DIR)) {
+            int i = name.indexOf('/', VERSIONS_DIR.length());
+            if (i >= 0) {
+                try {
+                    String v = name.substring(VERSIONS_DIR.length(), i);
+                    if (version == BASE_VERSION || Integer.valueOf(v) == version) {
+                        return name.substring(i + 1, name.length());
+                    }
+                } catch (NumberFormatException x) {}
+            }
+            throw new InternalError("unexpected versioned entry: " +
+                    name + " version " + version);
+        }
+        return name;
+    }
+
     /**
      * Expands list of files to process into full list of all files that
      * can be found by recursively descending directories.
@@ -865,28 +939,47 @@
             else
                 f = new File(dir, files[i]);
 
-            Entry entry = new Entry(version, f);
-            String entryName = entry.entryname;
-
+            Entry e = new Entry(version, f);
+            String entryName = e.entryname;
+            Entry entry = e;
+            if (e.basename.startsWith(VERSIONS_DIR) && isValidVersionedEntry(e, version)) {
+                entry = e.toVersionedEntry(version);
+            }
             if (f.isFile()) {
                 if (entryName.endsWith(MODULE_INFO)) {
                     moduleInfoPaths.put(entryName, f.toPath());
                     if (isUpdate)
                         entryMap.put(entryName, entry);
-                } else if (entries.add(entry)) {
-                    jarEntries.add(entryName);
-                    if (entry.basename.endsWith(".class"))
-                        packages.add(toPackageName(entry.basename));
-                    if (isUpdate)
-                        entryMap.put(entryName, entry);
+                } else if (isValidVersionedEntry(entry, version)) {
+                    if (entries.add(entry)) {
+                        jarEntries.add(entryName);
+                        // add the package if it's a class or resource
+                        addPackageIfNamed(trimVersionsDir(entry.basename, version));
+                        if (isUpdate)
+                            entryMap.put(entryName, entry);
+                    }
+                } else {
+                    error(formatMsg2("error.release.unexpected.versioned.entry",
+                                      entry.basename, String.valueOf(version)));
+                    ok = false;
                 }
             } else if (f.isDirectory()) {
-                if (entries.add(entry)) {
-                    if (isUpdate) {
-                        entryMap.put(entryName, entry);
+                if (isValidVersionedEntry(entry, version)) {
+                    if (entries.add(entry)) {
+                        if (isUpdate) {
+                            entryMap.put(entryName, entry);
+                        }
                     }
-                    expand(f, f.list(), isUpdate, moduleInfoPaths, version);
+                } else if (entry.basename.equals(VERSIONS_DIR)) {
+                    if (vflag) {
+                        output(formatMsg("out.ignore.entry", entry.basename));
+                    }
+                } else {
+                    error(formatMsg2("error.release.unexpected.versioned.entry",
+                                      entry.basename, String.valueOf(version)));
+                    ok = false;
                 }
+                expand(f, f.list(), isUpdate, moduleInfoPaths, version);
             } else {
                 error(formatMsg("error.nosuch.fileordir", String.valueOf(f)));
                 ok = false;
@@ -1047,6 +1140,7 @@
             } else if (moduleInfos != null && isModuleInfoEntry) {
                 moduleInfos.putIfAbsent(name, readModuleInfo(zis));
             } else {
+                boolean isDir = e.isDirectory();
                 if (!entryMap.containsKey(name)) { // copy the old stuff
                     // do our own compression
                     ZipEntry e2 = new ZipEntry(name);
@@ -1065,11 +1159,14 @@
                     addFile(zos, ent);
                     entryMap.remove(name);
                     entries.remove(ent);
+                    isDir = ent.isDir;
                 }
 
                 jarEntries.add(name);
-                if (name.endsWith(".class"))
-                    packages.add(toPackageName(name));
+                if (!isDir) {
+                    // add the package if it's a class or resource
+                    addPackageIfNamed(trimVersionsDir(name, BASE_VERSION));
+                }
             }
         }
 
@@ -1850,13 +1947,13 @@
 
     // Modular jar support
 
-    static <T> String toString(Set<T> set,
+    static <T> String toString(Collection<T> c,
                                CharSequence prefix,
                                CharSequence suffix ) {
-        if (set.isEmpty())
+        if (c.isEmpty())
             return "";
 
-        return set.stream().map(e -> e.toString())
+        return c.stream().map(e -> e.toString())
                            .collect(joining(", ", prefix, suffix));
     }
 
@@ -1890,7 +1987,7 @@
         return false;
     }
 
-    static <T> String toString(Set<T> set) {
+    static <T> String toString(Collection<T> set) {
         if (set.isEmpty()) { return ""; }
         return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
                   .collect(joining(" "));
@@ -1903,7 +2000,10 @@
     {
         ModuleDescriptor md = ModuleDescriptor.read(entryInputStream);
         StringBuilder sb = new StringBuilder();
-        sb.append("\n").append(md.toNameAndVersion());
+        sb.append("\n");
+        if (md.isOpen())
+            sb.append("open ");
+        sb.append(md.toNameAndVersion());
 
         md.requires().stream()
             .sorted(Comparator.comparing(Requires::name))
@@ -1921,10 +2021,17 @@
             .sorted(Comparator.comparing(Exports::source))
             .forEach(p -> sb.append("\n  exports ").append(p));
 
-        md.conceals().stream().sorted()
-            .forEach(p -> sb.append("\n  conceals ").append(p));
+        md.opens().stream()
+            .sorted(Comparator.comparing(Opens::source))
+            .forEach(p -> sb.append("\n  opens ").append(p));
 
-        md.provides().values().stream()
+        Set<String> concealed = new HashSet<>(md.packages());
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        md.opens().stream().map(Opens::source).forEach(concealed::remove);
+        concealed.stream().sorted()
+            .forEach(p -> sb.append("\n  contains ").append(p));
+
+        md.provides().stream()
             .sorted(Comparator.comparing(Provides::service))
             .forEach(p -> sb.append("\n  provides ").append(p.service())
                             .append(" with ")
@@ -1957,10 +2064,9 @@
     {
         ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes));
         Set<String> missing = md.provides()
-                                .values()
                                 .stream()
                                 .map(Provides::providers)
-                                .flatMap(Set::stream)
+                                .flatMap(List::stream)
                                 .filter(p -> !jarEntries.contains(toBinaryName(p)))
                                 .collect(Collectors.toSet());
         if (missing.size() > 0) {
@@ -1988,22 +2094,17 @@
             ModuleDescriptor vd = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue()));
             if (!(isValidVersionedDescriptor(vd, rd)))
                 return false;
-            e.setValue(extendedInfoBytes(rd, vd, e.getValue(), concealedPackages));
+            e.setValue(extendedInfoBytes(rd, vd, e.getValue(), packages));
         }
         return true;
     }
 
-    private Set<String> findConcealedPackages(ModuleDescriptor md){
+    private Set<String> findConcealedPackages(ModuleDescriptor md) {
         Objects.requireNonNull(md);
-
-        Set<String> exports = md.exports()
-                .stream()
-                .map(Exports::source)
-                .collect(toSet());
-
-        return packages.stream()
-                .filter(p -> !exports.contains(p))
-                .collect(toSet());
+        Set<String> concealed = new HashSet<>(packages);
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        md.opens().stream().map(Opens::source).forEach(concealed::remove);
+        return concealed;
     }
 
     private static boolean isPlatformModule(String name) {
@@ -2034,8 +2135,8 @@
             for (Requires r : vd.requires()) {
                 if (rootRequires.contains(r)) {
                     continue;
-                } else if (r.modifiers().contains(Requires.Modifier.PUBLIC)) {
-                    fatalError(getMsg("error.versioned.info.requires.public"));
+                } else if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) {
+                    fatalError(getMsg("error.versioned.info.requires.transitive"));
                     return false;
                 } else if (!isPlatformModule(r.name())) {
                     fatalError(getMsg("error.versioned.info.requires.added"));
@@ -2056,6 +2157,10 @@
             fatalError(getMsg("error.versioned.info.exports.notequal"));
             return false;
         }
+        if (!rd.opens().equals(vd.opens())) {
+            fatalError(getMsg("error.versioned.info.opens.notequal"));
+            return false;
+        }
         if (!rd.provides().equals(vd.provides())) {
             fatalError(getMsg("error.versioned.info.provides.notequal"));
             return false;
@@ -2074,15 +2179,15 @@
     private byte[] extendedInfoBytes(ModuleDescriptor rootDescriptor,
                                      ModuleDescriptor md,
                                      byte[] miBytes,
-                                     Set<String> conceals)
+                                     Set<String> packages)
         throws IOException
     {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         InputStream is = new ByteArrayInputStream(miBytes);
         ModuleInfoExtender extender = ModuleInfoExtender.newExtender(is);
 
-        // Add (or replace) the ConcealedPackages attribute
-        extender.conceals(conceals);
+        // Add (or replace) the Packages attribute
+        extender.packages(packages);
 
         // --main-class
         if (ename != null)
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -67,14 +67,16 @@
         in the root
 error.versioned.info.name.notequal=\
         module-info.class in a versioned directory contains incorrect name
-error.versioned.info.requires.public=\
-        module-info.class in a versioned directory contains additional "requires public"
+error.versioned.info.requires.transitive=\
+        module-info.class in a versioned directory contains additional "requires transitive"
 error.versioned.info.requires.added=\
         module-info.class in a versioned directory contains additional "requires"
 error.versioned.info.requires.dropped=\
         module-info.class in a versioned directory contains missing "requires"
 error.versioned.info.exports.notequal=\
         module-info.class in a versioned directory contains different "exports"
+error.versioned.info.opens.notequal=\
+        module-info.class in a versioned directory contains different "opens"
 error.versioned.info.provides.notequal=\
         module-info.class in a versioned directory contains different "provides"
 error.invalid.versioned.module.attribute=\
@@ -85,6 +87,8 @@
         release {0} not valid
 error.release.value.toosmall=\
         release {0} not valid, must be >= 9
+error.release.unexpected.versioned.entry=\
+        unexpected versioned entry {0} for release {1}
 error.validator.jarfile.exception=\
         can not validate {0}: {1}
 error.validator.jarfile.invalid=\
@@ -104,14 +108,16 @@
 error.validator.different.api=\
         entry: {0}, contains a class with different api from earlier version
 error.validator.names.mismatch=\
-         entry: {0}, contains a class with internal name {1}, names do not match
+        entry: {0}, contains a class with internal name {1}, names do not match
 warn.validator.identical.entry=\
-        warning - entry: {0} contains a class that is identical to an entry already in the jar
+        Warning: entry {0} contains a class that\n\
+        is identical to an entry already in the jar
 warn.validator.resources.with.same.name=\
-         warning - entry: {0}, multiple resources with same name
+        Warning: entry {0}, multiple resources with same name
 warn.validator.concealed.public.class=\
-         warning - entry {0} is a public class in a concealed package, \n\
-         placing this jar on the class path will result in incompatible public interfaces
+        Warning: entry {0} is a public class\n\
+        in a concealed package, placing this jar on the class path will result\n\
+        in incompatible public interfaces
 out.added.manifest=\
         added manifest
 out.added.module-info=\
--- a/jdk/src/jdk.jconsole/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jconsole/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,8 +24,8 @@
  */
 
 module jdk.jconsole {
-    requires public java.desktop;
-    requires public java.management;
+    requires transitive java.desktop;
+    requires transitive java.management;
     requires java.logging;
     requires java.rmi;
     requires jdk.attach;
--- a/jdk/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/XMBeanAttributes.java	Thu Dec 01 21:39:49 2016 +0000
@@ -40,8 +40,8 @@
 import java.util.WeakHashMap;
 
 import java.util.concurrent.ExecutionException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import java.lang.System.Logger;
+import java.lang.System.Logger.Level;
 import javax.management.JMException;
 import javax.management.MBeanInfo;
 import javax.management.MBeanAttributeInfo;
@@ -81,7 +81,7 @@
 public class XMBeanAttributes extends XTable {
 
     final Logger LOGGER =
-            Logger.getLogger(XMBeanAttributes.class.getPackage().getName());
+            System.getLogger(XMBeanAttributes.class.getPackage().getName());
 
     private final static String[] columnNames =
     {Messages.NAME,
@@ -190,8 +190,8 @@
     }
 
     public void cancelCellEditing() {
-        if (LOGGER.isLoggable(Level.FINER)) {
-            LOGGER.finer("Cancel Editing Row: "+getEditingRow());
+        if (LOGGER.isLoggable(Level.TRACE)) {
+            LOGGER.log(Level.TRACE, "Cancel Editing Row: "+getEditingRow());
         }
         final TableCellEditor tableCellEditor = getCellEditor();
         if (tableCellEditor != null) {
@@ -200,8 +200,8 @@
     }
 
     public void stopCellEditing() {
-        if (LOGGER.isLoggable(Level.FINER)) {
-            LOGGER.finer("Stop Editing Row: "+getEditingRow());
+        if (LOGGER.isLoggable(Level.TRACE)) {
+            LOGGER.log(Level.TRACE, "Stop Editing Row: "+getEditingRow());
         }
         final TableCellEditor tableCellEditor = getCellEditor();
         if (tableCellEditor != null) {
@@ -211,8 +211,8 @@
 
     @Override
     public final boolean editCellAt(final int row, final int column, EventObject e) {
-        if (LOGGER.isLoggable(Level.FINER)) {
-            LOGGER.finer("editCellAt(row="+row+", col="+column+
+        if (LOGGER.isLoggable(Level.TRACE)) {
+            LOGGER.log(Level.TRACE, "editCellAt(row="+row+", col="+column+
                     ", e="+e+")");
         }
         if (JConsole.isDebug()) {
@@ -1002,8 +1002,9 @@
                 Object tableValue = model.getValueAt(e.getFirstRow(),
                                                  e.getColumn());
 
-                if (LOGGER.isLoggable(Level.FINER)) {
-                    LOGGER.finer("tableChanged: firstRow="+e.getFirstRow()+
+                if (LOGGER.isLoggable(Level.TRACE)) {
+                    LOGGER.log(Level.TRACE,
+                        "tableChanged: firstRow="+e.getFirstRow()+
                         ", lastRow="+e.getLastRow()+", column="+e.getColumn()+
                         ", value="+tableValue);
                 }
--- a/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/jdi/ModuleReference.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,17 +30,17 @@
  * A module in the target VM.
  * <p>
  * Any method on {@code ModuleReference} which directly or
- * indirectly takes {@code ModuleReference} as an parameter may throw
+ * indirectly takes {@code ModuleReference} as a parameter may throw
  * {@link com.sun.jdi.VMDisconnectedException} if the target VM is
  * disconnected and the {@link com.sun.jdi.event.VMDisconnectEvent} has been or is
  * available to be read from the {@link com.sun.jdi.event.EventQueue}.
  * <p>
  * Any method on {@code ModuleReference} which directly or
- * indirectly takes {@code ModuleReference} as an parameter may throw
+ * indirectly takes {@code ModuleReference} as a parameter may throw
  * {@link com.sun.jdi.VMOutOfMemoryException} if the target VM has run out of memory.
  * <p>
  * Any method on {@code ModuleReference} or which directly or indirectly takes
- * {@code ModuleReference} as parameter may throw
+ * {@code ModuleReference} as a parameter may throw
  * {@link com.sun.jdi.InvalidModuleException} if the mirrored module
  * has been unloaded.
  *
@@ -67,12 +67,4 @@
      * @return the {@link ClassLoaderReference} object for this module.
      */
     ClassLoaderReference classLoader();
-
-    /**
-     * Indicates if this module reads another module.
-     *
-     * @return {@code true} if this module reads {@code other},
-     *         {@code false} otherwise
-     */
-    boolean canRead(ModuleReference other);
 }
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ModuleReferenceImpl.java	Thu Dec 01 21:39:49 2016 +0000
@@ -75,15 +75,4 @@
         }
         return classLoader;
     }
-
-    public synchronized boolean canRead(ModuleReference module) {
-        boolean ret;
-        try {
-            ret = JDWP.ModuleReference.CanRead.
-                process(this.vm, this, (ModuleReferenceImpl)module).canRead;
-        } catch (JDWPException ex) {
-            throw ex.toJDIException();
-        }
-        return ret;
-    }
 }
--- a/jdk/src/jdk.jdi/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jdi/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Defines the Java Debugger Interface.
+ */
 module jdk.jdi {
     requires jdk.attach;
     requires jdk.jdwp.agent;
@@ -37,10 +40,11 @@
     uses com.sun.jdi.connect.spi.TransportService;
 
     // windows shared memory connector providers are added at build time
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.ProcessAttachingConnector;
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.RawCommandLineLauncher;
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SocketAttachingConnector;
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SocketListeningConnector;
-    provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SunCommandLineLauncher;
+    provides com.sun.jdi.connect.Connector with
+        com.sun.tools.jdi.ProcessAttachingConnector,
+        com.sun.tools.jdi.RawCommandLineLauncher,
+        com.sun.tools.jdi.SocketAttachingConnector,
+        com.sun.tools.jdi.SocketListeningConnector,
+        com.sun.tools.jdi.SunCommandLineLauncher;
 }
 
--- a/jdk/src/jdk.jdi/windows/classes/module-info.java.extra	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jdi/windows/classes/module-info.java.extra	Thu Dec 01 21:39:49 2016 +0000
@@ -23,5 +23,6 @@
  * questions.
  */
 
-provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SharedMemoryAttachingConnector;
-provides com.sun.jdi.connect.Connector with com.sun.tools.jdi.SharedMemoryListeningConnector;
+provides com.sun.jdi.connect.Connector with
+    com.sun.tools.jdi.SharedMemoryAttachingConnector,
+    com.sun.tools.jdi.SharedMemoryListeningConnector;
--- a/jdk/src/jdk.jdwp.agent/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jdwp.agent/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,9 @@
  * questions.
  */
 
+/**
+ * Java Debug Wire Protocol.
+ */
 module jdk.jdwp.agent {
 }
 
--- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/ModuleReferenceImpl.c	Thu Dec 01 21:39:49 2016 +0000
@@ -83,36 +83,8 @@
     return JNI_TRUE;
 }
 
-static jboolean
-canRead(PacketInputStream *in, PacketOutputStream *out)
-{
-    static jmethodID method = NULL;
-    JNIEnv *env = getEnv();
-    jboolean can_read;
-    jobject module;
-    jobject source_module;
-
-    if (method == NULL) {
-        method = getMethod(env, jlrM(env), "canRead", "(Ljava/lang/reflect/Module;)Z");
-    }
-    module = inStream_readModuleRef(env, in);
-    if (inStream_error(in)) {
-        return JNI_TRUE;
-    }
-    source_module = inStream_readModuleRef(env, in);
-    if (inStream_error(in)) {
-        return JNI_TRUE;
-    }
-    can_read = JNI_FUNC_PTR(env, CallBooleanMethod)
-        (env, module, method, source_module);
-
-    (void)outStream_writeBoolean(out, can_read);
-    return JNI_TRUE;
-}
-
 
 void *ModuleReference_Cmds[] = { (void *)3
     ,(void *)getName
     ,(void *)getClassLoader
-    ,(void *)canRead
 };
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Thu Dec 01 21:39:49 2016 +0000
@@ -268,7 +268,15 @@
                             resources.getStringTable());
                 }
             }
-            resPool = p.transform(resPool, resMgr.resourcePoolBuilder());
+            try {
+                resPool = p.transform(resPool, resMgr.resourcePoolBuilder());
+            } catch (PluginException pe) {
+                if (JlinkTask.DEBUG) {
+                    System.err.println("Plugin " + p.getName() + " threw exception during transform");
+                    pe.printStackTrace();
+                }
+                throw pe;
+            }
             if (resPool.isEmpty()) {
                 throw new Exception("Invalid resource pool for plugin " + p);
             }
@@ -444,6 +452,7 @@
                         res = res.copyWithContent(bytes);
                     } catch (IOException ex) {
                         if (JlinkTask.DEBUG) {
+                            System.err.println("IOException while reading resource: " + res.path());
                             ex.printStackTrace();
                         }
                         throw new PluginException(ex);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java	Thu Dec 01 21:39:49 2016 +0000
@@ -298,7 +298,15 @@
         List<Plugin> bootPlugins = PluginRepository.getPlugins(Layer.boot());
         for (Plugin bp : bootPlugins) {
             if (Utils.isAutoEnabled(bp)) {
-                bp.configure(Collections.emptyMap());
+                try {
+                    bp.configure(Collections.emptyMap());
+                } catch (IllegalArgumentException e) {
+                    if (JlinkTask.DEBUG) {
+                        System.err.println("Plugin " + bp.getName() + " threw exception with config: {}");
+                        e.printStackTrace();
+                    }
+                    throw e;
+                }
                 plugins.add(bp);
             }
         }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
 import java.io.PrintWriter;
 import java.io.UncheckedIOException;
 import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReference;
 import java.lang.module.ResolutionException;
@@ -191,6 +192,7 @@
                 taskHelper.showVersion(options.fullVersion);
                 return EXIT_OK;
             }
+
             if (taskHelper.getExistingImage() == null) {
                 if (options.modulePath.isEmpty()) {
                     throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true);
@@ -256,7 +258,6 @@
         ImageProvider imageProvider =
                 createImageProvider(finder,
                                     config.getModules(),
-                                    config.getLimitmods(),
                                     config.getByteOrder(),
                                     null,
                                     IGNORE_SIGNING_DEFAULT);
@@ -291,23 +292,43 @@
         postProcessImage(img, config.getPlugins());
     }
 
+    // the token for "all modules on the module path"
+    private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
     private void createImage() throws Exception {
         if (options.output == null) {
             throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true);
         }
-        ModuleFinder finder
-                = newModuleFinder(options.modulePath, options.limitMods, options.addMods);
+
         if (options.addMods.isEmpty()) {
             throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules")
                     .showUsage(true);
         }
+
+        Set<String> roots = new HashSet<>();
+        for (String mod : options.addMods) {
+            if (mod.equals(ALL_MODULE_PATH)) {
+                ModuleFinder finder = modulePathFinder();
+                finder.findAll()
+                      .stream()
+                      .map(ModuleReference::descriptor)
+                      .map(ModuleDescriptor::name)
+                      .forEach(mn -> roots.add(mn));
+            } else {
+                roots.add(mod);
+            }
+        }
+
+        ModuleFinder finder = newModuleFinder(options.modulePath,
+                                              options.limitMods,
+                                              roots);
+
+
         // First create the image provider
         ImageProvider imageProvider = createImageProvider(finder,
-                        options.addMods,
-                        options.limitMods,
-                        options.endian,
-                        options.packagedModulesPath,
-                        options.ignoreSigning);
+                                                          roots,
+                                                          options.endian,
+                                                          options.packagedModulesPath,
+                                                          options.ignoreSigning);
 
         // Then create the Plugin Stack
         ImagePluginStack stack = ImagePluginConfiguration.
@@ -362,21 +383,20 @@
     }
 
     private static ImageProvider createImageProvider(ModuleFinder finder,
-                                                     Set<String> addMods,
-                                                     Set<String> limitMods,
+                                                     Set<String> roots,
                                                      ByteOrder order,
                                                      Path retainModulesPath,
                                                      boolean ignoreSigning)
             throws IOException
     {
-        if (addMods.isEmpty()) {
+        if (roots.isEmpty()) {
             throw new IllegalArgumentException("empty modules and limitmods");
         }
 
         Configuration cf = Configuration.empty()
                 .resolveRequires(finder,
                                  ModuleFinder.of(),
-                                 addMods);
+                                 roots);
 
         Map<String, Path> mods = cf.modules().stream()
             .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
@@ -388,8 +408,8 @@
      * modules, their transitive dependences, plus a set of other modules.
      */
     private static ModuleFinder limitFinder(ModuleFinder finder,
-            Set<String> roots,
-            Set<String> otherMods) {
+                                            Set<String> roots,
+                                            Set<String> otherMods) {
 
         // resolve all root modules
         Configuration cf = Configuration.empty()
@@ -535,40 +555,4 @@
             return image;
         }
     }
-
-    private static enum Section {
-        NATIVE_LIBS("native"),
-        NATIVE_CMDS("bin"),
-        CLASSES("classes"),
-        CONFIG("conf"),
-        UNKNOWN("unknown");
-
-        private final String jmodDir;
-
-        Section(String jmodDir) {
-            this.jmodDir = jmodDir;
-        }
-
-        String jmodDir() {
-            return jmodDir;
-        }
-
-        boolean matches(String path) {
-            return path.startsWith(jmodDir);
-        }
-
-        static Section getSectionFromName(String dir) {
-            if (Section.NATIVE_LIBS.matches(dir)) {
-                return Section.NATIVE_LIBS;
-            } else if (Section.NATIVE_CMDS.matches(dir)) {
-                return Section.NATIVE_CMDS;
-            } else if (Section.CLASSES.matches(dir)) {
-                return Section.CLASSES;
-            } else if (Section.CONFIG.matches(dir)) {
-                return Section.CONFIG;
-            } else {
-                return Section.UNKNOWN;
-            }
-        }
-    }
 }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java	Thu Dec 01 21:39:49 2016 +0000
@@ -74,7 +74,15 @@
         Objects.requireNonNull(pluginsLayer);
         Plugin plugin = getPlugin(name, pluginsLayer);
         if (plugin != null) {
-            plugin.configure(config);
+            try {
+                plugin.configure(config);
+            } catch (IllegalArgumentException e) {
+                if (JlinkTask.DEBUG) {
+                    System.err.println("Plugin " + plugin.getName() + " threw exception with config: " + config);
+                    e.printStackTrace();
+                }
+                throw e;
+            }
         }
         return plugin;
     }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Thu Dec 01 21:39:49 2016 +0000
@@ -50,24 +50,23 @@
         ModuleDescriptor md = mod.descriptor();
 
         // drop hashes
-        ModuleDescriptor.Builder builder = new ModuleDescriptor.Builder(md.name());
+        ModuleDescriptor.Builder builder = ModuleDescriptor.module(md.name());
         md.requires().stream()
           .forEach(builder::requires);
         md.exports().stream()
           .forEach(builder::exports);
+        md.opens().stream()
+          .forEach(builder::opens);
         md.uses().stream()
           .forEach(builder::uses);
-        md.provides().values().stream()
+        md.provides().stream()
           .forEach(builder::provides);
 
         // build the proper concealed packages
-        Set<String> exps = md.exports().stream()
-            .map(ModuleDescriptor.Exports::source)
-            .collect(Collectors.toSet());
-
-        mod.packages().stream()
-           .filter(pn -> !exps.contains(pn))
-           .forEach(builder::conceals);
+        Set<String> concealed = new HashSet<>(mod.packages());
+        md.exports().stream().map(ModuleDescriptor.Exports::source).forEach(concealed::remove);
+        md.opens().stream().map(ModuleDescriptor.Opens::source).forEach(concealed::remove);
+        concealed.stream().forEach(builder::contains);
 
         md.version().ifPresent(builder::version);
         md.mainClass().ifPresent(builder::mainClass);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java	Thu Dec 01 21:39:49 2016 +0000
@@ -35,6 +35,7 @@
 import java.util.Set;
 import java.util.stream.Stream;
 import jdk.internal.jimage.decompressor.CompressedResourceHeader;
+import jdk.internal.loader.ResourceHelper;
 import jdk.tools.jlink.plugin.ResourcePool;
 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
 import jdk.tools.jlink.plugin.ResourcePoolEntry;
@@ -58,6 +59,14 @@
         return ModuleDescriptor.read(bb);
     }
 
+    /**
+     * Returns true if a resource has an effective package.
+     */
+    public static boolean isNamedPackageResource(String path) {
+        return (path.endsWith(".class") && !path.endsWith("module-info.class")) ||
+                !ResourceHelper.isSimpleResource(path);
+    }
+
     class ResourcePoolModuleImpl implements ResourcePoolModule {
 
         final Map<String, ResourcePoolEntry> moduleContent = new LinkedHashMap<>();
@@ -100,7 +109,7 @@
                 .filter(m -> m.type() == ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
                 .forEach(res -> {
                     String name = ImageFileCreator.resourceName(res.path());
-                    if (name.endsWith(".class") && !name.endsWith("module-info.class")) {
+                    if (isNamedPackageResource(name)) {
                         String pkg = ImageFileCreator.toPackage(name);
                         if (!pkg.isEmpty()) {
                             pkgs.add(pkg);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Thu Dec 01 21:39:49 2016 +0000
@@ -421,7 +421,15 @@
                 // we call configure once for each occurrence. It is upto the plugin
                 // to 'merge' and/or 'override' arguments.
                 for (Map<String, String> map : argsMaps) {
-                    plugin.configure(Collections.unmodifiableMap(map));
+                    try {
+                        plugin.configure(Collections.unmodifiableMap(map));
+                    } catch (IllegalArgumentException e) {
+                        if (JlinkTask.DEBUG) {
+                            System.err.println("Plugin " + plugin.getName() + " threw exception with config: " + map);
+                            e.printStackTrace();
+                        }
+                        throw e;
+                    }
                 }
 
                 if (!Utils.isDisabled(plugin)) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeJmodSectionPlugin.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeJmodSectionPlugin.java	Thu Dec 01 21:39:49 2016 +0000
@@ -55,7 +55,7 @@
     public void configure(Map<String, String> config) {
         String arg = config.get(NAME);
         if (arg.isEmpty()) {
-            throw new PluginException("Section name must be specified");
+            throw new IllegalArgumentException("Section name must be specified");
         }
 
         switch (arg) {
@@ -66,7 +66,7 @@
                 filters.add(Type.HEADER_FILE);
                 break;
             default:
-                throw new PluginException("Invalid section name: " + arg);
+                throw new IllegalArgumentException("Invalid section name: " + arg);
         }
     }
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OrderResourcesPlugin.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OrderResourcesPlugin.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.file.FileSystem;
 import java.nio.file.Files;
 import java.nio.file.PathMatcher;
@@ -177,7 +178,7 @@
                     try {
                         lines = Files.readAllLines(file.toPath());
                     } catch (IOException ex) {
-                        throw new PluginException(ex);
+                        throw new UncheckedIOException(ex);
                     }
 
                     for (String line : lines) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java	Thu Dec 01 21:39:49 2016 +0000
@@ -115,7 +115,7 @@
                 try (FileInputStream fis = new FileInputStream(operation)) {
                     props.load(fis);
                 } catch (IOException exp) {
-                    throw new RuntimeException(exp);
+                    throw new UncheckedIOException(exp);
                 }
                 props.forEach((k, v) -> release.put(k.toString(), v.toString()));
             }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.PathMatcher;
@@ -35,7 +36,6 @@
 import java.util.Objects;
 import java.util.function.Predicate;
 import jdk.tools.jlink.internal.Utils;
-import jdk.tools.jlink.plugin.PluginException;
 
 /**
  *
@@ -62,7 +62,7 @@
                     try {
                         lines = Files.readAllLines(file.toPath());
                     } catch (IOException ex) {
-                        throw new PluginException(ex);
+                        throw new UncheckedIOException(ex);
                     }
 
                     lines.stream().forEach((line) -> {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,17 +28,18 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.*;
-import java.lang.module.ModuleDescriptor;
 import java.util.ArrayList;
-import java.util.Collections;
+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.Optional;
+import java.util.Objects;
 import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.function.IntSupplier;
 
 import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.misc.SharedSecrets;
@@ -50,16 +51,17 @@
 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.Builder.*;
+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 installed modules.
- * It will extend module-info.class with ConcealedPackages attribute,
+ * 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.
  *
@@ -69,16 +71,14 @@
  * @see SystemModules
  */
 public final class SystemModuleDescriptorPlugin implements Plugin {
-    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
+    private static final JavaLangModuleAccess JLMA =
+        SharedSecrets.getJavaLangModuleAccess();
 
-    // TODO: packager has the dependency on the plugin name
-    // Keep it as "--installed-modules" until packager removes such
-    // dependency (should not need to specify this plugin since it
-    // is enabled by default)
-    private static final String NAME = "installed-modules";
-    private static final String DESCRIPTION = PluginsResourceBundle.getDescription(NAME);
+    private static final String NAME = "system-modules";
+    private static final String DESCRIPTION =
+        PluginsResourceBundle.getDescription(NAME);
+
     private boolean enabled;
-
     public SystemModuleDescriptorPlugin() {
         this.enabled = true;
     }
@@ -106,39 +106,38 @@
         }
     }
 
-
     @Override
     public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
         if (!enabled) {
             throw new PluginException(NAME + " was set");
         }
 
-        Builder builder = new Builder();
+        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 -> {
-            Optional<ResourcePoolEntry> optData = module.findEntry("module-info.class");
-            if (! optData.isPresent()) {
+
+            ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
                 // automatic module not supported yet
-                throw new PluginException("module-info.class not found for " +
-                                          module.name() + " module");
-            }
-            ResourcePoolEntry data = optData.get();
+                () ->  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);
 
-                ModuleDescriptorBuilder mbuilder = builder.module(md, module.packages());
-                int packages = md.exports().size() + md.conceals().size();
-                if (md.conceals().isEmpty() &&
-                        packages != module.packages().size()) {
-                    // add ConcealedPackages attribute if not exist
+                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, mbuilder.conceals());
+                        new ModuleInfoRewriter(bain, module.packages());
                     // replace with the overridden version
                     data = data.copyWithContent(minfoWriter.getBytes());
                 }
@@ -149,11 +148,11 @@
         });
 
         // Generate the new class
-        ClassWriter cwriter = builder.build();
+        ClassWriter cwriter = generator.getClassWriter();
         in.entries().forEach(data -> {
             if (data.path().endsWith("module-info.class"))
                 return;
-            if (builder.isOverriddenClass(data.path())) {
+            if (generator.isOverriddenClass(data.path())) {
                 byte[] bytes = cwriter.toByteArray();
                 ResourcePoolEntry ndata = data.copyWithContent(bytes);
                 out.add(ndata);
@@ -166,14 +165,14 @@
     }
 
     /*
-     * Add ConcealedPackages attribute
+     * Add Packages attribute
      */
     class ModuleInfoRewriter extends ByteArrayOutputStream {
         final ModuleInfoExtender extender;
-        ModuleInfoRewriter(InputStream in, Set<String> conceals) throws IOException {
+        ModuleInfoRewriter(InputStream in, Set<String> packages) throws IOException {
             this.extender = ModuleInfoExtender.newExtender(in);
-            // Add ConcealedPackages attribute
-            this.extender.conceals(conceals);
+            // Add Packages attribute
+            this.extender.packages(packages);
             this.extender.write(this);
         }
 
@@ -190,19 +189,21 @@
         for (Exports e : md.exports()) {
             Checks.requirePackageName(e.source());
             if (e.isQualified())
-               e.targets().forEach(Checks::requireModuleName);
+                e.targets().forEach(Checks::requireModuleName);
         }
-        for (Map.Entry<String, Provides> e : md.provides().entrySet()) {
-            String service = e.getKey();
-            Provides provides = e.getValue();
-            Checks.requireServiceTypeName(service);
+        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.conceals()) {
+        for (String pn : md.packages()) {
             Checks.requirePackageName(pn);
         }
     }
@@ -222,45 +223,60 @@
     }
 
     /**
-     * Builder of a new jdk.internal.module.SystemModules class
-     * to reconstitute ModuleDescriptor of the installed modules.
+     * ClassWriter of a new jdk.internal.module.SystemModules class
+     * to reconstitute ModuleDescriptor of the system modules.
      */
-    static class Builder {
+    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 BUILDER_VAR    = 0;
-        private static final int MD_VAR         = 1;   // variable for ModuleDescriptor
-        private static final int MODS_VAR       = 2;   // variable for Set<Modifier>
-        private static final int STRING_SET_VAR = 3;   // variable for Set<String>
         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 nextLocalVar = 4;
         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, String> modulesToHash = new HashMap<>();
+        private final Map<String, byte[]> modulesToHash = new HashMap<>();
+
+        // module name to index in MODULES_TO_HASH
+        private final Map<String, Integer> modulesToHashIndex = new HashMap<>();
 
-        // map Set<String> to a specialized builder to allow them to be
-        // deduplicated as they are requested
-        private final Map<Set<String>, StringSetBuilder> stringSets = 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 Builder() {
-            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS+ClassWriter.COMPUTE_FRAMES);
+        public SystemModulesClassGenerator() {
+            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
+                                      ClassWriter.COMPUTE_FRAMES);
+        }
+
+        private int getNextLocalVar() {
+            return nextLocalVar++;
         }
 
         /*
@@ -270,16 +286,16 @@
          */
         private void clinit(int numModules, int numPackages) {
             cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME,
-                    null, "java/lang/Object", null);
+                     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 String[] MODULES_TO_HASH = new String[] {....};
+            // public static byte[][] MODULES_TO_HASH
             cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULES_TO_HASH,
-                "[Ljava/lang/String;", null, null)
+                "[[B", null, null)
                 .visitEnd();
 
             // public static int PACKAGES_IN_BOOT_LAYER;
@@ -308,23 +324,30 @@
 
             // create the MODULES_TO_HASH array
             pushInt(numModules);
-            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+            mv.visitTypeInsn(ANEWARRAY, "[B");
 
             index = 0;
             for (ModuleDescriptorBuilder builder : builders) {
                 String mn = builder.md.name();
-                String recordedHash = modulesToHash.get(mn);
+                byte[] recordedHash = modulesToHash.get(mn);
                 if (recordedHash != null) {
                     mv.visitInsn(DUP);              // arrayref
                     pushInt(index);
-                    mv.visitLdcInsn(recordedHash);  // value
+                    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,
-                    "[Ljava/lang/String;");
+            mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH, "[[B");
 
             mv.visitInsn(RETURN);
             mv.visitMaxs(0, 0);
@@ -333,42 +356,42 @@
         }
 
         /*
-         * Adds the given ModuleDescriptor to the installed module list, and
-         * prepares mapping from Set<String> to StringSetBuilders to emit an
-         * optimized number of string sets during build.
+         * 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 ModuleDescriptorBuilder module(ModuleDescriptor md, Set<String> packages) {
+        public void addModule(ModuleDescriptor md, Set<String> packages) {
             ModuleDescriptorBuilder builder = new ModuleDescriptorBuilder(md, packages);
             builders.add(builder);
 
             // exports
-            for (ModuleDescriptor.Exports e : md.exports()) {
-                if (e.isQualified()) {
-                    stringSets.computeIfAbsent(e.targets(), s -> new StringSetBuilder(s))
-                              .increment();
-                }
+            for (Exports e : md.exports()) {
+                dedupSetBuilder.stringSet(e.targets());
+                dedupSetBuilder.exportsModifiers(e.modifiers());
             }
 
-            // provides (preserve iteration order)
-            for (ModuleDescriptor.Provides p : md.provides().values()) {
-                stringSets.computeIfAbsent(p.providers(), s -> new StringSetBuilder(s, true))
-                          .increment();
+            // 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
-            stringSets.computeIfAbsent(md.uses(), s -> new StringSetBuilder(s))
-                      .increment();
+            dedupSetBuilder.stringSet(md.uses());
 
             // hashes
             JLMA.hashes(md).ifPresent(mh -> modulesToHash.putAll(mh.hashes()));
-
-            return builder;
         }
 
         /*
          * Generate bytecode for SystemModules
          */
-        public ClassWriter build() {
+        public ClassWriter getClassWriter() {
             int numModules = builders.size();
             int numPackages = 0;
             for (ModuleDescriptorBuilder builder : builders) {
@@ -411,108 +434,79 @@
         }
 
         class ModuleDescriptorBuilder {
-            static final String REQUIRES_MODIFIER_CLASSNAME =
-                    "java/lang/module/ModuleDescriptor$Requires$Modifier";
-            static final String REQUIRES_MODIFIER_TYPE =
-                "Ljava/lang/module/ModuleDescriptor$Requires$Modifier;";
             static final String BUILDER_TYPE = "Ljdk/internal/module/Builder;";
-            static final String REQUIRES_MODIFIER_STRING_SIG =
-                "(" + REQUIRES_MODIFIER_TYPE + "Ljava/lang/String;)" + BUILDER_TYPE;
-            static final String STRING_SET_SIG =
-                "(Ljava/lang/String;Ljava/util/Set;)" + BUILDER_TYPE;
-            static final String SET_STRING_SIG =
-                "(Ljava/util/Set;Ljava/lang/String;)" + BUILDER_TYPE;
-            static final String SET_SIG =
-                "(Ljava/util/Set;)" + BUILDER_TYPE;
+            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_STRING_SIG =
-                "(Ljava/lang/String;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 newBuilder(String name, int reqs, int exports, int provides,
-                            int packages) {
-                mv.visitTypeInsn(NEW, MODULE_DESCRIPTOR_BUILDER);
-                mv.visitInsn(DUP);
-                mv.visitLdcInsn(name);
-                pushInt(initialCapacity(reqs));
-                pushInt(initialCapacity(exports));
-                pushInt(initialCapacity(provides));
-                pushInt(initialCapacity(packages));
-                mv.visitMethodInsn(INVOKESPECIAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "<init>", "(Ljava/lang/String;IIII)V", false);
-                mv.visitVarInsn(ASTORE, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-            }
-
-            /*
-             * Returns the set of concealed packages from ModuleDescriptor, if present
-             * or compute it if the module does not have ConcealedPackages attribute
-             */
-            Set<String> conceals() {
-                Set<String> conceals = md.conceals();
-                if (conceals.isEmpty() && md.exports().size() != packages.size()) {
-                    Set<String> exports = md.exports().stream()
-                                            .map(Exports::source)
-                                            .collect(Collectors.toSet());
-                    conceals = packages.stream()
-                                       .filter(pn -> !exports.contains(pn))
-                                       .collect(Collectors.toSet());
-                }
-
-                if (conceals.size() + md.exports().size() != packages.size() &&
-                    // jdk.localedata may have concealed packages that don't exist
-                    !md.name().equals("jdk.localedata")) {
-                    throw new AssertionError(md.name() + ": conceals=" + conceals.size() +
-                            ", exports=" + md.exports().size() + ", packages=" + packages.size());
-                }
-                return conceals;
-            }
-
             void build() {
-                newBuilder(md.name(), md.requires().size(),
-                           md.exports().size(),
-                           md.provides().size(),
-                           packages.size());
+                // new jdk.internal.module.Builder
+                newBuilder();
 
                 // requires
-                for (ModuleDescriptor.Requires req : md.requires()) {
-                    switch (req.modifiers().size()) {
-                        case 0:
-                            requires(req.name());
-                            break;
-                        case 1:
-                            ModuleDescriptor.Requires.Modifier mod =
-                                req.modifiers().iterator().next();
-                            requires(mod, req.name());
-                            break;
-                        default:
-                            requires(req.modifiers(), req.name());
-                    }
-                }
+                requires(md.requires());
 
                 // exports
-                for (ModuleDescriptor.Exports e : md.exports()) {
-                    if (e.isQualified()) {
-                        exports(e.source(), e.targets());
-                    } else {
-                        exports(e.source());
-                    }
-                }
+                exports(md.exports());
+
+                // opens
+                opens(md.opens());
 
                 // uses
                 uses(md.uses());
 
                 // provides
-                for (ModuleDescriptor.Provides p : md.provides().values()) {
-                    provides(p.service(), p.providers());
-                }
+                provides(md.provides());
 
                 // all packages
                 packages(packages);
@@ -532,6 +526,38 @@
                 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
              */
@@ -539,130 +565,220 @@
                 mv.visitVarInsn(ALOAD, MD_VAR);
                 pushInt(nextModulesIndex++);
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(md.hashCode());
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                    "build", "()Ljava/lang/module/ModuleDescriptor;", false);
+                                   "build", "(I)Ljava/lang/module/ModuleDescriptor;",
+                                   false);
                 mv.visitInsn(AASTORE);
             }
 
             /*
-             * Invoke Builder.requires(String mn)
+             * Call Builder::newRequires to create Requires instances and
+             * then pass it to the builder by calling:
+             *      Builder.requires(Requires[])
+             *
              */
-            void requires(String name) {
+            void requires(Set<Requires> requires) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitLdcInsn(name);
+                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", STRING_SIG, false);
-                mv.visitInsn(POP);
-            }
-
-            /*
-             * Invoke Builder.requires(Modifier mod, String mn)
-             */
-            void requires(ModuleDescriptor.Requires.Modifier mod, String name) {
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitFieldInsn(GETSTATIC, REQUIRES_MODIFIER_CLASSNAME, mod.name(),
-                                  REQUIRES_MODIFIER_TYPE);
-                mv.visitLdcInsn(name);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "requires", REQUIRES_MODIFIER_STRING_SIG, false);
-                mv.visitInsn(POP);
+                                   "requires", REQUIRES_ARRAY_SIG, false);
             }
 
             /*
-             * Invoke Builder.requires(Set<Modifier> mods, String mn)
+             * Invoke Builder.newRequires(Set<Modifier> mods, String mn)
              *
-             * EnumSet<Modifier> mods = EnumSet.of(mod,....);
-             * Buidler.requires(mods, mn);
+             * Set<Modifier> mods = ...
+             * Builder.newRequires(mods, mn);
              */
-            void requires(Set<ModuleDescriptor.Requires.Modifier> mods, String name) {
-                mv.visitVarInsn(ALOAD, MODS_VAR);
-                String signature = "(";
-                for (ModuleDescriptor.Requires.Modifier m : mods) {
-                    mv.visitFieldInsn(GETSTATIC, REQUIRES_MODIFIER_CLASSNAME, m.name(),
-                                      REQUIRES_MODIFIER_TYPE);
-                    signature += "Ljava/util/Enum;";
-                }
-                signature += ")Ljava/util/EnumSet;";
-                mv.visitMethodInsn(INVOKESTATIC, "java/util/EnumSet", "of",
-                                   signature, false);
-                mv.visitVarInsn(ASTORE, MODS_VAR);
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                mv.visitVarInsn(ALOAD, MODS_VAR);
+            void newRequires(Set<Requires.Modifier> mods, String name) {
+                int varIndex = dedupSetBuilder.indexOfRequiresModifiers(mods);
+                mv.visitVarInsn(ALOAD, varIndex);
                 mv.visitLdcInsn(name);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "requires", SET_STRING_SIG, false);
-                mv.visitInsn(POP);
+                mv.visitMethodInsn(INVOKESTATIC, MODULE_DESCRIPTOR_BUILDER,
+                                   "newRequires", REQUIRES_SET_STRING_SIG, false);
             }
 
             /*
-             * Invoke Builder.exports(String pn)
+             * Call Builder::newExports to create Exports instances and
+             * then pass it to the builder by calling:
+             *      Builder.exports(Exports[])
+             *
              */
-            void exports(String pn) {
+            void exports(Set<Exports> exports) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
-
-                mv.visitLdcInsn(pn);
+                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", STRING_SIG, false);
-                mv.visitInsn(POP);
+                                   "exports", EXPORTS_ARRAY_SIG, false);
             }
 
             /*
-             * Invoke Builder.exports(String pn, Set<String> targets)
+             * 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);
              * :
              * :
-             * Builder.exports(pn, targets);
+             *
+             * Set<Modifier> mods = ...
+             * Builder.newExports(mods, pn, targets);
              */
-            void exports(String pn, Set<String> targets) {
-                int varIndex = stringSets.get(targets).build();
+            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);
-                mv.visitLdcInsn(pn);
-                mv.visitVarInsn(ALOAD, varIndex);
+                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,
-                                   "exports", STRING_SET_SIG, false);
-                mv.visitInsn(POP);
+                        "opens", OPENS_ARRAY_SIG, false);
             }
 
             /*
-             * Invokes Builder.uses(Set<String> uses)
+             * 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 = stringSets.get(uses).build();
+                int varIndex = dedupSetBuilder.indexOfStringSet(uses);
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
                 mv.visitVarInsn(ALOAD, varIndex);
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                        "uses", SET_SIG, false);
+                                   "uses", SET_SIG, false);
                 mv.visitInsn(POP);
             }
 
             /*
-             * Invoke Builder.provides(String service, Set<String> providers)
+            * 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 LinkedHashSet<>();
+             * Set<String> providers = new HashSet<>();
              * providers.add(impl);
              * :
              * :
-             * Builder.exports(service, providers);
+             * Builder.newProvides(service, providers);
              */
-            void provides(String service, Set<String> providers) {
-                int varIndex = stringSets.get(providers).build();
-                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+            void newProvides(String service, List<String> providers) {
                 mv.visitLdcInsn(service);
-                mv.visitVarInsn(ALOAD, varIndex);
-                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
-                                   "provides", STRING_SET_SIG, false);
-                mv.visitInsn(POP);
+                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.conceals(String pn)
+             * Invoke Builder.packages(String pn)
              */
             void packages(Set<String> packages) {
+                int varIndex = dedupSetBuilder.newStringSet(packages);
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
-                int varIndex = new StringSetBuilder(packages).build();
-                assert varIndex == STRING_SET_VAR;
                 mv.visitVarInsn(ALOAD, varIndex);
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
                                    "packages", SET_SIG, false);
@@ -683,7 +799,7 @@
             /*
              * Invoke Builder.version(Version v);
              */
-            void version(ModuleDescriptor.Version v) {
+            void version(Version v) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
                 mv.visitLdcInsn(v.toString());
                 mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
@@ -691,99 +807,277 @@
                 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);
+                                   "algorithm", STRING_SIG, false);
                 mv.visitInsn(POP);
             }
 
-            void moduleHash(String name, String hashString) {
+            /*
+             * Invoke Builder.moduleHash(String name, byte[] hash);
+             */
+            void moduleHash(String name, byte[] hash) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
                 mv.visitLdcInsn(name);
-                mv.visitLdcInsn(hashString);
+
+                // 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_STRING_SIG, false);
+                                   "moduleHash", STRING_BYTE_ARRAY_SIG, false);
                 mv.visitInsn(POP);
             }
         }
 
         /*
-         * StringSetBuilder generates bytecode to create one single instance
-         * of HashSet for a given set of names and assign to a local variable
-         * slot.  When there is only one single reference to a Set<String>,
-         * it will reuse STRING_SET_VAR for reference.  For Set<String> with
-         * multiple references, it will use a new local variable.
+         * Wraps set creation, ensuring identical sets are properly deduplicated.
          */
-        class StringSetBuilder {
-            final Set<String> names;
-            final boolean linked;
-            int refCount;
-            int localVarIndex;
+        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;
 
-            StringSetBuilder(Set<String> names, boolean linked) {
-                this.names = names;
-                this.linked = linked;
+            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();
             }
 
-            StringSetBuilder(Set<String> names) {
-                this(names, false);
+            /*
+             * 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();
             }
 
-            void increment() {
+
+            /*
+             * 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<String> represented by this builder,
+             * 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.
              */
-            int build() {
+            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 ? STRING_SET_VAR
-                                          : nextLocalVar++;
+                    index = refCount <= 1 ? defaultVarIndex
+                                          : nextLocalVar.getAsInt();
                     if (index < MAX_LOCAL_VARS) {
                         localVarIndex = index;
                     } else {
-                        // overflow: disable optimization and keep localVarIndex = 0
-                        index = STRING_SET_VAR;
+                        // overflow: disable optimization by using localVarIndex = 0
+                        index = defaultVarIndex;
                     }
 
-                    if (names.isEmpty()) {
-                        mv.visitMethodInsn(INVOKESTATIC, "java/util/Collections",
-                                "emptySet", "()Ljava/util/Set;", false);
-                        mv.visitVarInsn(ASTORE, index);
-                    } else if (names.size() == 1) {
-                        mv.visitLdcInsn(names.iterator().next());
-                        mv.visitMethodInsn(INVOKESTATIC, "java/util/Collections",
-                                "singleton", "(Ljava/lang/Object;)Ljava/util/Set;", false);
-                        mv.visitVarInsn(ASTORE, index);
-                    } else {
-                        String cn = linked ? "java/util/LinkedHashSet" : "java/util/HashSet";
-                        mv.visitTypeInsn(NEW, cn);
-                        mv.visitInsn(DUP);
-                        pushInt(initialCapacity(names.size()));
-                        mv.visitMethodInsn(INVOKESPECIAL, cn, "<init>", "(I)V", false);
-
-                        mv.visitVarInsn(ASTORE, index);
-                        for (String t : names) {
-                            mv.visitVarInsn(ALOAD, index);
-                            mv.visitLdcInsn(t);
-                            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set",
-                                    "add", "(Ljava/lang/Object;)Z", true);
-                            mv.visitInsn(POP);
-                        }
-                    }
+                    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 + ";");
+            }
         }
     }
 }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -80,7 +80,7 @@
 Takes a file hinting to jlink what java.lang.invoke classes to pre-generate. If\n\
 this flag is not specified a default set of classes will be generated.
 
-installed-modules.description=Fast loading of module descriptors (always enabled)
+system-modules.description=Fast loading of module descriptors (always enabled)
 
 onoff.argument=<on|off>
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Thu Dec 01 21:39:49 2016 +0000
@@ -40,6 +40,7 @@
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Version;
@@ -83,6 +84,7 @@
 import java.util.stream.Collectors;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
+import java.util.stream.Stream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
@@ -97,6 +99,7 @@
 import jdk.internal.joptsimple.OptionSet;
 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;
@@ -261,9 +264,9 @@
         }
     }
 
-    static <T> String toString(Set<T> set) {
-        if (set.isEmpty()) { return ""; }
-        return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
+    static <T> String toString(Collection<T> c) {
+        if (c.isEmpty()) { return ""; }
+        return c.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
                   .collect(joining(" "));
     }
 
@@ -291,14 +294,21 @@
             .sorted(Comparator.comparing(Exports::source))
             .forEach(p -> sb.append("\n  exports ").append(p));
 
-        md.conceals().stream().sorted()
-            .forEach(p -> sb.append("\n  conceals ").append(p));
+        md.opens().stream()
+            .sorted(Comparator.comparing(Opens::source))
+            .forEach(p -> sb.append("\n  opens ").append(p));
 
-        md.provides().values().stream()
+        Set<String> concealed = new HashSet<>(md.packages());
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        md.opens().stream().map(Opens::source).forEach(concealed::remove);
+        concealed.stream().sorted()
+                 .forEach(p -> sb.append("\n  contains ").append(p));
+
+        md.provides().stream()
             .sorted(Comparator.comparing(Provides::service))
             .forEach(p -> sb.append("\n  provides ").append(p.service())
-                .append(" with ")
-                .append(toString(p.providers())));
+                            .append(" with ")
+                            .append(toString(p.providers())));
 
         md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
 
@@ -311,8 +321,8 @@
         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))));
+                         .append(hashes.algorithm()).append(" ")
+                         .append(hashes.hashFor(mod))));
 
         out.println(sb.toString());
     }
@@ -414,7 +424,7 @@
         /**
          * Writes the updated module-info.class to the ZIP output stream.
          *
-         * The updated module-info.class will have a ConcealedPackages attribute
+         * The updated module-info.class will have a Packages attribute
          * with the set of module-private/non-exported packages.
          *
          * If --module-version, --main-class, or other options were provided
@@ -439,15 +449,9 @@
             try (InputStream in = miSupplier.get()) {
                 ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in);
 
-                // Add (or replace) the ConcealedPackages attribute
+                // Add (or replace) the Packages attribute
                 if (packages != null) {
-                    Set<String> exported = descriptor.exports().stream()
-                        .map(ModuleDescriptor.Exports::source)
-                        .collect(Collectors.toSet());
-                    Set<String> concealed = packages.stream()
-                        .filter(p -> !exported.contains(p))
-                        .collect(Collectors.toSet());
-                    extender.conceals(concealed);
+                    extender.packages(packages);
                 }
 
                 // --main-class
@@ -556,10 +560,11 @@
         Set<String> findPackages(Path dir) {
             try {
                 return Files.find(dir, Integer.MAX_VALUE,
-                        ((path, attrs) -> attrs.isRegularFile() &&
-                                path.toString().endsWith(".class")))
-                        .map(path -> toPackageName(dir.relativize(path)))
-                        .filter(pkg -> pkg.length() > 0)   // module-info
+                                  ((path, attrs) -> attrs.isRegularFile()))
+                        .map(dir::relativize)
+                        .filter(path -> isResource(path.toString()))
+                        .map(path -> toPackageName(path))
+                        .filter(pkg -> pkg.length() > 0)
                         .distinct()
                         .collect(Collectors.toSet());
             } catch (IOException ioe) {
@@ -572,21 +577,30 @@
          */
         Set<String> findPackages(JarFile jf) {
             return jf.stream()
-                     .filter(e -> e.getName().endsWith(".class"))
+                     .filter(e -> !e.isDirectory() && isResource(e.getName()))
                      .map(e -> toPackageName(e))
-                     .filter(pkg -> pkg.length() > 0)   // module-info
+                     .filter(pkg -> pkg.length() > 0)
                      .distinct()
                      .collect(Collectors.toSet());
         }
 
+        /**
+         * Returns true if it's a .class or a resource with an effective
+         * package name.
+         */
+        boolean isResource(String name) {
+            name = name.replace(File.separatorChar, '/');
+            return name.endsWith(".class") || !ResourceHelper.isSimpleResource(name);
+        }
+
+
         String toPackageName(Path path) {
             String name = path.toString();
-            assert name.endsWith(".class");
             int index = name.lastIndexOf(File.separatorChar);
             if (index != -1)
                 return name.substring(0, index).replace(File.separatorChar, '.');
 
-            if (!name.equals(MODULE_INFO)) {
+            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
                 IOException e = new IOException(name  + " in the unnamed package");
                 throw new UncheckedIOException(e);
             }
@@ -595,12 +609,15 @@
 
         String toPackageName(ZipEntry entry) {
             String name = entry.getName();
-            assert name.endsWith(".class");
             int index = name.lastIndexOf("/");
             if (index != -1)
                 return name.substring(0, index).replace('/', '.');
-            else
-                return "";
+
+            if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
+                IOException e = new IOException(name  + " in the unnamed package");
+                throw new UncheckedIOException(e);
+            }
+            return "";
         }
 
         void processClasses(JmodOutputStream out, List<Path> classpaths)
--- a/jdk/src/jdk.jlink/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jlink/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -31,21 +31,23 @@
 
     uses jdk.tools.jlink.plugin.Plugin;
 
-    provides java.util.spi.ToolProvider with jdk.tools.jmod.Main.JmodToolProvider;
-    provides java.util.spi.ToolProvider with jdk.tools.jlink.internal.Main.JlinkToolProvider;
+    provides java.util.spi.ToolProvider with
+        jdk.tools.jmod.Main.JmodToolProvider,
+        jdk.tools.jlink.internal.Main.JlinkToolProvider;
 
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.FileCopierPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.StripDebugPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludePlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.OrderResourcesPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.DefaultCompressPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ExcludeVMPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.IncludeLocalesPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin;
-    provides jdk.tools.jlink.plugin.Plugin with jdk.tools.jlink.internal.plugins.ClassForNamePlugin;
+    provides jdk.tools.jlink.plugin.Plugin with
+        jdk.tools.jlink.internal.plugins.FileCopierPlugin,
+        jdk.tools.jlink.internal.plugins.StripDebugPlugin,
+        jdk.tools.jlink.internal.plugins.ExcludePlugin,
+        jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin,
+        jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin,
+        jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin,
+        jdk.tools.jlink.internal.plugins.StripNativeCommandsPlugin,
+        jdk.tools.jlink.internal.plugins.OrderResourcesPlugin,
+        jdk.tools.jlink.internal.plugins.DefaultCompressPlugin,
+        jdk.tools.jlink.internal.plugins.ExcludeVMPlugin,
+        jdk.tools.jlink.internal.plugins.IncludeLocalesPlugin,
+        jdk.tools.jlink.internal.plugins.GenerateJLIClassesPlugin,
+        jdk.tools.jlink.internal.plugins.ReleaseInfoPlugin,
+        jdk.tools.jlink.internal.plugins.ClassForNamePlugin;
  }
--- a/jdk/src/jdk.jvmstat/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.jvmstat/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -36,7 +36,8 @@
         jdk.jstatd;
 
     uses sun.jvmstat.monitor.MonitoredHostService;
-    provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService;
-    provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostLocalService;
+    provides sun.jvmstat.monitor.MonitoredHostService with
+        sun.jvmstat.perfdata.monitor.protocol.file.MonitoredHostFileService,
+        sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostLocalService;
 }
 
--- a/jdk/src/jdk.localedata/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.localedata/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,8 +25,7 @@
 
 module jdk.localedata {
     provides sun.util.locale.provider.LocaleDataMetaInfo with
-        sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo;
-    provides sun.util.locale.provider.LocaleDataMetaInfo with
+        sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo,
         sun.util.resources.provider.NonBaseLocaleDataMetaInfo;
     provides sun.util.resources.LocaleData.CommonResourceBundleProvider with
         sun.util.resources.provider.LocaleDataProvider;
--- a/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.management/share/classes/com/sun/management/VMOption.java	Thu Dec 01 21:39:49 2016 +0000
@@ -238,9 +238,4 @@
         }
 
     }
-
-    // for sun.management.MappedMXBeanType
-    static CompositeData toCompositeData(VMOption option) {
-        return VMOptionCompositeData.toCompositeData(option);
-    }
 }
--- a/jdk/src/jdk.management/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.management/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,7 @@
  */
 
 module jdk.management {
-    requires public java.management;
+    requires transitive java.management;
 
     exports com.sun.management;
 
--- a/jdk/src/jdk.naming.dns/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.naming.dns/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,8 +26,8 @@
 module jdk.naming.dns {
     requires java.naming;
 
-    exports com.sun.jndi.url.dns to
-        java.naming;
+    // temporary export until NamingManager.getURLContext uses services
+    exports com.sun.jndi.url.dns to java.naming;
 
     provides javax.naming.spi.InitialContextFactory
         with com.sun.jndi.dns.DnsContextFactory;
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericGroupPrincipal.java	Thu Dec 01 21:39:49 2016 +0000
@@ -54,14 +54,7 @@
     private static final long serialVersionUID = 2345199581042573224L;
 
     private static final java.util.ResourceBundle rb =
-          java.security.AccessController.doPrivileged
-          (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
-              public java.util.ResourceBundle run() {
-                  return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources",
-                                sun.security.util.ResourcesMgr.class.getModule()));
-              }
-          });
+        java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /**
      * @serial
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisNumericUserPrincipal.java	Thu Dec 01 21:39:49 2016 +0000
@@ -53,15 +53,7 @@
     private static final long serialVersionUID = -3178578484679887104L;
 
     private static final java.util.ResourceBundle rb =
-          java.security.AccessController.doPrivileged
-          (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
-              public java.util.ResourceBundle run() {
-                  return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources",
-                                 sun.security.util.ResourcesMgr.class.getModule()));
-              }
-           });
-
+        java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /**
      * @serial
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/SolarisPrincipal.java	Thu Dec 01 21:39:49 2016 +0000
@@ -51,14 +51,7 @@
     private static final long serialVersionUID = -7840670002439379038L;
 
     private static final java.util.ResourceBundle rb =
-          java.security.AccessController.doPrivileged
-          (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
-              public java.util.ResourceBundle run() {
-                  return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources",
-                                 sun.security.util.ResourcesMgr.class.getModule()));
-              }
-          });
+        java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");
 
 
     /**
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/X500Principal.java	Thu Dec 01 21:39:49 2016 +0000
@@ -56,14 +56,7 @@
     private static final long serialVersionUID = -8222422609431628648L;
 
     private static final java.util.ResourceBundle rb =
-        java.security.AccessController.doPrivileged
-        (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
-              public java.util.ResourceBundle run() {
-                  return (java.util.ResourceBundle.getBundle
-                                ("sun.security.util.AuthResources",
-                                 sun.security.util.ResourcesMgr.class.getModule()));
-              }
-        });
+        java.util.ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /**
      * @serial
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/JndiLoginModule.java	Thu Dec 01 21:39:49 2016 +0000
@@ -153,15 +153,8 @@
  */
 public class JndiLoginModule implements LoginModule {
 
-    private static final ResourceBundle rb = AccessController.doPrivileged(
-            new PrivilegedAction<ResourceBundle>() {
-                public ResourceBundle run() {
-                    return ResourceBundle.getBundle(
-                            "sun.security.util.AuthResources",
-                            sun.security.util.ResourcesMgr.class.getModule());
-                }
-            }
-    );
+    private static final ResourceBundle rb =
+        ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /** JNDI Provider */
     public final String USER_PROVIDER = "user.provider.url";
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/KeyStoreLoginModule.java	Thu Dec 01 21:39:49 2016 +0000
@@ -112,15 +112,8 @@
  */
 public class KeyStoreLoginModule implements LoginModule {
 
-    private static final ResourceBundle rb = AccessController.doPrivileged(
-            new PrivilegedAction<ResourceBundle>() {
-                public ResourceBundle run() {
-                    return ResourceBundle.getBundle(
-                            "sun.security.util.AuthResources",
-                            sun.security.util.ResourcesMgr.class.getModule());
-                }
-            }
-    );
+    private static final ResourceBundle rb =
+        ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /* -- Fields -- */
 
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java	Thu Dec 01 21:39:49 2016 +0000
@@ -419,15 +419,8 @@
 
     private static final String NAME = "javax.security.auth.login.name";
     private static final String PWD = "javax.security.auth.login.password";
-    private static final ResourceBundle rb = AccessController.doPrivileged(
-            new PrivilegedAction<ResourceBundle>() {
-                public ResourceBundle run() {
-                    return ResourceBundle.getBundle(
-                            "sun.security.util.AuthResources",
-                            sun.security.util.ResourcesMgr.class.getModule());
-                }
-            }
-    );
+    private static final ResourceBundle rb =
+        ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     /**
      * Initialize this {@code LoginModule}.
--- a/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java	Thu Dec 01 21:39:49 2016 +0000
@@ -306,15 +306,8 @@
 public class LdapLoginModule implements LoginModule {
 
     // Use the default classloader for this class to load the prompt strings.
-    private static final ResourceBundle rb = AccessController.doPrivileged(
-            new PrivilegedAction<ResourceBundle>() {
-                public ResourceBundle run() {
-                    return ResourceBundle.getBundle(
-                        "sun.security.util.AuthResources",
-                        sun.security.util.ResourcesMgr.class.getModule());
-                }
-            }
-        );
+    private static final ResourceBundle rb =
+        ResourceBundle.getBundle("sun.security.util.AuthResources");
 
     // Keys to retrieve the stored username and password
     private static final String USERNAME_KEY = "javax.security.auth.login.name";
--- a/jdk/src/jdk.security.auth/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.auth/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,24 +28,22 @@
  * various authentication modules.
  */
 module jdk.security.auth {
-    requires public java.naming;
+    requires transitive java.naming;
     requires java.security.jgss;
 
     exports com.sun.security.auth;
     exports com.sun.security.auth.callback;
     exports com.sun.security.auth.login;
     exports com.sun.security.auth.module;
-    provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.Krb5LoginModule;
-    provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.UnixLoginModule;
+
+    uses sun.security.util.AuthResourcesProvider;
+
     provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.JndiLoginModule;
-    provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.KeyStoreLoginModule;
-    provides javax.security.auth.spi.LoginModule with
-        com.sun.security.auth.module.LdapLoginModule;
-    provides javax.security.auth.spi.LoginModule with
+        com.sun.security.auth.module.Krb5LoginModule,
+        com.sun.security.auth.module.UnixLoginModule,
+        com.sun.security.auth.module.JndiLoginModule,
+        com.sun.security.auth.module.KeyStoreLoginModule,
+        com.sun.security.auth.module.LdapLoginModule,
         com.sun.security.auth.module.NTLoginModule;
 }
 
--- a/jdk/src/jdk.security.jgss/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.security.jgss/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,7 +28,7 @@
  * GSSAPI mechanism.
  */
 module jdk.security.jgss {
-    requires public java.security.jgss;
+    requires transitive java.security.jgss;
     requires java.logging;
     requires java.security.sasl;
     exports com.sun.security.jgss;
--- a/jdk/src/jdk.unsupported/share/classes/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/src/jdk.unsupported/share/classes/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,5 +27,8 @@
     exports sun.misc;
     exports sun.reflect;
     exports com.sun.nio.file;
+
+    opens sun.misc;
+    opens sun.reflect;
 }
 
--- a/jdk/test/ProblemList.txt	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/ProblemList.txt	Thu Dec 01 21:39:49 2016 +0000
@@ -145,10 +145,17 @@
 
 ############################################################################
 
-# jdk_jmx
+# jdk_management
 
 com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java 8030957 aix-all
 com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java  8030957 aix-all
+
+com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java 8169575 generic-all
+
+############################################################################
+
+# jdk_jmx
+
 javax/management/MBeanServer/OldMBeanServerTest.java            8030957 aix-all
 
 javax/management/remote/mandatory/notif/NotifReconnectDeadlockTest.java 8042215 generic-all
@@ -305,5 +312,8 @@
 # jdk_other
 
 com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java                   8169942 linux-i586,macosx-all,windows-x64
+javax/rmi/PortableRemoteObject/8146975/RmiIiopReturnValueTest.java 8169737 linux-all
+
+javax/xml/ws/clientjar/TestWsImport.java			8170370 generic-all
 
 ############################################################################
--- a/jdk/test/TEST.ROOT	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/TEST.ROOT	Thu Dec 01 21:39:49 2016 +0000
@@ -26,8 +26,8 @@
 # Allow querying of various System properties in @requires clauses
 requires.properties=sun.arch.data.model java.runtime.name
 
-# Tests using jtreg 4.2 b03 features
-requiredVersion=4.2 b03
+# Tests using jtreg 4.2 b04 features
+requiredVersion=4.2 b04
 
 # Path to libraries in the topmost test directory. This is needed so @library
 # does not need ../../ notation to reach them
--- a/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/corba/serialization/ObjectStreamTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -62,9 +62,10 @@
  * @test
  * @library /test/lib
  * @build jdk.test.lib.*
- * @compile  ObjectStreamTest.java  ObjectStreamTest$_Echo_Stub.java
- *           ObjectStreamTest$_Server_Tie.java
- * @modules java.corba/com.sun.corba.se.impl.io java.base/java.io
+ * @compile ObjectStreamTest.java  ObjectStreamTest$_Echo_Stub.java
+ *          ObjectStreamTest$_Server_Tie.java
+ * @modules java.base/java.io:open
+ *          java.corba/com.sun.corba.se.impl.io:+open
  *          java.corba/com.sun.corba.se.impl.activation
  * @summary Tests of ReflectionFactory use in IIOP Serialization
  * @run testng/othervm ObjectStreamTest
--- a/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/crypto/provider/Cipher/AES/TestGHASH.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,7 @@
 /*
  * @test
  * @bug 8069072
- * @modules java.base/com.sun.crypto.provider
+ * @modules java.base/com.sun.crypto.provider:open
  * @summary Test vectors for com.sun.crypto.provider.GHASH.
  *
  * Single iteration to verify software-only GHASH algorithm.
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/CheckPBEKeySize.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,8 @@
 /**
  * @test
  * @bug 8151149
- * @modules java.base/com.sun.crypto.provider
+ * @modules java.base/javax.crypto:open
+ *          java.base/com.sun.crypto.provider:+open
  */
 
 import java.lang.reflect.*;
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/NegativeLength.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 8001596
+ * @modules java.base/javax.crypto.spec:open
  * @summary Incorrect condition check in PBKDF2KeyImpl.java
  */
 
--- a/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,7 +28,7 @@
  *
  *  @author Egor Ushakov
  *
- *  @modules jdk.jdi/com.sun.tools.jdi
+ *  @modules jdk.jdi/com.sun.tools.jdi:+open
  *  @run build TestScaffold VMConnection
  *  @run compile -g ConstantPoolInfoGC.java
  *  @run main/othervm ConstantPoolInfoGC
--- a/jdk/test/com/sun/jdi/ModulesTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/jdi/ModulesTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -78,7 +78,6 @@
         }
         // Sanity checks: make sure there is no crash or exception
         String otherName = other.name();
-        boolean cond = module.canRead(other);
         return true;
     }
 
@@ -159,8 +158,6 @@
             }
             bootUnnamedModule = module;
         }
-        boolean cond = module.canRead(other);
-        println("    can read: " + cond);
     }
 
     // Check that the java.lang.String class was loaded by the java.base module.
@@ -198,24 +195,6 @@
             testFailed = true;
             println(FailPrefix + "unnamed module of PlatformClassLoader was not observed");
         }
-
-        for (ModuleReference module : modules) {
-            if (!bootUnnamedModule.canRead(module)) {
-                testFailed = true;
-                println(FailPrefix + "boot unnamed module must read any module" +
-                        "but a non-readible module is found: " + module.name());
-            }
-            if (!appUnnamedModule.canRead(module)) {
-                testFailed = true;
-                println(FailPrefix + "app unnamed module must read any module" +
-                        "but a non-readible module is found: " + module.name());
-            }
-            if (!extUnnamedModule.canRead(module)) {
-                testFailed = true;
-                println(FailPrefix + "ext unnamed module must read any module" +
-                        "but a non-readible module is found: " + module.name());
-            }
-        }
     }
 
     protected void runTests() throws Exception {
--- a/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/jdi/connect/spi/GeneratedConnectors.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,8 +30,8 @@
  * to encapsulate the transport. This tests that the connectors are
  * created and that they have an "address" argument.
  *
- * @modules jdk.jdi
- * @build GeneratedConnectors NullTransportService
+ * @modules jdk.jdi/com.sun.tools.jdi
+ * @build GeneratedConnectors NullTransportService SimpleLaunchingConnector
  * @run main/othervm GeneratedConnectors
  */
 
--- a/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -33,7 +33,7 @@
  *          with a lower-case letter
  *
  * @author Jaroslav Bachorik
- * @modules java.management/com.sun.jmx.mbeanserver
+ * @modules java.management/com.sun.jmx.mbeanserver:open
  * @run clean SimpleIntrospectorTest
  * @run build SimpleIntrospectorTest BeanClass
  * @run main SimpleIntrospectorTest
--- a/jdk/test/com/sun/jndi/dns/Parser.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/jndi/dns/Parser.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,7 @@
  * @test
  * @bug 8035105
  * @summary DNS resource record parsing
- * @modules jdk.naming.dns/com.sun.jndi.dns
+ * @modules jdk.naming.dns/com.sun.jndi.dns:+open
  * @compile --add-modules jdk.naming.dns Parser.java
  */
 
--- a/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/jndi/ldap/SimpleClientIdHashCode.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,7 @@
  * @test
  * @bug 8158802
  * @summary com.sun.jndi.ldap.SimpleClientId produces wrong hash code
- * @modules java.naming/com.sun.jndi.ldap
+ * @modules java.naming/com.sun.jndi.ldap:open
  */
 
 import java.io.OutputStream;
--- a/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/UnbindIdempotent.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/jndi/rmi/registry/RegistryContext/UnbindIdempotent.java	Thu Dec 01 21:39:49 2016 +0000
@@ -43,7 +43,7 @@
 public class UnbindIdempotent {
 
     public static void main(String[] args) throws Exception {
-        Registry registry = TestLibrary.createRegistryOnUnusedPort();
+        Registry registry = TestLibrary.createRegistryOnEphemeralPort();
         int registryPort = TestLibrary.getRegistryPort(registry);
         InitialContext ictx = new InitialContext();
         Context rctx;
--- a/jdk/test/com/sun/management/VMOptionOpenDataTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/management/VMOptionOpenDataTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,58 +21,77 @@
  * questions.
  */
 
+import com.sun.management.HotSpotDiagnosticMXBean;
 import com.sun.management.VMOption;
-import java.io.InvalidObjectException;
-import java.util.Objects;
-import javax.management.openmbean.OpenDataException;
-import sun.management.MappedMXBeanType;
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.management.MBeanServerConnection;
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenType;
+
+import static javax.management.openmbean.SimpleType.*;
 
 /*
  * @test
  * @bug     8042901
  * @summary Check that MappedMXBeanType.toOpenTypeData supports VMOption
- * @modules java.management/sun.management
- *          jdk.management/com.sun.management
+ * @modules jdk.management/com.sun.management
  * @author  Shanliang Jiang
  */
 public class VMOptionOpenDataTest {
-    public static void main(String[] args) throws Exception {
-        System.out.println("--- VMOptionOpenDataTest-main: Checking that "
-                + "MappedMXBeanType.toOpenTypeData supports VMOption");
-        Exception failed = null;
-        try {
-            VMOption vo = new VMOption("toto", "titi", true, VMOption.Origin.OTHER);
-            System.out.println("--- Construct a VMOption object: \"" + vo + "\"");
+    private static final String[] names = new String[] {
+        "name", "value", "origin", "writeable"
+    };
+    private static final OpenType[] types = new OpenType[] {
+        STRING, STRING, STRING, BOOLEAN
+    };
 
-            Object open = MappedMXBeanType.toOpenTypeData(vo, VMOption.class);
-            System.out.println("--- Map it to an open type:  \"" + open +" \"");
+    public static void main(String... args) throws Exception {
+        MBeanServerConnection msc = ManagementFactory.getPlatformMBeanServer();
+        HotSpotDiagnosticMXBean mxbean =
+            ManagementFactory.getPlatformMXBean(msc, HotSpotDiagnosticMXBean.class);
+
 
-            Object back = MappedMXBeanType.toJavaTypeData(open, VMOption.class);
-            System.out.println("--- Map it back to java type:  \"" + back +" \"");
+        String[] signatures = new String[] {
+            String.class.getName()
+        };
+        Object obj = msc.invoke(mxbean.getObjectName(), "getVMOption",
+            new String[] { "PrintVMOptions"}, signatures);
 
-            if (back == null) {
-                failed = new RuntimeException("Failed, mapping back got null.");
-            } else if (!(back instanceof VMOption)) {
-                failed = new RuntimeException("Failed, not mapped back to a VMOption: "
-                        +back.getClass());
-            } else {
-                VMOption mapBack = (VMOption)back;
-                if (!Objects.equals(vo.getName(), mapBack.getName()) ||
-                        !Objects.equals(vo.getOrigin(), mapBack.getOrigin()) ||
-                        !Objects.equals(vo.getValue(), mapBack.getValue()) ||
-                        vo.isWriteable() != mapBack.isWriteable()) {
-                    failed = new RuntimeException(
-                            "Failed, failed to map back the original VMOtion.");
-                }
+        CompositeData data = (CompositeData)obj;
+        validateType(data);
+
+        VMOption option = mxbean.getVMOption("PrintVMOptions");
+        VMOption o = VMOption.from(data);
+        assertEquals(option, o);
+    }
+
+    private static void validateType(CompositeData data) {
+        CompositeType type = data.getCompositeType();
+        Set<String> keys = Arrays.stream(names).collect(Collectors.toSet());
+        if (!type.keySet().equals(keys)) {
+            throw new RuntimeException("key not matched: " + type.keySet().toString());
+        }
+        for (int i=0; i < names.length; i++) {
+            OpenType t = type.getType(names[i]);
+            if (t != types[i]) {
+                throw new AssertionError(names[i] + ": type not matched: " +
+                    t + " expected: " + types[i]);
             }
-        } catch (OpenDataException | InvalidObjectException ode) {
-            failed = ode;
-        }
-        if (failed == null) {
-            System.out.println("--- PASSED!");
-        } else {
-            System.out.println("--- Failed: "+failed.getMessage());
-            throw failed;
         }
     }
+
+    private static void assertEquals(VMOption o1, VMOption o2) {
+        if (!o1.getName().equals(o2.getName()) ||
+            !o1.getOrigin().equals(o2.getOrigin()) ||
+            !o1.getValue().equals(o2.getValue()) ||
+            o1.isWriteable() != o2.isWriteable()) {
+            throw new AssertionError(o1 + " != " + o2);
+        }
+
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/security/auth/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,1 @@
+modules = jdk.security.auth
--- a/jdk/test/com/sun/security/jgss/InquireSecContextPermissionCheck.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/security/jgss/InquireSecContextPermissionCheck.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -21,9 +21,10 @@
  * questions.
  */
 
-/**
+/*
  * @test
  * @bug 6710360
+ * @modules jdk.security.jgss
  * @summary export Kerberos session key to applications
  */
 
--- a/jdk/test/com/sun/security/sasl/Cram.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/com/sun/security/sasl/Cram.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 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
@@ -24,15 +24,17 @@
 /*
  * @test
  * @bug 4634892
+ * @modules jdk.security.auth
  * @summary Ensure that authentication via CRAM-MD5 works.
  */
 
 /*
  * Can set logging to FINEST to view exchange.
  */
-import javax.security.sasl.*;
-import javax.security.auth.callback.*;
-import java.security.Security;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslServer;
 
 public class Cram {
     private static final String MECH = "CRAM-MD5";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/security/sasl/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,1 @@
+modules = java.security.sasl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/security/sasl/digest/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,1 @@
+modules = jdk.security.auth
--- a/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/EventDispatchThread/EDTShutdownTest/EDTShutdownTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,6 +27,7 @@
   @summary [macosx] TwentyThousandTest test intermittently hangs
   @author Oleg Pekhovskiy
   @modules java.desktop/sun.awt
+  @modules java.desktop/java.awt:open
   @run main EDTShutdownTest
  */
 
--- a/jdk/test/java/awt/Focus/DisposedWindow/DisposeDialogNotActivateOwnerTest/DisposeDialogNotActivateOwnerTest.html	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-<!--
- Copyright (c) 2006, 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.
--->
-
-<html>
-<!--
-  @test
-  @key headful
-  @bug        6386592
-  @summary    Tests that disposing a dialog doesn't activate its invisible owner.
-  @author     anton.tarasov@sun.com: area=awt.focus
-  @run        applet DisposeDialogNotActivateOwnerTest.html
-  -->
-<head>
-<title>DisposeDialogNotActivateOwnerTest</title>
-</head>
-<body>
- 
-<h1>DisposeDialogNotActivateOwnerTest<br>Bug ID: 6386592</h1>
- 
-<p>See the dialog box (usually in upper left corner) for instructions</p>
- 
-<APPLET CODE=DisposeDialogNotActivateOwnerTest.class WIDTH=200 HEIGHT=200></APPLET>
-</body>
-</html>
--- a/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/Focus/RequestOnCompWithNullParent/RequestOnCompWithNullParent1.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
   @library ../../regtesthelpers
   @modules java.desktop/java.awt.peer
            java.desktop/sun.awt
+           java.desktop/java.awt:open
   @build Util
   @run main RequestOnCompWithNullParent1
 */
--- a/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html	Thu Dec 01 21:39:49 2016 +0000
@@ -30,7 +30,7 @@
   @requires (os.family == "linux" | os.family == "solaris")
   @modules java.desktop/sun.awt
            java.desktop/java.awt.peer
-           java.desktop/sun.awt.X11
+           java.desktop/sun.awt.X11:open
   @run applet FocusEmptyListTest.html
   -->
 <head>
--- a/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/Modal/LWModalTest/LWModalTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,6 +28,7 @@
   @summary The test checks that Container's method startLWModal
 and stopLWModal work correctly. The test scenario is very close
 to JOptionPane.showInternal*Dialog methods
+  @modules java.desktop/java.awt:open
   @author artem.ananiev@...: area=awt.modal
   @library ../../regtesthelpers
   @build Util
--- a/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TextArea/TextAreaCaretVisibilityTest/bug7129742.java	Thu Dec 01 21:39:49 2016 +0000
@@ -34,7 +34,7 @@
  * @requires (os.family == "linux" | os.family == "solaris")
  * @modules java.desktop/sun.awt
  *          java.desktop/java.awt.peer
- *          java.desktop/sun.awt.X11
+ *          java.desktop/sun.awt.X11:open
  * @author Sean Chou
  */
 
--- a/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/Toolkit/Headless/WrappedToolkitTest/WrappedToolkitTest.sh	Thu Dec 01 21:39:49 2016 +0000
@@ -154,16 +154,16 @@
 case "$OS" in
   Windows* | CYGWIN* )
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
                          TestWrapped sun.awt.windows.WToolkit
     status=$?
     if [ ! $status -eq "0" ]; then
       fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.awt.windows.WToolkit";
     fi
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.awt.windows=ALL-UNNAMED ${CP} \
                          -Dawt.toolkit=sun.awt.windows.WToolkit \
                          TestWrapped sun.awt.windows.WToolkit
     status=$?
@@ -174,8 +174,8 @@
 
   SunOS | Linux )
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
                          -Dawt.toolkit=sun.awt.X11.XToolkit \
                          TestWrapped sun.awt.X11.XToolkit
     status=$?
@@ -183,8 +183,8 @@
       fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.awt.xawt.XToolkit";
     fi
     AWT_TOOLKIT=XToolkit ${TESTJAVA}/bin/java ${TESTVMOPTS} \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.awt.X11=ALL-UNNAMED ${CP} \
                                               -Djava.awt.headless=true \
                                               TestWrapped sun.awt.X11.XToolkit
     status=$?
@@ -195,16 +195,16 @@
 
   Darwin)
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
                          TestWrapped sun.lwawt.macosx.LWCToolkit
     status=$?
     if [ ! $status -eq "0" ]; then
       fail "Test FAILED: toolkit wrapped into HeadlessToolkit is not an instance of sun.lwawt.macosx.LWCToolkit";
     fi
     ${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.awt.headless=true \
-                         --add-exports java.desktop/sun.awt=ALL-UNNAMED \
-                         --add-exports java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
+                         --add-opens java.desktop/sun.awt=ALL-UNNAMED \
+                         --add-opens java.desktop/sun.lwawt.macosx=ALL-UNNAMED ${CP} \
                          -Dawt.toolkit=sun.lwawt.macosx.LWCToolkit \
                          TestWrapped sun.lwawt.macosx.LWCToolkit
     status=$?
--- a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,6 +30,7 @@
  *          of the ActionEvent triggered when TrayIcon is double clicked
  *          (single clicked, on Mac)
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library ../../../../lib/testlibrary ../
  * @library /java/awt/patchlib
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java	Thu Dec 01 21:39:49 2016 +0000
@@ -33,6 +33,7 @@
  *          triggered when multiple AWTEventListeners and ActionListeners
  *          are added.
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/ActionEventTest/ActionEventTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,8 @@
  * @test
  * @bug 6191390 8154328
  * @summary Verify that ActionEvent is received with correct modifiers set.
+ * @modules java.desktop/java.awt:open
+ * @modules java.desktop/java.awt.peer
  * @library ../../../../lib/testlibrary ../
  * @library /java/awt/patchlib
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
  * @test
  * @summary Check for MouseEvents with all mouse buttons
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build ExtendedRobot SystemTrayIconHelper
--- a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -32,6 +32,7 @@
  *          checks if all listeners are triggered when AWTEventListeners
  *          and MouseListeners are added.
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
  * @test
  * @summary Check for MouseEvents with all mouse buttons
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../../lib/testlibrary ../../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -39,6 +39,7 @@
  * @key headful
  * @summary Check if MouseEvent has the proper modifiers when
  *          TrayIcon is clicked pressing the modifier keys
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,6 +30,7 @@
  * @test
  * @summary Check for MouseEvents with all mouse buttons
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -34,6 +34,7 @@
  *          it is double clicked with mouse button 1 on windows
  *          or single clicked with button 3 on Mac OS X
  *          or single clicked with button 1 on rest.
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
  * @summary Check if a JPopupMenu can be displayed when TrayIcon is
  *          right clicked. It uses a JWindow as the parent of the JPopupMenu
  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
+ * @modules java.desktop/java.awt:open
  * @library /java/awt/patchlib
  * @library ../../../../lib/testlibrary ../
  * @build java.desktop/java.awt.Helper
--- a/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,7 @@
   @key headful
   @bug 6758673
   @summary Tests that windows are removed from owner's child windows list
+  @modules java.desktop/java.awt:open
   @author art: area=awt.toplevel
   @run main/othervm -mx128m OwnedWindowsLeak
 */
--- a/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/event/InputEvent/ButtonArraysEquality/ButtonArraysEquality.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,6 +27,7 @@
   @bug 6315717
   @summary verifies that InputEvents button masks arrays are the same
   @author Andrei Dmitriev : area=awt.event
+  @modules java.desktop/java.awt.event:open
   @run main ButtonArraysEquality
  */
 
--- a/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/event/MouseEvent/CheckGetMaskForButton/CheckGetMaskForButton.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
   @test %I% %E%
   @key headful
   @bug 6315717
+  @modules java.desktop/java.awt.event:open
   @summary verifies that InputEvent.getMaskForButton() returns the same values as in InputEvent.BUTTON_DOWN_MASK
   @author Andrei Dmitriev : area=awt.event
   @run main CheckGetMaskForButton
--- a/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/font/FontNames/GetLCIDFromLocale.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 4351212
- * @modules java.desktop/sun.font
+ * @modules java.desktop/sun.font:open
  * @summary Verify that new getLCIDFromLocale method works
  */
 
--- a/jdk/test/java/awt/image/MultiResolutionImageTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/image/MultiResolutionImageTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -48,7 +48,7 @@
  * @requires (os.family == "mac")
  * @modules java.desktop/sun.awt
  *          java.desktop/sun.awt.image
- *          java.desktop/sun.lwawt.macosx
+ *          java.desktop/sun.lwawt.macosx:open
  * @run main MultiResolutionImageTest TOOLKIT_PREPARE
  * @run main MultiResolutionImageTest TOOLKIT_LOAD
  * @run main MultiResolutionImageTest TOOLKIT
--- a/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,6 @@
 public class Helper {
     private Helper() { }
     public static void addExports(String pn, Module target) {
-        java.awt.Component.class.getModule().addExports(pn, target);
+        java.awt.Component.class.getModule().addOpens(pn, target);
     }
 }
--- a/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/beans/Introspector/6380849/TestBeanInfo.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 6380849
  * @summary Tests BeanInfo finder
+ * @modules java.desktop/java.beans:open
  * @author Sergey Malenkov
  */
 
--- a/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/beans/XMLEncoder/java_awt_CardLayout.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8007458
  * @summary Tests CardLayout encoding
+ * @modules java.desktop/java.awt:open
  * @author Sergey Malenkov
  */
 
--- a/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/beans/XMLEncoder/java_awt_GridBagLayout.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8007458
  * @summary Tests GridBagLayout encoding
+ * @modules java.desktop/java.awt:open
  * @author Sergey Malenkov
  */
 
--- a/jdk/test/java/io/FilePermission/Correctness.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/io/FilePermission/Correctness.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  *
  * @test
  * @bug 8164705
+ * @modules java.base/java.io:open
  * @summary Remove pathname canonicalization from FilePermission
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/FilePermission/MergeName.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,84 @@
+/*
+ * 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 jdk.test.lib.process.ProcessTools;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * @test
+ * @bug 8170364
+ * @summary FilePermission path modified during merge
+ * @library /test/lib
+ */
+
+public class MergeName {
+
+    public static final String[] ALL_ACTIONS
+            = {"read", "write", "execute", "delete"};
+
+    public static void main(String[] args) throws Exception {
+        if (args.length == 0) {
+            test("p1", "read", "write", "delete", "execute");
+            test("p2", "read,write", "delete,execute");
+            test("p3", "read,write,delete", "execute");
+            test("p4", "read,write,delete,execute");
+        } else {
+            SecurityManager sm = System.getSecurityManager();
+            for (String arg : args) {
+                // Use bits to create powerset of ALL_ACTIONS
+                IntStream.range(1, 16)
+                        .mapToObj(n -> IntStream.range(0, 4)
+                                .filter(x -> (n & (1 << x)) != 0)
+                                .mapToObj(x -> ALL_ACTIONS[x])
+                                .collect(Collectors.joining(",")))
+                        .forEach(a -> sm.checkPermission(
+                                new FilePermission(arg, a)));
+            }
+        }
+    }
+
+    private static void test(String file, String... actions) throws Exception {
+        List<String> content = new ArrayList<>();
+        content.add("grant {");
+        for (String action : actions) {
+            content.add("   permission java.io.FilePermission " +
+                    "\"x\", \"" +action + "\";");
+        }
+        content.add("};");
+        Files.write(Paths.get(file), content);
+        ProcessTools.executeTestJvm("-Djava.security.manager",
+                "-Djava.security.policy=" + file,
+                "MergeName",
+                "x",
+                new File(System.getProperty("user.dir"), "x").getPath())
+            .shouldHaveExitValue(0);
+    }
+}
--- a/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/io/ObjectInputStream/PeekInputStreamTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,6 +30,7 @@
 /*
  * @test
  * @bug 8067870
+ * @modules java.base/java.io:open
  * @summary verifies java.io.ObjectInputStream.PeekInputStream.skip works
  *          as intended
  */
--- a/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,8 @@
  * @bug 8080535
  * @summary Expected size of Character.UnicodeBlock.map is not optimal
  * @library /lib/testlibrary
+ * @modules java.base/java.lang:open
+ *          java.base/java.util:open
  * @build jdk.testlibrary.OptimalCapacity
  * @run main OptimalMapSize
  */
--- a/jdk/test/java/lang/Class/GetModuleTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/GetModuleTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -31,7 +31,6 @@
  */
 
 import java.awt.Component;
-import java.lang.reflect.Field;
 import java.lang.reflect.Module;
 
 import jdk.internal.org.objectweb.asm.ClassWriter;
@@ -44,16 +43,7 @@
 
 public class GetModuleTest {
 
-    static final Unsafe U;
-    static {
-        try {
-            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-            theUnsafe.setAccessible(true);
-            U = (Unsafe) theUnsafe.get(null);
-        } catch (Exception e) {
-            throw new AssertionError(e);
-        }
-    }
+    private static final Unsafe U = Unsafe.getUnsafe();
 
     private static final Module TEST_MODULE = GetModuleTest.class.getModule();
 
--- a/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -44,7 +44,7 @@
         try {
             Class<?> c = findClass(m1, "p1.internal.B");
             c.newInstance();
-            throw new RuntimeException(c.getName() + " is not exported to m2");
+            throw new RuntimeException(c.getName() + " should not be exported to m2");
         } catch (IllegalAccessException e) {}
     }
 
--- a/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/getDeclaredField/ClassDeclaredFieldsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -40,6 +40,7 @@
  *          set accessible if the right permission is granted; this test
  *          also verifies that Class.classLoader final private field is
  *          hidden from reflection access.
+ * @modules java.base/java.lang:open
  * @run main/othervm ClassDeclaredFieldsTest UNSECURE
  * @run main/othervm ClassDeclaredFieldsTest SECURE
  *
--- a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -58,9 +58,9 @@
 /**
  * @test
  * @bug 8065552
- * @summary test that all fields returned by getDeclaredFields() can be
- *          set accessible if the right permission is granted; this test
- *          loads all the classes in the BCL, get their declared fields,
+ * @summary test that all public fields returned by getDeclaredFields() can
+ *          be set accessible if the right permission is granted; this test
+ *          loads all classes and get their declared fields
  *          and call setAccessible(false) followed by setAccessible(true);
  * @modules java.base/jdk.internal.module
  * @run main/othervm --add-modules=ALL-SYSTEM FieldSetAccessibleTest UNSECURE
@@ -81,24 +81,30 @@
 
 
     // Test that all fields for any given class can be made accessibles
-    static void testSetFieldsAccessible(Class<?> c, boolean expectException) {
+    static void testSetFieldsAccessible(Class<?> c) {
+        Module self = FieldSetAccessibleTest.class.getModule();
+        Module target = c.getModule();
+        String pn = c.getPackageName();
+        boolean exported = self.canRead(target) && target.isExported(pn, self);
         for (Field f : c.getDeclaredFields()) {
             fieldCount.incrementAndGet();
-            boolean expect = expectException;
-            if ((c == Module.class || c == AccessibleObject.class) &&
-                !Modifier.isPublic(f.getModifiers())) {
-                expect = true;
-            }
+
+            // setAccessible succeeds only if it's exported and the member
+            // is public and of a public class, or it's opened
+            // otherwise it would fail.
+            boolean isPublic = Modifier.isPublic(f.getModifiers()) &&
+                Modifier.isPublic(c.getModifiers());
+            boolean access = (exported && isPublic) || target.isOpen(pn, self);
             try {
                 f.setAccessible(false);
                 f.setAccessible(true);
-                if (expect) {
+                if (!access) {
                     throw new RuntimeException(
                         String.format("Expected InaccessibleObjectException is not thrown "
                                       + "for field %s in class %s%n", f.getName(), c.getName()));
                 }
             } catch (InaccessibleObjectException expected) {
-                if (!expect) {
+                if (access) {
                     throw new RuntimeException(expected);
                 }
             }
@@ -110,18 +116,17 @@
     public static boolean test(Class<?> c, boolean addExports) {
         Module self = FieldSetAccessibleTest.class.getModule();
         Module target = c.getModule();
-        String pn = c.getPackage().getName();
+        String pn = c.getPackageName();
         boolean exported = self.canRead(target) && target.isExported(pn, self);
         if (addExports && !exported) {
             Modules.addExports(target, pn, self);
             exported = true;
         }
-        boolean expectException = !exported;
 
         classCount.incrementAndGet();
 
         // Call getDeclaredFields() and try to set their accessible flag.
-        testSetFieldsAccessible(c, expectException);
+        testSetFieldsAccessible(c);
 
         // add more tests here...
 
--- a/jdk/test/java/lang/Class/getResource/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/getResource/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,6 @@
 import java.lang.module.Configuration;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -33,8 +32,8 @@
 import java.nio.file.Paths;
 
 /**
- * Basic test of Class getResource and getResourceAsStream when invoked from
- * code in named modules.
+ * Basic test of Class getResource and getResourceAsStream to locate/read
+ * resources in named modules.
  */
 
 public class Main {
@@ -43,62 +42,192 @@
 
     public static void main(String[] args) throws IOException {
 
-        // create m1/myresource containing "m1"
-        Path file = directoryFor("m1").resolve(NAME);
-        Files.write(file, "m1".getBytes("UTF-8"));
+        // create resources in m1
+        createResource("m1", Paths.get("."), "m1");
+        createResource("m1", Paths.get("p1"), "m1/p1");
+        createResource("m1", Paths.get("p1", "impl"), "m1/p1.impl");
+        createResource("m1", Paths.get("p1", "resources"), "m1/p1.resources");
+
+        // create resources in m2
+        createResource("m2", Paths.get("."), "m2");
+        createResource("m2", Paths.get("p2"), "m2/p2");
+        createResource("m2", Paths.get("p2", "impl"), "m2/p2.impl");
+        createResource("m2", Paths.get("p2", "resources"), "m2/p2.resources");
+
+
+        // invoke Class getResource from an unnamed module.
+        URL url = Main.class.getResource("/" + NAME);
+        assertNotNull(url);
+
+        url = Main.class.getResource("/p1/" + NAME);
+        assertNull(url);
 
-        // create m2/myresource containing "m2"
-        file = directoryFor("m2").resolve(NAME);
-        Files.write(file, "m2".getBytes("UTF-8"));
+        url = Main.class.getResource("/p1/impl/" + NAME);
+        assertNull(url);
+
+        url = Main.class.getResource("/p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        url = Main.class.getResource("/p2/" + NAME);
+        assertNull(url);
+
+        url = Main.class.getResource("/p2/impl/" + NAME);
+        assertNull(url);
 
-        // check that m3/myresource does not exist
-        assertTrue(Files.notExists(directoryFor("m3").resolve(NAME)));
+        // m1: exports private p1.resources
+        url = Main.class.getResource("/p2/resources/" + NAME);
+        assertNull(url);
+
+
+        // invoke Class getResource from module m1
+        url = p1.Main.getResource("/" + NAME);
+        assertEquals(readAllAsString(url), "m1");
+
+        url = p1.Main.getResource("/p1/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1");
 
-        // invoke Class getResource from the unnamed module
-        URL url0 = Main.class.getResource("/" + NAME);
-        assertNull(url0);
+        url = p1.Main.getResource("/p1/impl/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.impl");
+
+        url = p1.Main.getResource("/p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        // m2: not a named package
+        url = p1.Main.getResource(p2.Main.class, "/" + NAME);
+        assertEquals(readAllAsString(url), "m2");
+
+        url = p1.Main.getResource(p2.Main.class, "/p2/" + NAME);
+        assertNull(url);
+
+        // m2: exports p2.impl to m1
+        url = p1.Main.getResource(p2.Main.class, "/p2/impl/" + NAME);
+        assertNull(url);
+
+        // m2: exports private p2.resources to m1;
+        url = p1.Main.getResource(p2.Main.class, "/p2/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m2/p2.resources");
+
 
-        // invoke Class getResource from modules m1-m3
-        URL url1 = p1.Main.getResource("/" + NAME);
-        URL url2 = p2.Main.getResource("/" + NAME);
-        URL url3 = p3.Main.getResource("/" + NAME);
-        assertNotNull(url1);
-        assertNotNull(url2);
-        assertNull(url3);
+        // invoke Class getResource from module m2
+        url = p2.Main.getResource("/" + NAME);
+        assertEquals(readAllAsString(url), "m2");
+
+        url = p2.Main.getResource("/p2/" + NAME);
+        assertEquals(readAllAsString(url), "m2/p2");
+
+        url = p2.Main.getResource("/p2/impl/" + NAME);
+        assertEquals(readAllAsString(url), "m2/p2.impl");
+
+        url = p2.Main.getResource("/p2/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m2/p2.resources");
 
-        // check contents of resurces at url1 and url2
-        assertEquals(new String(readAll(url1), "UTF-8"), "m1");
-        assertEquals(new String(readAll(url2), "UTF-8"), "m2");
+        // m1: not a named package
+        url = p2.Main.getResource(p1.Main.class, "/" + NAME);
+        assertEquals(readAllAsString(url), "m1");
+
+        url = p2.Main.getResource(p1.Main.class, "/p1/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResource(p1.Main.class, "/p1/impl/" + NAME);
+        assertNull(url);
+
+        // m1: exports private p1.resources;
+        url = p2.Main.getResource(p1.Main.class, "/p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
 
-        // invoke Class getResourceAsStream from the unnamed module
-        InputStream in0 = Main.class.getResourceAsStream("/" + NAME);
-        assertNull(in0);
+
+        // invoke Class getResourceAsStream from an unnamed module.
+        InputStream in = Main.class.getResourceAsStream("/" + NAME);
+        assertNotNull(in);
+
+        in = Main.class.getResourceAsStream("/p1/" + NAME);
+        assertNull(in);
+
+        in = Main.class.getResourceAsStream("/p1/impl/" + NAME);
+        assertNull(in);
+
+        in = Main.class.getResourceAsStream("/p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = Main.class.getResourceAsStream("/p2/" + NAME);
+        assertNull(in);
+
+        in = Main.class.getResourceAsStream("/p2/impl/" + NAME);
+        assertNull(in);
+
+        in = Main.class.getResourceAsStream("/p2/resources/" + NAME);
+        assertNull(in);
+
+
+        // invoke Class getResourceAsStream from module m1
+        in = p1.Main.getResourceAsStream("/" + NAME);
+        assertEquals(readAllAsString(in), "m1");
+
+        in = p1.Main.getResourceAsStream("/p1/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1");
+
+        in = p1.Main.getResourceAsStream("/p1/impl/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.impl");
+
+        in = p1.Main.getResourceAsStream("/p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = p1.Main.getResourceAsStream(p2.Main.class, "/" + NAME);
+        assertEquals(readAllAsString(in), "m2");
+
+        in = p1.Main.getResourceAsStream(p2.Main.class, "/p2/" + NAME);
+        assertNull(in);
+
+        in = p1.Main.getResourceAsStream(p2.Main.class, "/p2/impl/" + NAME);
+        assertNull(in);
 
-        // invoke Class getResourceAsStream from modules m1-m3
-        try (InputStream in = p1.Main.getResourceAsStream("/" + NAME)) {
-            String s = new String(in.readAllBytes(), "UTF-8");
-            assertEquals(s, "m1");
-        }
-        try (InputStream in = p2.Main.getResourceAsStream("/" + NAME)) {
-            String s = new String(in.readAllBytes(), "UTF-8");
-            assertEquals(s, "m2");
-        }
-        InputStream in3 = p3.Main.getResourceAsStream("/" + NAME);
-        assertNull(in3);
+        in = p1.Main.getResourceAsStream(p2.Main.class, "/p2/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m2/p2.resources");
+
+
+        // invoke Class getResourceAsStream from module m2
+        in = p2.Main.getResourceAsStream("/" + NAME);
+        assertEquals(readAllAsString(in), "m2");
+
+        in = p2.Main.getResourceAsStream("/p2/" + NAME);
+        assertEquals(readAllAsString(in), "m2/p2");
+
+        in = p2.Main.getResourceAsStream("/p2/impl/" + NAME);
+        assertEquals(readAllAsString(in), "m2/p2.impl");
+
+        in = p2.Main.getResourceAsStream("/p2/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m2/p2.resources");
+
+        in = p2.Main.getResourceAsStream(p1.Main.class, "/" + NAME);
+        assertEquals(readAllAsString(in), "m1");
+
+        in = p2.Main.getResourceAsStream(p1.Main.class, "/p1/" + NAME);
+        assertNull(in);
 
-        // invoke Module getResources on modules m1-m3
-        InputStream in1 = p1.Main.class.getModule().getResourceAsStream("/" + NAME);
-        InputStream in2 = p2.Main.class.getModule().getResourceAsStream("/" + NAME);
-        in3 = p3.Main.class.getModule().getResourceAsStream("/" + NAME);
-        assertNotNull(in1);
-        assertNotNull(in2);
-        assertNull(in3);
+        in = p2.Main.getResourceAsStream(p1.Main.class, "/p1/impl/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStream(p1.Main.class, "/p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
 
-        // check the content of in1 and in2
-        String s1 = new String(in1.readAllBytes(), "UTF-8");
-        String s2 = new String(in2.readAllBytes(), "UTF-8");
-        assertEquals(s1, "m1");
-        assertEquals(s2, "m2");
+        // Nulls
+        try {
+            Main.class.getResource(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+        try {
+            Main.class.getResourceAsStream(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+        try {
+            p1.Main.class.getResource(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+        try {
+            p1.Main.class.getResourceAsStream(null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
 
         // SecurityManager case
         System.setSecurityManager(new SecurityManager());
@@ -106,17 +235,24 @@
         assertNull(Main.class.getResource("/" + NAME));
         assertNull(p1.Main.getResource("/" + NAME));
         assertNull(p2.Main.getResource("/" + NAME));
-        assertNull(p3.Main.getResource("/" + NAME));
 
         assertNull(Main.class.getResourceAsStream("/" + NAME));
         assertNull(p1.Main.getResourceAsStream("/" + NAME));
         assertNull(p2.Main.getResourceAsStream("/" + NAME));
-        assertNull(p3.Main.getResourceAsStream("/" + NAME));
 
         System.out.println("Success!");
     }
 
     /**
+     * Create a resource in the sub-directory of the given exploded module
+     */
+    static void createResource(String mn, Path subdir, String msg) throws IOException {
+        Path dir = directoryFor(mn).resolve(subdir);
+        Path file = dir.resolve(NAME);
+        Files.write(file, msg.getBytes("UTF-8"));
+    }
+
+    /**
      * Returns the directory for the given module (by name).
      */
     static Path directoryFor(String name) {
@@ -130,12 +266,21 @@
         return dir;
     }
 
-    static byte[] readAll(URL url) throws IOException {
-        try (InputStream in = url.openStream()) {
-            return in.readAllBytes();
+    static String readAllAsString(InputStream in) throws IOException {
+        if (in == null)
+            return null;
+        try (in) {
+            return new String(in.readAllBytes(), "UTF-8");
         }
     }
 
+    static String readAllAsString(URL url) throws IOException {
+        if (url == null)
+            return null;
+        InputStream in = url.openStream();
+        return readAllAsString(url.openStream());
+    }
+
     static void assertTrue(boolean condition) {
         if (!condition) throw new RuntimeException();
     }
--- a/jdk/test/java/lang/Class/getResource/ResourcesTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/getResource/ResourcesTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -68,7 +68,7 @@
             .compile(Paths.get(TEST_SRC, "Main.java"),
                      CLASSES_DIR,
                      "--module-path", MODS_DIR.toString(),
-                     "--add-modules", "m1,m2,m3");
+                     "--add-modules", "m1,m2");
         assertTrue(compiled);
 
     }
@@ -80,7 +80,7 @@
 
         int exitValue
             = executeTestJava("--module-path", MODS_DIR.toString(),
-                              "--add-modules", "m1,m2,m3",
+                              "--add-modules", "m1,m2",
                                "-cp", CLASSES_DIR.toString(),
                               "Main")
                 .outputTo(System.out)
--- a/jdk/test/java/lang/Class/getResource/src/m1/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m1/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,4 +23,5 @@
 
 module m1 {
     exports p1;
+    opens p1.resources;
 }
--- a/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -36,4 +36,12 @@
     public static InputStream getResourceAsStream(String name) {
         return Main.class.getResourceAsStream(name);
     }
+
+    public static URL getResource(Class<?> c, String name) {
+        return c.getResource(name);
+    }
+
+    public static InputStream getResourceAsStream(Class<?> c, String name) {
+        return c.getResourceAsStream(name);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/impl/Type.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p1.impl;
+
+public class Type { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/resources/Type.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p1.resources;
+
+public class Type { }
--- a/jdk/test/java/lang/Class/getResource/src/m2/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m2/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,4 +23,6 @@
 
 module m2 {
     exports p2;
+    exports p2.impl to m1;
+    opens p2.resources to m1;
 }
--- a/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -36,4 +36,12 @@
     public static InputStream getResourceAsStream(String name) {
         return Main.class.getResourceAsStream(name);
     }
+
+    public static URL getResource(Class<?> c, String name) {
+        return c.getResource(name);
+    }
+
+    public static InputStream getResourceAsStream(Class<?> c, String name) {
+        return c.getResourceAsStream(name);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/impl/Type.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p2.impl;
+
+public class Type { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/resources/Type.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p2.resources;
+
+public class Type { }
--- a/jdk/test/java/lang/Class/getResource/src/m3/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +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.
- *
- * 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 m3 {
-    exports p3;
-}
--- a/jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +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.
- *
- * 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 p3;
-
-import java.io.InputStream;
-import java.net.URL;
-
-public class Main {
-    private Main() { }
-
-    public static URL getResource(String name) {
-        return Main.class.getResource(name);
-    }
-
-    public static InputStream getResourceAsStream(String name) {
-        return Main.class.getResourceAsStream(name);
-    }
-}
--- a/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ClassLoader/LibraryPathProperty.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,6 +28,7 @@
  *          Quoted entries should get unquoted on Windows.
  *          Empty entries should be replaced with dot.
  * @library /lib/testlibrary
+ * @modules java.base/java.lang:open
  * @build jdk.testlibrary.Platform
  * @run main LibraryPathProperty
  */
--- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh	Thu Dec 01 21:39:49 2016 +0000
@@ -106,6 +106,7 @@
 # run test
 ${TESTJAVA}${FS}bin${FS}java \
         ${TESTVMOPTS} \
+        --add-opens java.base/java.lang=ALL-UNNAMED \
         -verbose:class -Xlog:class+load -cp . \
         -Dtest.classes=${TESTCLASSES} \
         Starter cross
--- a/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ClassLoader/deadlock/TestOneWayDelegate.sh	Thu Dec 01 21:39:49 2016 +0000
@@ -102,6 +102,7 @@
 # run test
 ${TESTJAVA}${FS}bin${FS}java \
         ${TESTVMOPTS} \
+        --add-opens java.base/java.lang=ALL-UNNAMED \
         -verbose:class -Xlog:class+load -cp . \
         -Dtest.classes=${TESTCLASSES} \
         Starter one-way
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -21,13 +21,18 @@
  * questions.
  */
 
+import java.io.InputStream;
 import java.lang.module.Configuration;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
 import java.io.IOException;
+import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
 
 /**
  * Basic test of ClassLoader getResource and getResourceAsStream when
@@ -40,36 +45,242 @@
 
     public static void main(String[] args) throws IOException {
 
-        // create m1/myresource containing "m1"
-        Path file = directoryFor("m1").resolve(NAME);
-        Files.write(file, "m1".getBytes("UTF-8"));
+        // create resources in m1
+        createResource("m1", Paths.get("."), "m1");
+        createResource("m1", Paths.get("p1"), "m1/p1");
+        createResource("m1", Paths.get("p1", "impl"), "m1/p1.impl");
+        createResource("m1", Paths.get("p1", "resources"), "m1/p1.resources");
 
-        // create m2/myresource containing "m2"
-        file = directoryFor("m2").resolve(NAME);
-        Files.write(file, "m2".getBytes("UTF-8"));
+        // create resources in m2
+        createResource("m2", Paths.get("."), "m2");
+        createResource("m2", Paths.get("p2"), "m2/p2");
+        createResource("m2", Paths.get("p2", "impl"), "m2/p2.impl");
+        createResource("m2", Paths.get("p2", "resources"), "m2/p2.resources");
 
-        // check that m3/myresource does not exist
-        assertTrue(Files.notExists(directoryFor("m3").resolve(NAME)));
 
         // invoke ClassLoader getResource from the unnamed module
-        assertNull(Main.class.getClassLoader().getResource("/" + NAME));
+        ClassLoader thisLoader = Main.class.getClassLoader();
+
+        URL url = thisLoader.getResource(NAME);
+        assertNotNull(url);
+
+        url = thisLoader.getResource("p1/" + NAME);
+        assertNull(url);
+
+        url = thisLoader.getResource("p1/impl/" + NAME);
+        assertNull(url);
+
+        url = thisLoader.getResource("p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        url = thisLoader.getResource("p2/" + NAME);
+        assertNull(url);
+
+        url = thisLoader.getResource("p2/impl/" + NAME);
+        assertNull(url);
+
+        url = thisLoader.getResource("p2/resources/" + NAME);
+        assertNull(url);
+
+
+        // invoke ClassLoader getResource from module m1
+        url = p1.Main.getResourceInClassLoader(NAME);
+        assertNotNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p1/" + NAME);
+        assertNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p1/impl/" + NAME);
+        assertNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        url = p1.Main.getResourceInClassLoader("p2/" + NAME);
+        assertNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p2/impl/" + NAME);
+        assertNull(url);
+
+        url = p1.Main.getResourceInClassLoader("p2/resources/" + NAME);
+        assertNull(url);
+
+
+        // invoke ClassLoader getResource from module m2
+        url = p2.Main.getResourceInClassLoader(NAME);
+        assertNotNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p1/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p1/impl/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p1/resources/" + NAME);
+        assertEquals(readAllAsString(url), "m1/p1.resources");
+
+        url = p2.Main.getResourceInClassLoader("p2/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p2/impl/" + NAME);
+        assertNull(url);
+
+        url = p2.Main.getResourceInClassLoader("p2/resources/" + NAME);
+        assertNull(url);
+
+
+        // invoke ClassLoader getResources from the unnamed module
+        Enumeration<URL> urls = thisLoader.getResources(NAME);
+        List<String> resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 2);
+        assertTrue(resources.contains("m1"));
+        assertTrue(resources.contains("m2"));
 
-        // invoke ClassLoader getResource from modules m1-m3
-        // Resources in a named module are private to that module.
-        // ClassLoader.getResource should not find resource in named modules.
-        assertNull(p1.Main.getResourceInClassLoader("/" + NAME));
-        assertNull(p2.Main.getResourceInClassLoader("/" + NAME));
-        assertNull(p3.Main.getResourceInClassLoader("/" + NAME));
+        urls = thisLoader.getResources("p1/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = thisLoader.getResources("p1/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = thisLoader.getResources("p1/resources/" + NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 1);
+        assertTrue(resources.contains("m1/p1.resources"));
+
+        urls = thisLoader.getResources("p2/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = thisLoader.getResources("p2/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = thisLoader.getResources("p2/resources/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+
+        // invoke ClassLoader getResources from m1
+        urls = p1.Main.getResourcesInClassLoader(NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 2);
+        assertTrue(resources.contains("m1"));
+        assertTrue(resources.contains("m2"));
+
+        urls = p1.Main.getResourcesInClassLoader("p1/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p1.Main.getResourcesInClassLoader("p1/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p1.Main.getResourcesInClassLoader("p1/resources/" + NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 1);
+        assertTrue(resources.contains("m1/p1.resources"));
+
+        urls = p1.Main.getResourcesInClassLoader("p2/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p1.Main.getResourcesInClassLoader("p2/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p1.Main.getResourcesInClassLoader("p2/resources/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+
+        // invoke ClassLoader getResources from m2
+        urls = p2.Main.getResourcesInClassLoader(NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 2);
+        assertTrue(resources.contains("m1"));
+        assertTrue(resources.contains("m2"));
+
+        urls = p2.Main.getResourcesInClassLoader("p1/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p2.Main.getResourcesInClassLoader("p1/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p2.Main.getResourcesInClassLoader("p1/resources/" + NAME);
+        resources = readAllAsStrings(urls);
+        assertTrue(resources.size() == 1);
+        assertTrue(resources.contains("m1/p1.resources"));
+
+        urls = p2.Main.getResourcesInClassLoader("p2/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p2.Main.getResourcesInClassLoader("p2/impl/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
+        urls = p2.Main.getResourcesInClassLoader("p2/resources/" + NAME);
+        assertTrue(readAllAsStrings(urls).isEmpty());
+
 
         // invoke ClassLoader getResourceAsStream from the unnamed module
-        assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME));
+        InputStream in = thisLoader.getResourceAsStream(NAME);
+        assertNotNull(in);
+
+        in = thisLoader.getResourceAsStream("p1/" + NAME);
+        assertNull(in);
+
+        in = thisLoader.getResourceAsStream("p1/impl/" + NAME);
+        assertNull(in);
+
+        in = thisLoader.getResourceAsStream("p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = thisLoader.getResourceAsStream("p2/" + NAME);
+        assertNull(in);
+
+        in = thisLoader.getResourceAsStream("p2/impl/" + NAME);
+        assertNull(in);
+
+        in = thisLoader.getResourceAsStream("p2/resources/" + NAME);
+        assertNull(in);
+
+
+        // invoke ClassLoader getResource from modules m1
+        in = p1.Main.getResourceAsStreamInClassLoader(NAME);
+        assertNotNull(in);
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p1/" + NAME);
+        assertNull(in);
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p1/impl/" + NAME);
+        assertNull(in);
 
-        // invoke ClassLoader getResourceAsStream from modules m1-m3
-        // Resources in a named module are private to that module.
-        // ClassLoader.getResourceAsStream should not find resource in named modules.
-        assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME));
-        assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME));
-        assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME));
+        in = p1.Main.getResourceAsStreamInClassLoader("p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p2/" + NAME);
+        assertNull(in);
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p2/impl/" + NAME);
+        assertNull(in);
+
+        in = p1.Main.getResourceAsStreamInClassLoader("p2/resources/" + NAME);
+        assertNull(in);
+
+
+        // invoke ClassLoader getResource from modules m2
+        in = p2.Main.getResourceAsStreamInClassLoader(NAME);
+        assertNotNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p1/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p1/impl/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p1/resources/" + NAME);
+        assertEquals(readAllAsString(in), "m1/p1.resources");
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p2/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p2/impl/" + NAME);
+        assertNull(in);
+
+        in = p2.Main.getResourceAsStreamInClassLoader("p2/resources/" + NAME);
+        assertNull(in);
+
 
         // SecurityManager case
         System.setSecurityManager(new SecurityManager());
@@ -77,17 +288,24 @@
         assertNull(Main.class.getClassLoader().getResource("/" + NAME));
         assertNull(p1.Main.getResourceInClassLoader("/" + NAME));
         assertNull(p2.Main.getResourceInClassLoader("/" + NAME));
-        assertNull(p3.Main.getResourceInClassLoader("/" + NAME));
 
         assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME));
         assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME));
         assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME));
-        assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME));
 
         System.out.println("Success!");
     }
 
     /**
+     * Create a resource in the sub-directory of the given exploded module
+     */
+    static void createResource(String mn, Path subdir, String msg) throws IOException {
+        Path dir = directoryFor(mn).resolve(subdir);
+        Path file = dir.resolve(NAME);
+        Files.write(file, msg.getBytes("UTF-8"));
+    }
+
+    /**
      * Returns the directory for the given module (by name).
      */
     static Path directoryFor(String mn) {
@@ -101,12 +319,60 @@
         return dir;
     }
 
+    static String readAllAsString(InputStream in) throws IOException {
+        if (in == null)
+            return null;
+        try (in) {
+            return new String(in.readAllBytes(), "UTF-8");
+        }
+    }
+
+    static String readAllAsString(URL url) throws IOException {
+        if (url == null)
+            return null;
+        InputStream in = url.openStream();
+        return readAllAsString(url.openStream());
+    }
+
+    static List<String> readAllAsStrings(Enumeration<URL> urls) throws IOException {
+        List<String> result = new ArrayList<>();
+        while (urls.hasMoreElements()) {
+            URL url = urls.nextElement();
+            result.add(readAllAsString(url));
+        }
+        return result;
+    }
+
     static void assertTrue(boolean condition) {
         if (!condition) throw new RuntimeException();
     }
 
+    static void assertFalse(boolean condition) {
+        if (condition) throw new RuntimeException();
+    }
+
     static void assertNull(Object o) {
         assertTrue(o == null);
     }
+
+    static void assertNotNull(Object o) {
+        assertTrue(o != null);
+    }
+
+    static void assertEquals(Object actual, Object expected) {
+        if (expected == null) {
+            assertNull(actual);
+        } else {
+            assertTrue(expected.equals(actual));
+        }
+    }
+
+    static void assertNotEquals(Object actual, Object expected) {
+        if (expected == null) {
+            assertNotNull(actual);
+        } else {
+            assertTrue(!expected.equals(actual));
+        }
+    }
 }
 
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -68,7 +68,7 @@
             .compile(Paths.get(TEST_SRC, "Main.java"),
                      CLASSES_DIR,
                      "--module-path", MODS_DIR.toString(),
-                     "--add-modules", "m1,m2,m3");
+                     "--add-modules", "m1,m2");
         assertTrue(compiled);
     }
 
@@ -78,7 +78,7 @@
     public void runTest() throws Exception {
         int exitValue
             = executeTestJava("--module-path", MODS_DIR.toString(),
-                              "--add-modules", "m1,m2,m3",
+                              "--add-modules", "m1,m2",
                                "-cp", CLASSES_DIR.toString(),
                               "Main")
                 .outputTo(System.out)
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,4 +23,5 @@
 
 module m1 {
     exports p1;
+    opens p1.resources;
 }
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,9 @@
 package p1;
 
 import java.io.InputStream;
+import java.io.IOException;
 import java.net.URL;
+import java.util.Enumeration;
 
 public class Main {
     private Main() { }
@@ -33,6 +35,10 @@
         return Main.class.getClassLoader().getResource(name);
     }
 
+    public static Enumeration<URL> getResourcesInClassLoader(String name) throws IOException {
+        return Main.class.getClassLoader().getResources(name);
+    }
+
     public static InputStream getResourceAsStreamInClassLoader(String name) {
         return Main.class.getClassLoader().getResourceAsStream(name);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/impl/Type.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p1.impl;
+
+public class Type { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/resources/Type.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p1.resources;
+
+public class Type { }
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,4 +23,6 @@
 
 module m2 {
     exports p2;
+    exports p2.impl to m1;
+    opens p2.resources to m1;
 }
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,9 @@
 package p2;
 
 import java.io.InputStream;
+import java.io.IOException;
 import java.net.URL;
+import java.util.Enumeration;
 
 public class Main {
     private Main() { }
@@ -33,6 +35,10 @@
         return Main.class.getClassLoader().getResource(name);
     }
 
+    public static Enumeration<URL> getResourcesInClassLoader(String name) throws IOException {
+        return Main.class.getClassLoader().getResources(name);
+    }
+
     public static InputStream getResourceAsStreamInClassLoader(String name) {
         return Main.class.getClassLoader().getResourceAsStream(name);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/impl/Type.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p2.impl;
+
+public class Type { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/resources/Type.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p2.resources;
+
+public class Type { }
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +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.
- *
- * 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 m3 {
-    exports p3;
-}
--- a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +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.
- *
- * 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 p3;
-
-import java.io.InputStream;
-import java.net.URL;
-
-public class Main {
-    private Main() { }
-
-    public static URL getResourceInClassLoader(String name) {
-        return Main.class.getClassLoader().getResource(name);
-    }
-
-    public static InputStream getResourceAsStreamInClassLoader(String name) {
-        return Main.class.getClassLoader().getResourceAsStream(name);
-    }
-}
--- a/jdk/test/java/lang/ProcessBuilder/Basic.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ProcessBuilder/Basic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
  *      4947220 7018606 7034570 4244896 5049299 8003488 8054494 8058464
  *      8067796
  * @summary Basic tests for Process and Environment Variable code
+ * @modules java.base/java.lang:open
  * @run main/othervm/timeout=300 Basic
  * @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=fork Basic
  * @author Martin Buchholz
--- a/jdk/test/java/lang/Runtime/Version/VersionProps.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/Runtime/Version/VersionProps.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8160564
  * @summary check the implementation of VersionProps.versionNumbers()
+ * @modules java.base/java.lang:open
  * @run main VersionProps
  * @author Volker Simonis
  */
--- a/jdk/test/java/lang/StackWalker/CountLocalSlots.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/StackWalker/CountLocalSlots.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8147039
  * @summary Confirm locals[] always has expected length, even for "dead" locals
+ * @modules java.base/java.lang:open
  * @compile LocalsAndOperands.java
  * @run testng/othervm -Xcomp CountLocalSlots
  */
--- a/jdk/test/java/lang/StackWalker/LocalsAndOperands.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/StackWalker/LocalsAndOperands.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8020968 8147039
  * @summary Tests for locals and operands
+ * @modules java.base/java.lang:open
  * @run testng LocalsAndOperands
  */
 
--- a/jdk/test/java/lang/StackWalker/LocalsCrash.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/StackWalker/LocalsCrash.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8147039
  * @summary Test for -Xcomp crash that happened before 8147039 fix
+ * @modules java.base/java.lang:open
  * @run testng/othervm -Xcomp LocalsCrash
  */
 
--- a/jdk/test/java/lang/String/CompactString/VMOptionsTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/String/CompactString/VMOptionsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -37,6 +37,7 @@
  *          if Compact String enable/disable VM Options is indeed working in String class,
  *          it's verified by testing if the VM option affect coder and
  *          COMPACT_STRINGS field in String class.
+ * @modules java.base/java.lang:open
  * @run testng/othervm -XX:+CompactStrings -DCompactStringEnabled=true VMOptionsTest
  * @run testng/othervm -XX:-CompactStrings -DCompactStringEnabled=false VMOptionsTest
  */
--- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerAPIsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -39,7 +39,7 @@
  * @bug     8144460 8144214
  * @summary Cover the logXX and LogEvent.valueOf APIs of BootstrapLogger
  *          and logXX APIs of SimpleConsoleLogger.
- * @modules java.base/jdk.internal.logger
+ * @modules java.base/jdk.internal.logger:+open
  *          java.base/sun.util.logging
  * @build BootstrapLoggerUtils LogStream
  * @run main/othervm BootstrapLoggerAPIsTest
--- a/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/BootstrapLogger/BootstrapLoggerTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -52,7 +52,7 @@
  * @summary JDK implementation specific unit test for JDK internal artifacts.
             Tests the behavior of bootstrap loggers (and SimpleConsoleLoggers
  *          too).
- * @modules java.base/jdk.internal.logger
+ * @modules java.base/jdk.internal.logger:+open
  *          java.logging
  * @build BootstrapLoggerUtils LogStream
  * @run main/othervm BootstrapLoggerTest NO_SECURITY
--- a/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/SystemLoggerInPlatformLoader/SystemLoggerInPlatformLoader.java	Thu Dec 01 21:39:49 2016 +0000
@@ -34,6 +34,7 @@
  * @test 8163162
  * @summary Checks that LazyLoggers are returned for System.Logger instances
  *          created by modules in the platform class loader.
+ * @modules java.base/java.lang:open
  * @build systempkg.log.SystemLoggerAccessor SystemLoggerInPlatformLoader
  * @run main/othervm SystemLoggerInPlatformLoader
  * @author danielfuchs
--- a/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/System/LoggerFinder/internal/backend/LoggerFinderBackendTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -38,7 +38,8 @@
  *           It calls both the {@link java.lang.System} factory methods and
  *           {@link jdk.internal.logger.LazyLoggers} to obtains those loggers,
  *           and configure them with all possible known levels.
- * @modules java.base/sun.util.logging
+ * @modules java.base/java.lang:open
+ *          java.base/sun.util.logging
  *          java.base/jdk.internal.logger
  *          java.logging/sun.util.logging.internal
  * @build LoggerFinderBackendTest SystemClassLoader
--- a/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/annotation/AnnotationsInheritanceOrderRedefinitionTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,7 +27,8 @@
  * @summary Test inheritance, order and class redefinition behaviour of RUNTIME
  *          class annotations
  * @author plevart
- * @modules java.base/sun.reflect.annotation
+ * @modules java.base/java.lang:open
+ *          java.base/sun.reflect.annotation
  */
 
 import sun.reflect.annotation.AnnotationParser;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/RedefineModuleAgent.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,50 @@
+/*
+ * 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.lang.instrument.Instrumentation;
+import java.lang.reflect.Module;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Agent used by RedefineModuleTest
+ */
+
+public class RedefineModuleAgent {
+
+    private static Instrumentation inst;
+
+    public static void premain(String args, Instrumentation inst) throws Exception {
+        RedefineModuleAgent.inst = inst;
+    }
+
+    static void redefineModule(Module module,
+                               Set<Module> extraReads,
+                               Map<String, Set<Module>> extraExports,
+                               Map<String, Set<Module>> extraOpens,
+                               Set<Class<?>> extraUses,
+                               Map<Class<?>, List<Class<?>>> extraProvides) {
+        inst.redefineModule(module, extraReads, extraExports, extraOpens, extraUses, extraProvides);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/RedefineModuleTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,369 @@
+/*
+ * 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
+ * @summary Basic test for redefineModule
+ * @modules java.instrument
+ * @build java.base/java.lang.TestProvider
+ *        java.base/jdk.internal.test.TestProviderImpl1
+ *        java.base/jdk.internal.test.TestProviderImpl2
+ * @run shell MakeJAR3.sh RedefineModuleAgent
+ * @run testng/othervm -javaagent:RedefineModuleAgent.jar RedefineModuleTest
+ */
+
+import java.lang.TestProvider;
+import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.net.URLStreamHandler;
+import java.net.spi.URLStreamHandlerProvider;
+import java.nio.file.FileSystems;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class RedefineModuleTest {
+
+    static void redefineModule(Module module,
+                               Set<Module> extraReads,
+                               Map<String, Set<Module>> extraExports,
+                               Map<String, Set<Module>> extraOpens,
+                               Set<Class<?>> extraUses,
+                               Map<Class<?>, List<Class<?>>> extraProvides) {
+        RedefineModuleAgent.redefineModule(module,
+                                           extraReads,
+                                           extraExports,
+                                           extraOpens,
+                                           extraUses,
+                                           extraProvides);
+    }
+
+
+    /**
+     * Use redefineModule to update java.base to read java.instrument
+     */
+    public void testAddReads() {
+        Module baseModule = Object.class.getModule();
+        Module instrumentModule = Instrumentation.class.getModule();
+
+        // pre-conditions
+        assertFalse(baseModule.canRead(instrumentModule));
+
+        // update java.base to read java.instrument
+        Set<Module> extraReads = Set.of(instrumentModule);
+        redefineModule(baseModule, extraReads, Map.of(), Map.of(), Set.of(), Map.of());
+        assertTrue(baseModule.canRead(instrumentModule));
+    }
+
+    /**
+     * Use redefineModule to update java.base to export jdk.internal.misc
+     */
+    public void testAddExports() {
+        Module baseModule = Object.class.getModule();
+        Module thisModule = this.getClass().getClassLoader().getUnnamedModule();
+        String pkg = "jdk.internal.misc";
+
+        // pre-conditions
+        assertFalse(baseModule.isExported(pkg));
+        assertFalse(baseModule.isExported(pkg, thisModule));
+
+        // update java.base to export jdk.internal.misc to an unnamed module
+        Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of(thisModule));
+        redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+        assertFalse(baseModule.isExported(pkg));
+        assertTrue(baseModule.isExported(pkg, thisModule));
+        assertFalse(baseModule.isOpen(pkg));
+        assertFalse(baseModule.isOpen(pkg, thisModule));
+    }
+
+    /**
+     * Use redefineModule to update java.base to open jdk.internal.loader
+     */
+    public void testAddOpens() {
+        Module baseModule = Object.class.getModule();
+        Module thisModule = this.getClass().getClassLoader().getUnnamedModule();
+        String pkg = "jdk.internal.loader";
+
+        // pre-conditions
+        assertFalse(baseModule.isOpen(pkg));
+        assertFalse(baseModule.isOpen(pkg, thisModule));
+
+        // update java.base to open dk.internal.loader to an unnamed module
+        Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of(thisModule));
+        redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of());
+        assertFalse(baseModule.isExported(pkg));
+        assertTrue(baseModule.isExported(pkg, thisModule));
+        assertFalse(baseModule.isOpen(pkg));
+        assertTrue(baseModule.isOpen(pkg, thisModule));
+    }
+
+    /**
+     * Use redefineModule to update java.base to use TestProvider and
+     * provide implementations of TestProvider.
+     */
+    public void testAddUsesAndProvides() throws Exception {
+        Module baseModule = Object.class.getModule();
+        Class<TestProvider> service = TestProvider.class;
+
+        // pre-conditions
+        assertFalse(baseModule.canUse(service));
+        assertTrue(collect(ServiceLoader.load(service)).isEmpty());
+        assertTrue(collect(ServiceLoader.load(Layer.boot(), service)).isEmpty());
+
+        // update java.base to use TestProvider
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(service), Map.of());
+        assertTrue(baseModule.canUse(service));
+        assertTrue(collect(ServiceLoader.load(service)).isEmpty());
+        assertTrue(collect(ServiceLoader.load(Layer.boot(), service)).isEmpty());
+
+        // update java.base to provide an implementation of TestProvider
+        Class<?> type1 = Class.forName("jdk.internal.test.TestProviderImpl1");
+        Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of(type1));
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+
+        // invoke ServiceLoader from java.base to find providers
+        Set<TestProvider> providers = collect(TestProvider.providers());
+        assertTrue(providers.size() == 1);
+        assertTrue(containsInstanceOf(providers, type1));
+
+        // use ServiceLoader to load implementations visible via TCCL
+        providers = collect(ServiceLoader.load(service));
+        assertTrue(collect(providers).size() == 1);
+        assertTrue(containsInstanceOf(collect(providers), type1));
+
+        // use ServiceLoader to load implementations in the boot layer
+        providers = collect(ServiceLoader.load(Layer.boot(), service));
+        assertTrue(collect(providers).size() == 1);
+        assertTrue(containsInstanceOf(collect(providers), type1));
+
+        // update java.base to provide a second implementation of TestProvider
+        Class<?> type2 = Class.forName("jdk.internal.test.TestProviderImpl2");
+        extraProvides = Map.of(service, List.of(type2));
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+
+        // invoke ServiceLoader from java.base to find providers
+        providers = collect(TestProvider.providers());
+        assertTrue(providers.size() == 2);
+        assertTrue(containsInstanceOf(providers, type1));
+        assertTrue(containsInstanceOf(providers, type2));
+
+        // use ServiceLoader to load implementations visible via TCCL
+        providers = collect(ServiceLoader.load(service));
+        assertTrue(collect(providers).size() == 2);
+        assertTrue(containsInstanceOf(providers, type1));
+        assertTrue(containsInstanceOf(providers, type2));
+
+        // use ServiceLoader to load implementations in the boot layer
+        providers = collect(ServiceLoader.load(Layer.boot(), service));
+        assertTrue(collect(providers).size() == 2);
+        assertTrue(containsInstanceOf(providers, type1));
+        assertTrue(containsInstanceOf(providers, type2));
+    }
+
+    private <S> Set<S> collect(Iterable<S> sl) {
+        Set<S> providers = new HashSet<>();
+        sl.forEach(providers::add);
+        return providers;
+    }
+
+    private boolean containsInstanceOf(Collection<?> c, Class<?> type) {
+        for (Object o : c) {
+            if (type.isInstance(o)) return true;
+        }
+        return false;
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testExportPackageToEmptySet() {
+        // attempt to update java.base to export jdk.internal.misc to nobody
+        Module baseModule = Object.class.getModule();
+        Map<String, Set<Module>> extraExports = Map.of("jdk.internal.misc", Set.of());
+        redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testOpenPackageToEmptySet() {
+        // attempt to update java.base to open jdk.internal.misc to nobody
+        Module baseModule = Object.class.getModule();
+        Map<String, Set<Module>> extraOpens = Map.of("jdk.internal.misc", Set.of());
+        redefineModule(baseModule, Set.of(), Map.of(), extraOpens, Set.of(), Map.of());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testProvideServiceWithEmptyList() throws Exception {
+        // update java.base to provide an empty list of TestProvider
+        Module baseModule = Object.class.getModule();
+        Class<?> service = TestProvider.class;
+        Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of());
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+    }
+
+    /**
+     * Test redefineClass by attempting to update java.base to export a package
+     * that it does not contain.
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testExportPackageNotInModule() {
+        Module baseModule = Object.class.getModule();
+        String pkg = "jdk.doesnotexist";
+
+        // attempt to update java.base to export jdk.doesnotexist
+        Map<String, Set<Module>> extraExports = Map.of(pkg, Set.of());
+        redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+    }
+
+    /**
+     * Test redefineClass by attempting to update java.base to provide a service
+     * where the service provider class is not in the module.
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testProvideServiceNotInModule() {
+        Module baseModule = Object.class.getModule();
+        class MyProvider extends URLStreamHandlerProvider {
+            @Override
+            public URLStreamHandler createURLStreamHandler(String protocol) {
+                return null;
+            }
+        }
+
+        // attempt to update java.base to provide MyProvider
+        Map<Class<?>, List<Class<?>>> extraProvides
+            = Map.of(URLStreamHandlerProvider.class, List.of(MyProvider.class));
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+    }
+
+    /**
+     * Test redefineClass by attempting to update java.base to provide a
+     * service where the service provider class is not a sub-type.
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testProvideServiceNotSubtype() {
+        Module baseModule = Object.class.getModule();
+
+        Class<?> service = TestProvider.class;
+        Class<?> impl = FileSystems.getDefault().provider().getClass();
+
+        // attempt to update java.base to provide an implementation of TestProvider
+        Map<Class<?>, List<Class<?>>> extraProvides = Map.of(service, List.of(impl));
+        redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+    }
+
+    /**
+     * Test redefineClass with null
+     */
+    public void testNulls() {
+        Module baseModule = Object.class.getModule();
+
+        try {
+            redefineModule(null, Set.of(), Map.of(), Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, null, Map.of(), Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, Set.of(), null, Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, Set.of(), Map.of(), null, Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), null, Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), null);
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Set<Module> containsNull = new HashSet<>();
+            containsNull.add(null);
+            redefineModule(baseModule, containsNull, Map.of(), Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Map<String, Set<Module>> extraExports = new HashMap<>();
+            extraExports.put(null, Set.of());
+            redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Map<String, Set<Module>> extraExports = new HashMap<>();
+            extraExports.put(null, Set.of());
+            redefineModule(baseModule, Set.of(), Map.of(), extraExports, Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Set<Module> containsNull = new HashSet<>();
+            containsNull.add(null);
+            Map<String, Set<Module>> extraExports = Map.of("java.lang", containsNull);
+            redefineModule(baseModule, Set.of(), extraExports, Map.of(), Set.of(), Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Set<Class<?>> containsNull = new HashSet<>();
+            containsNull.add(null);
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), containsNull, Map.of());
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            Map<Class<?>, List<Class<?>>> extraProvides = new HashMap<>();
+            extraProvides.put(null, List.of());
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+
+        try {
+            List<Class<?>> containsNull = new ArrayList<>();
+            containsNull.add(null);
+            Map<Class<?>, List<Class<?>>> extraProvides = Map.of(TestProvider.class, containsNull);
+            redefineModule(baseModule, Set.of(), Map.of(), Map.of(), Set.of(), extraProvides);
+            assertTrue(false);
+        } catch (NullPointerException e) { }
+    }
+
+}
--- a/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/instrument/TestAgentWithLimitMods.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,7 +28,7 @@
  * the module graph
  * @modules java.instrument
  * @run shell MakeJAR3.sh SimpleAgent
- * @run main/othervm -javaagent:SimpleAgent.jar -limitmods java.base TestAgentWithLimitMods
+ * @run main/othervm -javaagent:SimpleAgent.jar --limit-modules java.base TestAgentWithLimitMods
  *
  */
 public class TestAgentWithLimitMods {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/java.base/java/lang/TestProvider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * 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 java.lang;
+
+import java.util.ServiceLoader;
+
+public interface TestProvider {
+    public static Iterable<TestProvider> providers() {
+        return ServiceLoader.load(TestProvider.class);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl1.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * 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.internal.test;
+
+import java.lang.TestProvider;
+
+public class TestProviderImpl1 implements TestProvider {
+    public TestProviderImpl1() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/java.base/jdk/internal/test/TestProviderImpl2.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * 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.internal.test;
+
+import java.lang.TestProvider;
+
+public class TestProviderImpl2 implements TestProvider {
+    public TestProviderImpl2() { }
+}
+
--- a/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,7 +28,9 @@
  * @summary Test verifies that lambda forms are cached when run with multiple threads
  * @author kshefov
  * @library /lib/testlibrary/jsr292 /lib/testlibrary
- * @modules jdk.management
+ * @modules java.base/java.lang.invoke:open
+ *          java.base/java.lang.ref:open
+ *          jdk.management
  * @build TestMethods
  * @build LambdaFormTestCase
  * @build LFCachingTestCase
--- a/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,6 +28,8 @@
  * @summary Test verifies that lambda forms are cached when run with single thread
  * @author kshefov
  * @library /lib/testlibrary/jsr292 /lib/testlibrary
+ * @modules java.base/java.lang.ref:open
+ *          java.base/java.lang.invoke:open
  * @build TestMethods
  * @build LambdaFormTestCase
  * @build LFCachingTestCase
--- a/jdk/test/java/lang/invoke/LambdaFormTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/invoke/LambdaFormTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,7 @@
 
 /* @test
  * @summary unit tests for java.lang.invoke.LambdaForm
+ * @modules java.base/java.lang.invoke:open
  * @run junit/othervm test.java.lang.invoke.LambdaFormTest
  */
 package test.java.lang.invoke;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * 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
+ * @build test/* m1/* m2/* m3/*
+ * @run testng/othervm test/p.PrivateLookupInTests
+ * @summary Unit tests for MethodHandles.privateLookupIn
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+open module m1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m1/p1/Type.java	Thu Dec 01 21:39:49 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.
+ */
+package p1;
+
+class Type {
+    private static final Object obj = new Object();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * 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 m2 {
+    opens p2 to test;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m2/p2/Type.java	Thu Dec 01 21:39:49 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.
+ */
+package p2;
+
+class Type {
+    private static final Object obj = new Object();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * 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 m3 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/m3/p3/Type.java	Thu Dec 01 21:39:49 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.
+ */
+package p3;
+
+class Type {
+    private static final Object obj = new Object();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/module-info.java	Thu Dec 01 21:39:49 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 test {
+   requires testng;
+   exports p to testng;   // TestNG invokes the public methods
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,189 @@
+/*
+ * 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 p;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Module;
+
+import static java.lang.invoke.MethodHandles.Lookup.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * Unit tests for MethodHandles.privateLookupIn
+ */
+
+@Test
+public class PrivateLookupInTests {
+
+    /**
+     * A public and non-public types in the test module but in a different
+     * package to the test class.
+     *
+     * package p.internal;
+     * public class PublicType {
+     * }
+     *
+     * package p.internal;
+     * class NonPublicType {
+     *     private static final Object obj = ...
+     * }
+     */
+    private Class<?> publicType;
+    private Class<?> nonPublicType;
+
+    // initialize and sanity check publicType/nonPublicType
+    @BeforeTest
+    public void init() throws Exception {
+        publicType = Class.forName("p.internal.PublicType");
+        assertTrue(this.getClass().getModule() == publicType.getModule());
+        assertNotEquals(this.getClass().getPackageName(), publicType.getPackageName());
+        assertTrue(Modifier.isPublic(publicType.getModifiers()));
+
+        nonPublicType = Class.forName("p.internal.NonPublicType");
+        assertTrue(this.getClass().getModule() == nonPublicType.getModule());
+        assertNotEquals(this.getClass().getPackageName(), nonPublicType.getPackageName());
+        assertFalse(Modifier.isPublic(nonPublicType.getModifiers()));
+    }
+
+    // Invoke MethodHandles.privateLookupIn with a full-power caller
+    public void testAllAccessCallerSameModule() throws Throwable {
+        Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, MethodHandles.lookup());
+        assertTrue(lookup.lookupClass() == nonPublicType);
+        assertTrue(lookup.hasPrivateAccess());
+
+        // get obj field
+        MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class);
+        Object obj = mh.invokeExact();
+    }
+
+    // Invoke MethodHandles.privateLookupIn with a reduced-power caller
+    public void testReducedAccessCallerSameModule() throws Throwable {
+        // drop access
+        Lookup caller = MethodHandles.lookup().in(publicType);
+        assertTrue((caller.lookupModes() & PRIVATE) == 0);
+        assertTrue((caller.lookupModes() & PACKAGE) == 0);
+        assertTrue((caller.lookupModes() & MODULE) != 0);
+
+        Lookup lookup = MethodHandles.privateLookupIn(nonPublicType, caller);
+        assertTrue(lookup.lookupClass() == nonPublicType);
+        assertTrue(lookup.hasPrivateAccess());
+
+        // use it
+        MethodHandle mh = lookup.findStaticGetter(nonPublicType, "obj", Object.class);
+        Object obj = mh.invokeExact();
+    }
+
+    // Invoke MethodHandles.privateLookupIn with the public lookup as caller
+    @Test(expectedExceptions = {IllegalAccessException.class})
+    public void testPublicLookupSameModule() throws Exception {
+        Lookup caller = MethodHandles.publicLookup();
+        Lookup lookup = MethodHandles.privateLookupIn(publicType, caller);
+    }
+
+    // test reads m1, open module m1 containing p1
+    public void testTargetClassInOpenModule() throws Throwable {
+        // m1/p1.Type
+        Class<?> clazz = Class.forName("p1.Type");
+        assertEquals(clazz.getModule().getName(), "m1");
+
+        // ensure that this module reads m1
+        Module thisModule = getClass().getModule();
+        Module m1 = clazz.getModule();
+        thisModule.addReads(clazz.getModule());
+        assertTrue(m1.isOpen("p1", thisModule));
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        assertTrue(lookup.lookupClass() == clazz);
+        assertTrue(lookup.hasPrivateAccess());
+
+        // get obj field
+        MethodHandle mh = lookup.findStaticGetter(clazz, "obj", Object.class);
+        Object obj = mh.invokeExact();
+    }
+
+    // test does not read m2, m2 opens p2 to test
+    @Test(expectedExceptions = {IllegalAccessException.class})
+    public void testCallerDoesNotRead() throws Throwable {
+        // m2/p2.Type
+        Class<?> clazz = Class.forName("p2.Type");
+        assertEquals(clazz.getModule().getName(), "m2");
+
+        Module thisModule = getClass().getModule();
+        Module m2 = clazz.getModule();
+        assertFalse(thisModule.canRead(m2));
+        assertTrue(m2.isOpen("p2", thisModule));
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+    }
+
+    // test reads m3, m3 does not open p3 to test
+    @Test(expectedExceptions = {IllegalAccessException.class})
+    public void testNotOpenToCaller() throws Throwable {
+        // m3/p2.Type
+        Class<?> clazz = Class.forName("p3.Type");
+        assertEquals(clazz.getModule().getName(), "m3");
+
+        Module thisModule = getClass().getModule();
+        Module m3 = clazz.getModule();
+        thisModule.addReads(clazz.getModule());
+        assertFalse(m3.isOpen("p3", thisModule));
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with a primitive class
+    @Test(expectedExceptions = {IllegalArgumentException.class})
+    public void testPrimitiveClassAsTargetClass() throws Exception {
+        MethodHandles.privateLookupIn(int.class, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with an array class
+    @Test(expectedExceptions = {IllegalArgumentException.class})
+    public void testArrayClassAsTargetClass() throws Exception {
+        MethodHandles.privateLookupIn(PrivateLookupInTests[].class, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with a primitive array class
+    @Test(expectedExceptions = {IllegalArgumentException.class})
+    public void testPrimitiveArrayClassAsTargetClass() throws Exception {
+        MethodHandles.privateLookupIn(int[].class, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with null
+    @Test(expectedExceptions = {NullPointerException.class})
+    public void testNullTargetClass() throws Exception {
+        MethodHandles.privateLookupIn(null, MethodHandles.lookup());
+    }
+
+    // Invoke MethodHandles.privateLookupIn with null
+    @Test(expectedExceptions = {NullPointerException.class})
+    public void testNullCaller() throws Exception {
+        MethodHandles.privateLookupIn(getClass(), null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/NonPublicType.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * 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 p.internal;
+
+class NonPublicType {
+    private static final Object obj = new Object();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/internal/PublicType.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p.internal;
+
+public class PublicType {
+}
+
--- a/jdk/test/java/lang/invoke/PrivateInvokeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/invoke/PrivateInvokeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,7 @@
 
 /* @test
  * @summary white-box testing of method handle sub-primitives
+ * @modules java.base/java.lang.invoke:open
  * @run junit test.java.lang.invoke.PrivateInvokeTest
  */
 
--- a/jdk/test/java/lang/invoke/VMAnonymousClass.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/invoke/VMAnonymousClass.java	Thu Dec 01 21:39:49 2016 +0000
@@ -32,7 +32,6 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
-import java.lang.reflect.Field;
 import org.junit.Test;
 import jdk.internal.misc.Unsafe;
 import jdk.internal.org.objectweb.asm.*;
@@ -64,7 +63,7 @@
        throw new RuntimeException("Expected SecurityException");
      }
 
-    private static Unsafe unsafe = getUnsafe();
+    private static Unsafe unsafe = Unsafe.getUnsafe();
 
     private static void test(String pkg) throws Throwable {
         byte[] bytes = dumpClass(pkg);
@@ -130,14 +129,4 @@
         cw.visitEnd();
         return cw.toByteArray();
     }
-
-    private static synchronized Unsafe getUnsafe() {
-        try {
-            Field f = Unsafe.class.getDeclaredField("theUnsafe");
-            f.setAccessible(true);
-            return (Unsafe) f.get(null);
-        } catch (NoSuchFieldException | IllegalAccessException e) {
-            throw new RuntimeException("Unable to get Unsafe instance.", e);
-        }
-    }
 }
--- a/jdk/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -127,8 +127,13 @@
                                "-Djdk.internal.lambda.dumpProxyClasses=dump",
                                "-Djava.security.manager",
                                "com.example.TestLambda");
-        // dump/com/example + 2 class files
-        assertEquals(Files.walk(Paths.get("dump")).count(), 5, "Two lambda captured");
+        // 2 our own class files. We don't care about the others
+        assertEquals(Files.find(
+                        Paths.get("dump"),
+                        99,
+                        (p, a) -> p.startsWith(Paths.get("dump/com/example"))
+                                && a.isRegularFile()).count(),
+                2, "Two lambda captured");
         tr.assertZero("Should still return 0");
     }
 
--- a/jdk/test/java/lang/module/AutomaticModulesTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/module/AutomaticModulesTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -67,6 +67,15 @@
             // JAR file name                module-name[/version]
 
             { "foo.jar",                    "foo" },
+            { "foo4j.jar",                  "foo4j", },
+
+            { "foo1.jar",                   "foo" },
+            { "foo1.2.jar",                 "foo" },
+            { "foo1.2.3.jar",               "foo" },
+
+            { "foo10.jar",                  "foo" },
+            { "foo10.20.jar",               "foo" },
+            { "foo10.20.30.jar",            "foo" },
 
             { "foo-1.jar",                  "foo/1" },
             { "foo-1.2.jar",                "foo/1.2" },
@@ -258,8 +267,8 @@
 
         ModuleDescriptor descriptor = mref.get().descriptor();
         assertTrue(descriptor.provides().size() == 1);
-        assertTrue(descriptor.provides().containsKey(service));
-        ModuleDescriptor.Provides provides = descriptor.provides().get(service);
+        ModuleDescriptor.Provides provides = descriptor.provides().iterator().next();
+        assertEquals(provides.service(), service);
         assertTrue(provides.providers().size() == 1);
         assertTrue(provides.providers().contains((provider)));
     }
@@ -343,17 +352,17 @@
         attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
 
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m1.jar"), man);
+        createDummyJarFile(dir.resolve("m.jar"), man);
 
         ModuleFinder finder = ModuleFinder.of(dir);
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1");
+        Configuration cf = resolve(parent, finder, "m");
 
-        ModuleDescriptor m1 = findDescriptor(cf, "m1");
+        ModuleDescriptor descriptor = findDescriptor(cf, "m");
 
-        assertTrue(m1.mainClass().isPresent());
-        assertEquals(m1.mainClass().get(), mainClass);
+        assertTrue(descriptor.mainClass().isPresent());
+        assertEquals(descriptor.mainClass().get(), mainClass);
     }
 
 
@@ -380,7 +389,7 @@
         attrs.put(Attributes.Name.MAIN_CLASS, mainClass);
 
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m1.jar"), man);
+        createDummyJarFile(dir.resolve("m.jar"), man);
 
         // should throw FindException
         ModuleFinder.of(dir).findAll();
@@ -389,213 +398,213 @@
 
     /**
      * Basic test of a configuration created with automatic modules.
-     *   m1 requires m2*
-     *   m1 requires m3*
-     *   m2*
-     *   m3*
+     *   a requires b*
+     *   a requires c*
+     *   b*
+     *   c*
      */
     public void testConfiguration1() throws Exception {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .requires("m2")
-                .requires("m3")
+            = ModuleDescriptor.module("a")
+                .requires("b")
+                .requires("c")
                 .requires("java.base")
                 .build();
 
-        // m2 and m3 are automatic modules
+        // b and c are automatic modules
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m2.jar"), "p/T.class");
-        createDummyJarFile(dir.resolve("m3.jar"), "q/T.class");
+        createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
+        createDummyJarFile(dir.resolve("c.jar"), "q/T.class");
 
-        // module finder locates m1 and the modules in the directory
+        // module finder locates a and the modules in the directory
         ModuleFinder finder
             = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1),
                 ModuleFinder.of(dir));
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1");
+        Configuration cf = resolve(parent, finder, "a");
 
         assertTrue(cf.modules().size() == 3);
-        assertTrue(cf.findModule("m1").isPresent());
-        assertTrue(cf.findModule("m2").isPresent());
-        assertTrue(cf.findModule("m3").isPresent());
+        assertTrue(cf.findModule("a").isPresent());
+        assertTrue(cf.findModule("b").isPresent());
+        assertTrue(cf.findModule("c").isPresent());
 
         ResolvedModule base = cf.findModule("java.base").get();
         assertTrue(base.configuration() == Layer.boot().configuration());
-        ResolvedModule m1 = cf.findModule("m1").get();
-        ResolvedModule m2 = cf.findModule("m2").get();
-        ResolvedModule m3 = cf.findModule("m3").get();
+        ResolvedModule a = cf.findModule("a").get();
+        ResolvedModule b = cf.findModule("b").get();
+        ResolvedModule c = cf.findModule("c").get();
 
-        // m2 && m3 only require java.base
-        assertTrue(m2.reference().descriptor().requires().size() == 1);
-        assertTrue(m3.reference().descriptor().requires().size() == 1);
+        // b && c only require java.base
+        assertTrue(b.reference().descriptor().requires().size() == 1);
+        assertTrue(c.reference().descriptor().requires().size() == 1);
 
         // readability
 
-        assertTrue(m1.reads().size() == 3);
-        assertTrue(m1.reads().contains(base));
-        assertTrue(m1.reads().contains(m2));
-        assertTrue(m1.reads().contains(m3));
+        assertTrue(a.reads().size() == 3);
+        assertTrue(a.reads().contains(base));
+        assertTrue(a.reads().contains(b));
+        assertTrue(a.reads().contains(c));
 
-        assertTrue(m2.reads().contains(m1));
-        assertTrue(m2.reads().contains(m3));
-        testReadAllBootModules(cf, "m2");  // m2 reads all modules in boot layer
+        assertTrue(b.reads().contains(a));
+        assertTrue(b.reads().contains(c));
+        testReadAllBootModules(cf, "b");  // b reads all modules in boot layer
 
-        assertTrue(m3.reads().contains(m1));
-        assertTrue(m3.reads().contains(m2));
-        testReadAllBootModules(cf, "m3");  // m3 reads all modules in boot layer
+        assertTrue(c.reads().contains(a));
+        assertTrue(c.reads().contains(b));
+        testReadAllBootModules(cf, "c");  // c reads all modules in boot layer
 
     }
 
     /**
      * Basic test of a configuration created with automatic modules
-     *   m1 requires m2
-     *   m2 requires m3*
-     *   m3*
-     *   m4*
+     *   a requires b
+     *   b requires c*
+     *   c*
+     *   d*
      */
     public void testInConfiguration2() throws IOException {
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
-                .requires("m2")
+            = ModuleDescriptor.module("a")
+                .requires("b")
                 .requires("java.base")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
-                .requires("m3")
+            = ModuleDescriptor.module("b")
+                .requires("c")
                 .requires("java.base")
                 .build();
 
-        // m3 and m4 are automatic modules
+        // c and d are automatic modules
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m3.jar"), "p/T.class");
-        createDummyJarFile(dir.resolve("m4.jar"), "q/T.class");
+        createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
+        createDummyJarFile(dir.resolve("d.jar"), "q/T.class");
 
-        // module finder locates m1 and the modules in the directory
+        // module finder locates a and the modules in the directory
         ModuleFinder finder
             = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2),
                                    ModuleFinder.of(dir));
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1", "m4");
+        Configuration cf = resolve(parent, finder, "a", "d");
 
         assertTrue(cf.modules().size() == 4);
-        assertTrue(cf.findModule("m1").isPresent());
-        assertTrue(cf.findModule("m2").isPresent());
-        assertTrue(cf.findModule("m3").isPresent());
-        assertTrue(cf.findModule("m4").isPresent());
+        assertTrue(cf.findModule("a").isPresent());
+        assertTrue(cf.findModule("b").isPresent());
+        assertTrue(cf.findModule("c").isPresent());
+        assertTrue(cf.findModule("d").isPresent());
 
-        // m3 && m4 should only require java.base
-        assertTrue(findDescriptor(cf, "m3").requires().size() == 1);
-        assertTrue(findDescriptor(cf, "m4").requires().size() == 1);
+        // c && d should only require java.base
+        assertTrue(findDescriptor(cf, "c").requires().size() == 1);
+        assertTrue(findDescriptor(cf, "d").requires().size() == 1);
 
         // readability
 
         ResolvedModule base = cf.findModule("java.base").get();
         assertTrue(base.configuration() == Layer.boot().configuration());
-        ResolvedModule m1 = cf.findModule("m1").get();
-        ResolvedModule m2 = cf.findModule("m2").get();
-        ResolvedModule m3 = cf.findModule("m3").get();
-        ResolvedModule m4 = cf.findModule("m4").get();
+        ResolvedModule a = cf.findModule("a").get();
+        ResolvedModule b = cf.findModule("b").get();
+        ResolvedModule c = cf.findModule("c").get();
+        ResolvedModule d = cf.findModule("d").get();
 
-        assertTrue(m1.reads().size() == 2);
-        assertTrue(m1.reads().contains(m2));
-        assertTrue(m1.reads().contains(base));
+        assertTrue(a.reads().size() == 2);
+        assertTrue(a.reads().contains(b));
+        assertTrue(a.reads().contains(base));
 
-        assertTrue(m2.reads().size() == 3);
-        assertTrue(m2.reads().contains(m3));
-        assertTrue(m2.reads().contains(m4));
-        assertTrue(m2.reads().contains(base));
+        assertTrue(b.reads().size() == 3);
+        assertTrue(b.reads().contains(c));
+        assertTrue(b.reads().contains(d));
+        assertTrue(b.reads().contains(base));
 
-        assertTrue(m3.reads().contains(m1));
-        assertTrue(m3.reads().contains(m2));
-        assertTrue(m3.reads().contains(m4));
-        testReadAllBootModules(cf, "m3");   // m3 reads all modules in boot layer
+        assertTrue(c.reads().contains(a));
+        assertTrue(c.reads().contains(b));
+        assertTrue(c.reads().contains(d));
+        testReadAllBootModules(cf, "c");   // c reads all modules in boot layer
 
-        assertTrue(m4.reads().contains(m1));
-        assertTrue(m4.reads().contains(m2));
-        assertTrue(m4.reads().contains(m3));
-        testReadAllBootModules(cf, "m4");    // m4 reads all modules in boot layer
+        assertTrue(d.reads().contains(a));
+        assertTrue(d.reads().contains(b));
+        assertTrue(d.reads().contains(c));
+        testReadAllBootModules(cf, "d");    // d reads all modules in boot layer
     }
 
 
     /**
      * Basic test of a configuration created with automatic modules
-     *   m1 requires m2
-     *   m2 requires public m3*
-     *   m3*
-     *   m4*
+     *   a requires b
+     *   b requires transitive c*
+     *   c*
+     *   d*
      */
     public void testInConfiguration3() throws IOException {
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
-                .requires("m2")
+            = ModuleDescriptor.module("a")
+                .requires("b")
                 .requires("java.base")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m3")
+            = ModuleDescriptor.module("b")
+                .requires(Set.of(Modifier.TRANSITIVE), "c")
                 .requires("java.base")
                 .build();
 
-        // m3 and m4 are automatic modules
+        // c and d are automatic modules
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m3.jar"), "p/T.class");
-        createDummyJarFile(dir.resolve("m4.jar"), "q/T.class");
+        createDummyJarFile(dir.resolve("c.jar"), "p/T.class");
+        createDummyJarFile(dir.resolve("d.jar"), "q/T.class");
 
-        // module finder locates m1 and the modules in the directory
+        // module finder locates a and the modules in the directory
         ModuleFinder finder
             = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2),
                 ModuleFinder.of(dir));
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1", "m4");
+        Configuration cf = resolve(parent, finder, "a", "d");
 
         assertTrue(cf.modules().size() == 4);
-        assertTrue(cf.findModule("m1").isPresent());
-        assertTrue(cf.findModule("m2").isPresent());
-        assertTrue(cf.findModule("m3").isPresent());
-        assertTrue(cf.findModule("m4").isPresent());
+        assertTrue(cf.findModule("a").isPresent());
+        assertTrue(cf.findModule("b").isPresent());
+        assertTrue(cf.findModule("c").isPresent());
+        assertTrue(cf.findModule("d").isPresent());
 
         ResolvedModule base = cf.findModule("java.base").get();
         assertTrue(base.configuration() == Layer.boot().configuration());
-        ResolvedModule m1 = cf.findModule("m1").get();
-        ResolvedModule m2 = cf.findModule("m2").get();
-        ResolvedModule m3 = cf.findModule("m3").get();
-        ResolvedModule m4 = cf.findModule("m4").get();
+        ResolvedModule a = cf.findModule("a").get();
+        ResolvedModule b = cf.findModule("b").get();
+        ResolvedModule c = cf.findModule("c").get();
+        ResolvedModule d = cf.findModule("d").get();
 
-        // m3 && m4 should only require java.base
-        assertTrue(findDescriptor(cf, "m3").requires().size() == 1);
-        assertTrue(findDescriptor(cf, "m4").requires().size() == 1);
+        // c && d should only require java.base
+        assertTrue(findDescriptor(cf, "c").requires().size() == 1);
+        assertTrue(findDescriptor(cf, "d").requires().size() == 1);
 
         // readability
 
-        assertTrue(m1.reads().size() == 4);
-        assertTrue(m1.reads().contains(m2));
-        assertTrue(m1.reads().contains(m3));
-        assertTrue(m1.reads().contains(m4));
-        assertTrue(m1.reads().contains(base));
+        assertTrue(a.reads().size() == 4);
+        assertTrue(a.reads().contains(b));
+        assertTrue(a.reads().contains(c));
+        assertTrue(a.reads().contains(d));
+        assertTrue(a.reads().contains(base));
 
-        assertTrue(m2.reads().size() == 3);
-        assertTrue(m2.reads().contains(m3));
-        assertTrue(m2.reads().contains(m4));
-        assertTrue(m2.reads().contains(base));
+        assertTrue(b.reads().size() == 3);
+        assertTrue(b.reads().contains(c));
+        assertTrue(b.reads().contains(d));
+        assertTrue(b.reads().contains(base));
 
-        assertTrue(reads(cf, "m2", "m3"));
-        assertTrue(reads(cf, "m2", "m4"));
-        assertTrue(reads(cf, "m2", "java.base"));
+        assertTrue(reads(cf, "b", "c"));
+        assertTrue(reads(cf, "b", "d"));
+        assertTrue(reads(cf, "b", "java.base"));
 
-        assertTrue(m3.reads().contains(m1));
-        assertTrue(m3.reads().contains(m2));
-        assertTrue(m3.reads().contains(m4));
-        testReadAllBootModules(cf, "m3");   // m3 reads all modules in boot layer
+        assertTrue(c.reads().contains(a));
+        assertTrue(c.reads().contains(b));
+        assertTrue(c.reads().contains(d));
+        testReadAllBootModules(cf, "c");   // c reads all modules in boot layer
 
-        assertTrue(m4.reads().contains(m1));
-        assertTrue(m4.reads().contains(m2));
-        assertTrue(m4.reads().contains(m3));
-        testReadAllBootModules(cf, "m4");    // m4 reads all modules in boot layer
+        assertTrue(d.reads().contains(a));
+        assertTrue(d.reads().contains(b));
+        assertTrue(d.reads().contains(c));
+        testReadAllBootModules(cf, "d");    // d reads all modules in boot layer
     }
 
 
@@ -604,23 +613,23 @@
      */
     public void testInLayer() throws IOException {
         ModuleDescriptor descriptor
-            =  new ModuleDescriptor.Builder("m1")
-                .requires("m2")
-                .requires("m3")
+            = ModuleDescriptor.module("a")
+                .requires("b")
+                .requires("c")
                 .build();
 
-        // m2 and m3 are simple JAR files
+        // b and c are simple JAR files
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        createDummyJarFile(dir.resolve("m2.jar"), "p/T.class");
-        createDummyJarFile(dir.resolve("m3.jar"), "q/T2.class");
+        createDummyJarFile(dir.resolve("b.jar"), "p/T.class");
+        createDummyJarFile(dir.resolve("c.jar"), "q/T2.class");
 
-        // module finder locates m1 and the modules in the directory
+        // module finder locates a and the modules in the directory
         ModuleFinder finder
             = ModuleFinder.compose(ModuleUtils.finderOf(descriptor),
                 ModuleFinder.of(dir));
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = resolve(parent, finder, "m1");
+        Configuration cf = resolve(parent, finder, "a");
         assertTrue(cf.modules().size() == 3);
 
         // each module gets its own loader
@@ -629,15 +638,15 @@
         // an unnamed module
         Module unnamed = (new ClassLoader() { }).getUnnamedModule();
 
-        Module m2 = layer.findModule("m2").get();
-        assertTrue(m2.isNamed());
-        assertTrue(m2.canRead(unnamed));
-        testsReadsAll(m2, layer);
+        Module b = layer.findModule("b").get();
+        assertTrue(b.isNamed());
+        assertTrue(b.canRead(unnamed));
+        testsReadsAll(b, layer);
 
-        Module m3 = layer.findModule("m3").get();
-        assertTrue(m3.isNamed());
-        assertTrue(m2.canRead(unnamed));
-        testsReadsAll(m3, layer);
+        Module c = layer.findModule("c").get();
+        assertTrue(c.isNamed());
+        assertTrue(b.canRead(unnamed));
+        testsReadsAll(c, layer);
     }
 
 
@@ -646,19 +655,19 @@
      */
     public void testMisc() throws IOException {
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        Path m1_jar = createDummyJarFile(dir.resolve("m1.jar"), "p/T.class");
+        Path m_jar = createDummyJarFile(dir.resolve("m.jar"), "p/T.class");
 
-        ModuleFinder finder = ModuleFinder.of(m1_jar);
+        ModuleFinder finder = ModuleFinder.of(m_jar);
 
-        assertTrue(finder.find("m1").isPresent());
-        ModuleDescriptor m1 = finder.find("m1").get().descriptor();
+        assertTrue(finder.find("m").isPresent());
+        ModuleDescriptor m = finder.find("m").get().descriptor();
 
         // test miscellaneous methods
-        assertTrue(m1.isAutomatic());
-        assertFalse(m1.isSynthetic());
-        assertFalse(m1.osName().isPresent());
-        assertFalse(m1.osArch().isPresent());
-        assertFalse(m1.osVersion().isPresent());
+        assertTrue(m.isAutomatic());
+        assertFalse(m.isSynthetic());
+        assertFalse(m.osName().isPresent());
+        assertFalse(m.osArch().isPresent());
+        assertFalse(m.osVersion().isPresent());
     }
 
 
@@ -703,17 +712,15 @@
      * and its parent Layers.
      */
     static void testsReadsAll(Module m, Layer layer) {
-        while (layer != Layer.empty()) {
+        // check that m reads all modules in the layer
+        layer.configuration().modules().stream()
+            .map(ResolvedModule::name)
+            .map(layer::findModule)
+            .map(Optional::get)
+            .forEach(other -> assertTrue(m.canRead(other)));
 
-            // check that m reads all module in the layer
-            layer.configuration().modules().stream()
-                .map(ResolvedModule::name)
-                .map(layer::findModule)
-                .map(Optional::get)
-                .forEach(m2 -> assertTrue(m.canRead(m2)));
-
-            layer = layer.parent().get();
-        }
+        // also check parent layers
+        layer.parents().forEach(l -> testsReadsAll(m, l));
     }
 
     /**
@@ -721,11 +728,11 @@
      * that reads module mn2.
      */
     static boolean reads(Configuration cf, String mn1, String mn2) {
-        Optional<ResolvedModule> om1 = cf.findModule(mn1);
-        if (!om1.isPresent())
+        Optional<ResolvedModule> om = cf.findModule(mn1);
+        if (!om.isPresent())
             return false;
 
-        return om1.get().reads().stream()
+        return om.get().reads().stream()
                 .map(ResolvedModule::name)
                 .anyMatch(mn2::equals);
     }
@@ -757,7 +764,7 @@
      * in the resulting JAR file.
      */
     static Path createDummyJarFile(Path jarfile, String... entries)
-        throws IOException
+            throws IOException
     {
         return createDummyJarFile(jarfile, null, entries);
     }
--- a/jdk/test/java/lang/module/ConfigurationTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/module/ConfigurationTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -31,11 +31,13 @@
 
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ResolutionException;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 
@@ -53,17 +55,17 @@
      */
     public void testBasic() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m3")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .build();
 
         ModuleFinder finder
@@ -77,7 +79,8 @@
         assertTrue(cf.findModule("m2").isPresent());
         assertTrue(cf.findModule("m3").isPresent());
 
-        assertTrue(cf.parent().get() == Configuration.empty());
+        assertTrue(cf.parents().size() == 1);
+        assertTrue(cf.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf.findModule("m1").get();
         ResolvedModule m2 = cf.findModule("m2").get();
@@ -102,23 +105,23 @@
 
 
     /**
-     * Basic test of "requires public":
-     *     m1 requires m2, m2 requires public m3
+     * Basic test of "requires transitive":
+     *     m1 requires m2, m2 requires transitive m3
      */
-    public void testRequiresPublic1() {
-        // m1 requires m2, m2 requires public m3
+    public void testRequiresTransitive1() {
+        // m1 requires m2, m2 requires transitive m3
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m3")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m3")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .build();
 
         ModuleFinder finder
@@ -132,7 +135,8 @@
         assertTrue(cf.findModule("m2").isPresent());
         assertTrue(cf.findModule("m3").isPresent());
 
-        assertTrue(cf.parent().get() == Configuration.empty());
+        assertTrue(cf.parents().size() == 1);
+        assertTrue(cf.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf.findModule("m1").get();
         ResolvedModule m2 = cf.findModule("m2").get();
@@ -153,23 +157,23 @@
 
 
     /**
-     * Basic test of "requires public" with configurations.
+     * Basic test of "requires transitive" with configurations.
      *
      * The test consists of three configurations:
-     * - Configuration cf1: m1, m2 requires public m1
+     * - Configuration cf1: m1, m2 requires transitive m1
      * - Configuration cf2: m3 requires m2
      */
-    public void testRequiresPublic2() {
-
-        // cf1: m1 and m2, m2 requires public m1
+    public void testRequiresTransitive2() {
+
+        // cf1: m1 and m2, m2 requires transitive m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -179,7 +183,8 @@
         assertTrue(cf1.modules().size() == 2);
         assertTrue(cf1.findModule("m1").isPresent());
         assertTrue(cf1.findModule("m2").isPresent());
-        assertTrue(cf1.parent().get() == Configuration.empty());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf1.findModule("m1").get();
         ResolvedModule m2 = cf1.findModule("m2").get();
@@ -192,7 +197,7 @@
         // cf2: m3, m3 requires m2
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -204,7 +209,8 @@
         assertTrue(cf2.findModule("m1").isPresent());  // in parent
         assertTrue(cf2.findModule("m2").isPresent());  // in parent
         assertTrue(cf2.findModule("m3").isPresent());
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         ResolvedModule m3 = cf2.findModule("m3").get();
         assertTrue(m3.configuration() == cf2);
@@ -215,18 +221,18 @@
 
 
     /**
-     * Basic test of "requires public" with configurations.
+     * Basic test of "requires transitive" with configurations.
      *
      * The test consists of three configurations:
      * - Configuration cf1: m1
-     * - Configuration cf2: m2 requires public m1, m3 requires m2
+     * - Configuration cf2: m2 requires transitive m1, m3 requires m2
      */
-    public void testRequiresPublic3() {
+    public void testRequiresTransitive3() {
 
         // cf1: m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -235,21 +241,22 @@
 
         assertTrue(cf1.modules().size() == 1);
         assertTrue(cf1.findModule("m1").isPresent());
-        assertTrue(cf1.parent().get() == Configuration.empty());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf1.findModule("m1").get();
         assertTrue(m1.reads().size() == 0);
 
 
-        // cf2: m2, m3: m2 requires public m1, m3 requires m2
+        // cf2: m2, m3: m2 requires transitive m1, m3 requires m2
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -261,7 +268,8 @@
         assertTrue(cf2.findModule("m1").isPresent());   // in parent
         assertTrue(cf2.findModule("m2").isPresent());
         assertTrue(cf2.findModule("m3").isPresent());
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         ResolvedModule m2 = cf2.findModule("m2").get();
         ResolvedModule m3 = cf2.findModule("m3").get();
@@ -278,19 +286,19 @@
 
 
     /**
-     * Basic test of "requires public" with configurations.
+     * Basic test of "requires transitive" with configurations.
      *
      * The test consists of three configurations:
      * - Configuration cf1: m1
-     * - Configuration cf2: m2 requires public m1
+     * - Configuration cf2: m2 requires transitive m1
      * - Configuraiton cf3: m3 requires m2
      */
-    public void testRequiresPublic4() {
+    public void testRequiresTransitive4() {
 
         // cf1: m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -299,17 +307,18 @@
 
         assertTrue(cf1.modules().size() == 1);
         assertTrue(cf1.findModule("m1").isPresent());
-        assertTrue(cf1.parent().get() == Configuration.empty());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf1.findModule("m1").get();
         assertTrue(m1.reads().size() == 0);
 
 
-        // cf2: m2 requires public m1
+        // cf2: m2 requires transitive m1
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
@@ -319,7 +328,8 @@
         assertTrue(cf2.modules().size() == 1);
         assertTrue(cf2.findModule("m1").isPresent());  // in parent
         assertTrue(cf2.findModule("m2").isPresent());
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         ResolvedModule m2 = cf2.findModule("m2").get();
 
@@ -331,7 +341,7 @@
         // cf3: m3 requires m2
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -343,7 +353,8 @@
         assertTrue(cf3.findModule("m1").isPresent());  // in parent
         assertTrue(cf3.findModule("m2").isPresent());  // in parent
         assertTrue(cf3.findModule("m3").isPresent());
-        assertTrue(cf3.parent().get() == cf2);
+        assertTrue(cf3.parents().size() == 1);
+        assertTrue(cf3.parents().get(0) == cf2);
 
         ResolvedModule m3 = cf3.findModule("m3").get();
 
@@ -355,23 +366,23 @@
 
 
     /**
-     * Basic test of "requires public" with configurations.
+     * Basic test of "requires transitive" with configurations.
      *
      * The test consists of two configurations:
-     * - Configuration cf1: m1, m2 requires public m1
-     * - Configuration cf2: m3 requires public m2, m4 requires m3
+     * - Configuration cf1: m1, m2 requires transitive m1
+     * - Configuration cf2: m3 requires transitive m2, m4 requires m3
      */
-    public void testRequiresPublic5() {
-
-        // cf1: m1, m2 requires public m1
+    public void testRequiresTransitive5() {
+
+        // cf1: m1, m2 requires transitive m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -381,7 +392,8 @@
         assertTrue(cf1.modules().size() == 2);
         assertTrue(cf1.findModule("m1").isPresent());
         assertTrue(cf1.findModule("m2").isPresent());
-        assertTrue(cf1.parent().get() == Configuration.empty());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf1.findModule("m1").get();
         ResolvedModule m2 = cf1.findModule("m2").get();
@@ -394,15 +406,15 @@
         assertTrue(m2.reads().contains(m1));
 
 
-        // cf2: m3 requires public m2, m4 requires m3
+        // cf2: m3 requires transitive m2, m4 requires m3
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
-                .requires(Modifier.PUBLIC, "m2")
+            = ModuleDescriptor.module("m3")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2")
                 .build();
 
         ModuleDescriptor descriptor4
-            = new ModuleDescriptor.Builder("m4")
+            = ModuleDescriptor.module("m4")
                 .requires("m3")
                 .build();
 
@@ -416,7 +428,8 @@
         assertTrue(cf2.findModule("m2").isPresent());   // in parent
         assertTrue(cf2.findModule("m3").isPresent());
         assertTrue(cf2.findModule("m4").isPresent());
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         ResolvedModule m3 = cf2.findModule("m3").get();
         ResolvedModule m4 = cf2.findModule("m4").get();
@@ -435,6 +448,362 @@
 
 
     /**
+     * Basic test of "requires transitive" with configurations.
+     *
+     * The test consists of three configurations:
+     * - Configuration cf1: m1, m2 requires transitive m1
+     * - Configuration cf2: m1, m3 requires transitive m1
+     * - Configuration cf3(cf1,cf2): m4 requires m2, m3
+     */
+    public void testRequiresTransitive6() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+                .build();
+
+        ModuleDescriptor descriptor4
+            = ModuleDescriptor.module("m4")
+                .requires("m2")
+                .requires("m3")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+        Configuration cf1 = resolveRequires(finder1, "m2");
+        assertTrue(cf1.modules().size() == 2);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.findModule("m2").isPresent());
+        assertTrue(cf1.parents().size() == 1);
+        assertTrue(cf1.parents().get(0) == Configuration.empty());
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
+        Configuration cf2 = resolveRequires(finder2, "m3");
+        assertTrue(cf2.modules().size() == 2);
+        assertTrue(cf2.findModule("m3").isPresent());
+        assertTrue(cf2.findModule("m1").isPresent());
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == Configuration.empty());
+
+        ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4);
+        Configuration cf3 = Configuration.resolveRequires(finder3,
+                List.of(cf1, cf2),
+                ModuleFinder.of(),
+                Set.of("m4"));
+        assertTrue(cf3.modules().size() == 1);
+        assertTrue(cf3.findModule("m4").isPresent());
+
+        ResolvedModule m1_l = cf1.findModule("m1").get();
+        ResolvedModule m1_r = cf2.findModule("m1").get();
+        ResolvedModule m2 = cf1.findModule("m2").get();
+        ResolvedModule m3 = cf2.findModule("m3").get();
+        ResolvedModule m4 = cf3.findModule("m4").get();
+        assertTrue(m4.configuration() == cf3);
+
+        assertTrue(m4.reads().size() == 4);
+        assertTrue(m4.reads().contains(m1_l));
+        assertTrue(m4.reads().contains(m1_r));
+        assertTrue(m4.reads().contains(m2));
+        assertTrue(m4.reads().contains(m3));
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     m1 requires static m2
+     *     m2 is not observable
+     *     resolve m1
+     */
+    public void testRequiresStatic1() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 1);
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        assertTrue(m1.reads().size() == 0);
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     m1 requires static m2
+     *     m2
+     *     resolve m1
+     */
+    public void testRequiresStatic2() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 1);
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        assertTrue(m1.reads().size() == 0);
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     m1 requires static m2
+     *     m2
+     *     resolve m1, m2
+     */
+    public void testRequiresStatic3() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf = resolveRequires(finder, "m1", "m2");
+
+        assertTrue(cf.modules().size() == 2);
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+
+        assertTrue(m1.reads().size() == 1);
+        assertTrue(m1.reads().contains(m2));
+
+        assertTrue(m2.reads().size() == 0);
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     m1 requires m2, m3
+     *     m2 requires static m2
+     *     m3
+     */
+    public void testRequiresStatic4() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .requires("m2")
+                .requires("m3")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.STATIC), "m3")
+                .build();
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .build();
+
+        ModuleFinder finder
+                = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
+
+        Configuration cf = resolveRequires(finder, "m1");
+
+        assertTrue(cf.modules().size() == 3);
+
+        ResolvedModule m1 = cf.findModule("m1").get();
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+
+        assertTrue(m1.reads().size() == 2);
+        assertTrue(m1.reads().contains(m2));
+        assertTrue(m1.reads().contains(m3));
+
+        assertTrue(m2.reads().size() == 1);
+        assertTrue(m2.reads().contains(m3));
+
+        assertTrue(m3.reads().size() == 0);
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     * The test consists of three configurations:
+     * - Configuration cf1: m1, m2
+     * - Configuration cf2: m3 requires m1, requires static m2
+     */
+    public void testRequiresStatic5() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration cf1 = resolveRequires(finder1, "m1", "m2");
+
+        assertTrue(cf1.modules().size() == 2);
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf1.findModule("m2").isPresent());
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m3").isPresent());
+
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        ResolvedModule m2 = cf1.findModule("m2").get();
+        ResolvedModule m3 = cf2.findModule("m3").get();
+
+        assertTrue(m3.reads().size() == 2);
+        assertTrue(m3.reads().contains(m1));
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     * The test consists of three configurations:
+     * - Configuration cf1: m1
+     * - Configuration cf2: m3 requires m1, requires static m2
+     */
+    public void testRequiresStatic6() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf1 = resolveRequires(finder1, "m1");
+
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m1")
+                .requires(Set.of(Requires.Modifier.STATIC), "m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m3").isPresent());
+
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        ResolvedModule m3 = cf2.findModule("m3").get();
+
+        assertTrue(m3.reads().size() == 1);
+        assertTrue(m3.reads().contains(m1));
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     *     (m1 not observable)
+     *     m2 requires transitive static m1
+     *     m3 requires m2
+     */
+    public void testRequiresStatic7() {
+        ModuleDescriptor descriptor1 = null;  // not observable
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE,
+                                Requires.Modifier.STATIC),
+                         "m1")
+                .build();
+
+        ModuleDescriptor descriptor3
+                = ModuleDescriptor.module("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor2, descriptor3);
+
+        Configuration cf = resolveRequires(finder, "m3");
+
+        assertTrue(cf.modules().size() == 2);
+        assertTrue(cf.findModule("m2").isPresent());
+        assertTrue(cf.findModule("m3").isPresent());
+        ResolvedModule m2 = cf.findModule("m2").get();
+        ResolvedModule m3 = cf.findModule("m3").get();
+        assertTrue(m2.reads().isEmpty());
+        assertTrue(m3.reads().size() == 1);
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
+     * Basic test of "requires static":
+     * - Configuration cf1: m2 requires transitive static m1
+     * - Configuration cf2: m3 requires m2
+     */
+    public void testRequiresStatic8() {
+        ModuleDescriptor descriptor1 = null;  // not observable
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE,
+                                Requires.Modifier.STATIC),
+                        "m1")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2);
+
+        Configuration cf1 = resolveRequires(finder1, "m2");
+
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m2").isPresent());
+        ResolvedModule m2 = cf1.findModule("m2").get();
+        assertTrue(m2.reads().isEmpty());
+
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3);
+
+        Configuration cf2 = resolveRequires(cf1, finder2, "m3");
+
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m3").isPresent());
+        ResolvedModule m3 = cf2.findModule("m3").get();
+        assertTrue(m3.reads().size() == 1);
+        assertTrue(m3.reads().contains(m2));
+    }
+
+
+    /**
      * Basic test of binding services
      *     m1 uses p.S
      *     m2 provides p.S
@@ -442,15 +811,15 @@
     public void testServiceBinding1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -461,7 +830,8 @@
         assertTrue(cf.modules().size() == 2);
         assertTrue(cf.findModule("m1").isPresent());
         assertTrue(cf.findModule("m2").isPresent());
-        assertTrue(cf.parent().get() == Configuration.empty());
+        assertTrue(cf.parents().size() == 1);
+        assertTrue(cf.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf.findModule("m1").get();
         ResolvedModule m2 = cf.findModule("m2").get();
@@ -484,23 +854,23 @@
     public void testServiceBinding2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .uses("p.S2")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S1", "q.Service1Impl")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S2", "q.Service2Impl")
                 .build();
 
@@ -513,7 +883,8 @@
         assertTrue(cf.findModule("m1").isPresent());
         assertTrue(cf.findModule("m2").isPresent());
         assertTrue(cf.findModule("m3").isPresent());
-        assertTrue(cf.parent().get() == Configuration.empty());
+        assertTrue(cf.parents().size() == 1);
+        assertTrue(cf.parents().get(0) == Configuration.empty());
 
         ResolvedModule m1 = cf.findModule("m1").get();
         ResolvedModule m2 = cf.findModule("m2").get();
@@ -542,7 +913,7 @@
     public void testServiceBindingWithConfigurations1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
@@ -555,9 +926,9 @@
         assertTrue(cf1.findModule("m1").isPresent());
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -565,7 +936,9 @@
 
         Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
+
         assertTrue(cf2.modules().size() == 1);
         assertTrue(cf2.findModule("m2").isPresent());
 
@@ -589,17 +962,17 @@
     public void testServiceBindingWithConfigurations2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
-                .conceals("p1")
+                .contains("p1")
                 .provides("p.S", "p1.ServiceImpl")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("p2")
+                .contains("p2")
                 .provides("p.S", "p2.ServiceImpl")
                 .build();
 
@@ -613,16 +986,16 @@
 
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m1")
-                .conceals("p3")
+                .contains("p3")
                 .provides("p.S", "p3.ServiceImpl")
                 .build();
 
         ModuleDescriptor descriptor4
-            = new ModuleDescriptor.Builder("m4")
+            = ModuleDescriptor.module("m4")
                 .requires("m1")
-                .conceals("p4")
+                .contains("p4")
                 .provides("p.S", "p4.ServiceImpl")
                 .build();
 
@@ -630,7 +1003,9 @@
 
         Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
+
         assertTrue(cf2.modules().size() == 2);
         assertTrue(cf2.findModule("m3").isPresent());
         assertTrue(cf2.findModule("m4").isPresent());
@@ -663,15 +1038,15 @@
     public void testServiceBindingWithConfigurations3() {
 
         ModuleDescriptor service
-            = new ModuleDescriptor.Builder("s")
+            = ModuleDescriptor.module("s")
                 .exports("p")
                 .build();
 
         ModuleDescriptor provider_v1
-            = new ModuleDescriptor.Builder("p")
+            = ModuleDescriptor.module("p")
                 .version("1.0")
                 .requires("s")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -689,16 +1064,16 @@
 
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("s")
                 .uses("p.S")
                 .build();
 
         ModuleDescriptor provider_v2
-            = new ModuleDescriptor.Builder("p")
+            = ModuleDescriptor.module("p")
                 .version("2.0")
                 .requires("s")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -709,7 +1084,8 @@
 
         Configuration cf2 = resolveRequiresAndUses(cf1, finder2, "m1");
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
         assertTrue(cf2.modules().size() == 2);
 
         // p should be found in cf2
@@ -723,7 +1099,8 @@
 
         cf2 = resolveRequiresAndUses(cf1, ModuleFinder.of(), finder2, "m1");
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
         assertTrue(cf2.modules().size() == 1);
 
         // p should be found in cf1
@@ -741,17 +1118,17 @@
     public void testWithTwoFinders1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
 
         ModuleDescriptor descriptor2_v1
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .version("1.0")
                 .build();
 
         ModuleDescriptor descriptor2_v2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .version("2.0")
                 .build();
 
@@ -781,22 +1158,22 @@
     public void testWithTwoFinders2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
 
         ModuleDescriptor descriptor2_v1
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
         ModuleDescriptor descriptor2_v2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -824,7 +1201,7 @@
     public void testResolvedInParent1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
@@ -847,7 +1224,7 @@
     public void testResolvedInParent2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -859,7 +1236,7 @@
 
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .build();
 
@@ -880,12 +1257,221 @@
 
 
     /**
-     * Basic test of using the beforeFinder to override a module in the parent
+     * Basic test of resolving a module that depends on modules in two parent
+     * configurations.
+     *
+     * The test consists of three configurations:
+     * - Configuration cf1: m1
+     * - Configuration cf2: m2
+     * - Configuration cf3(cf1,cf2): m3 requires m1, m2
+     */
+    public void testResolvedInMultipleParents1() {
+
+        // Configuration cf1: m1
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build();
+        Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1");
+        assertEquals(cf1.parents(), List.of(Configuration.empty()));
+        assertTrue(cf1.findModule("m1").isPresent());
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        assertTrue(m1.configuration() == cf1);
+
+        // Configuration cf2: m2
+        ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build();
+        Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2");
+        assertEquals(cf2.parents(), List.of(Configuration.empty()));
+        assertTrue(cf2.findModule("m2").isPresent());
+        ResolvedModule m2 = cf2.findModule("m2").get();
+        assertTrue(m2.configuration() == cf2);
+
+        // Configuration cf3(cf1,cf2): m3 requires m1 and m2
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m1")
+                .requires("m2")
+                .build();
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor3);
+        Configuration cf3 = Configuration.resolveRequires(
+                finder,
+                List.of(cf1, cf2),  // parents
+                ModuleFinder.of(),
+                Set.of("m3"));
+        assertEquals(cf3.parents(), List.of(cf1, cf2));
+        assertTrue(cf3.findModule("m3").isPresent());
+        ResolvedModule m3 = cf3.findModule("m3").get();
+        assertTrue(m3.configuration() == cf3);
+
+        // check readability
+        assertTrue(m1.reads().isEmpty());
+        assertTrue(m2.reads().isEmpty());
+        assertEquals(m3.reads(), Set.of(m1, m2));
+    }
+
+
+    /**
+     * Basic test of resolving a module that depends on modules in three parent
+     * configurations arranged in a diamond (two direct parents).
+     *
+     * The test consists of four configurations:
+     * - Configuration cf1: m1
+     * - Configuration cf2(cf1): m2 requires m1
+     * - Configuration cf3(cf3): m3 requires m1
+     * - Configuration cf4(cf2,cf3): m4 requires m1,m2,m3
+     */
+    public void testResolvedInMultipleParents2() {
+        // Configuration cf1: m1
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build();
+        Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1");
+        assertEquals(cf1.parents(), List.of(Configuration.empty()));
+        assertTrue(cf1.findModule("m1").isPresent());
+        ResolvedModule m1 = cf1.findModule("m1").get();
+        assertTrue(m1.configuration() == cf1);
+
+        // Configuration cf2(cf1): m2 requires m1
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires("m1")
+                .build();
+        Configuration cf2 = Configuration.resolveRequires(
+                ModuleUtils.finderOf(descriptor2),
+                List.of(cf1),  // parents
+                ModuleFinder.of(),
+                Set.of("m2"));
+        assertEquals(cf2.parents(), List.of(cf1));
+        assertTrue(cf2.findModule("m2").isPresent());
+        ResolvedModule m2 = cf2.findModule("m2").get();
+        assertTrue(m2.configuration() == cf2);
+
+        // Configuration cf3(cf1): m3 requires m1
+        ModuleDescriptor descriptor3
+            = ModuleDescriptor.module("m3")
+                .requires("m1")
+                .build();
+        Configuration cf3 = Configuration.resolveRequires(
+                ModuleUtils.finderOf(descriptor3),
+                List.of(cf1),  // parents
+                ModuleFinder.of(),
+                Set.of("m3"));
+        assertEquals(cf3.parents(), List.of(cf1));
+        assertTrue(cf3.findModule("m3").isPresent());
+        ResolvedModule m3 = cf3.findModule("m3").get();
+        assertTrue(m3.configuration() == cf3);
+
+        // Configuration cf4(cf2,cf3): m4 requires m1,m2,m3
+        ModuleDescriptor descriptor4
+            = ModuleDescriptor.module("m4")
+                .requires("m1")
+                .requires("m2")
+                .requires("m3")
+                .build();
+        Configuration cf4 = Configuration.resolveRequires(
+                ModuleUtils.finderOf(descriptor4),
+                List.of(cf2, cf3),  // parents
+                ModuleFinder.of(),
+                Set.of("m4"));
+        assertEquals(cf4.parents(), List.of(cf2, cf3));
+        assertTrue(cf4.findModule("m4").isPresent());
+        ResolvedModule m4 = cf4.findModule("m4").get();
+        assertTrue(m4.configuration() == cf4);
+
+        // check readability
+        assertTrue(m1.reads().isEmpty());
+        assertEquals(m2.reads(), Set.of(m1));
+        assertEquals(m3.reads(), Set.of(m1));
+        assertEquals(m4.reads(), Set.of(m1, m2, m3));
+    }
+
+
+    /**
+     * Basic test of resolving a module that depends on modules in three parent
+     * configurations arranged in a diamond (two direct parents).
+     *
+     * The test consists of four configurations:
+     * - Configuration cf1: m1@1
+     * - Configuration cf2: m1@2, m2@2
+     * - Configuration cf3: m1@3, m2@3, m3@3
+     * - Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3
+     */
+    public void testResolvedInMultipleParents3() {
+        ModuleDescriptor descriptor1, descriptor2, descriptor3;
+
+        // Configuration cf1: m1@1
+        descriptor1 = ModuleDescriptor.module("m1").version("1").build();
+        Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1");
+        assertEquals(cf1.parents(), List.of(Configuration.empty()));
+
+        // Configuration cf2: m1@2, m2@2
+        descriptor1 = ModuleDescriptor.module("m1").version("2").build();
+        descriptor2 = ModuleDescriptor.module("m2").version("2").build();
+        Configuration cf2 = resolveRequires(
+                ModuleUtils.finderOf(descriptor1, descriptor2),
+                "m1", "m2");
+        assertEquals(cf2.parents(), List.of(Configuration.empty()));
+
+        // Configuration cf3: m1@3, m2@3, m3@3
+        descriptor1 = ModuleDescriptor.module("m1").version("3").build();
+        descriptor2 = ModuleDescriptor.module("m2").version("3").build();
+        descriptor3 = ModuleDescriptor.module("m3").version("3").build();
+        Configuration cf3 = resolveRequires(
+                ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3),
+                "m1", "m2", "m3");
+        assertEquals(cf3.parents(), List.of(Configuration.empty()));
+
+        // Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3
+        ModuleDescriptor descriptor4
+                = ModuleDescriptor.module("m4")
+                .requires("m1")
+                .requires("m2")
+                .requires("m3")
+                .build();
+        Configuration cf4 = Configuration.resolveRequires(
+                ModuleUtils.finderOf(descriptor4),
+                List.of(cf1, cf2, cf3),  // parents
+                ModuleFinder.of(),
+                Set.of("m4"));
+        assertEquals(cf4.parents(), List.of(cf1, cf2, cf3));
+
+        assertTrue(cf1.findModule("m1").isPresent());
+        assertTrue(cf2.findModule("m1").isPresent());
+        assertTrue(cf2.findModule("m2").isPresent());
+        assertTrue(cf3.findModule("m1").isPresent());
+        assertTrue(cf3.findModule("m2").isPresent());
+        assertTrue(cf3.findModule("m3").isPresent());
+        assertTrue(cf4.findModule("m4").isPresent());
+
+        ResolvedModule m1_1 = cf1.findModule("m1").get();
+        ResolvedModule m1_2 = cf2.findModule("m1").get();
+        ResolvedModule m2_2 = cf2.findModule("m2").get();
+        ResolvedModule m1_3 = cf3.findModule("m1").get();
+        ResolvedModule m2_3 = cf3.findModule("m2").get();
+        ResolvedModule m3_3 = cf3.findModule("m3").get();
+        ResolvedModule m4   = cf4.findModule("m4").get();
+
+        assertTrue(m1_1.configuration() == cf1);
+        assertTrue(m1_2.configuration() == cf2);
+        assertTrue(m2_2.configuration() == cf2);
+        assertTrue(m1_3.configuration() == cf3);
+        assertTrue(m2_3.configuration() == cf3);
+        assertTrue(m3_3.configuration() == cf3);
+        assertTrue(m4.configuration() == cf4);
+
+        // check readability
+        assertTrue(m1_1.reads().isEmpty());
+        assertTrue(m1_2.reads().isEmpty());
+        assertTrue(m2_2.reads().isEmpty());
+        assertTrue(m1_3.reads().isEmpty());
+        assertTrue(m2_3.reads().isEmpty());
+        assertTrue(m3_3.reads().isEmpty());
+        assertEquals(m4.reads(), Set.of(m1_1, m2_2, m3_3));
+    }
+
+
+    /**
+     * Basic test of using the beforeFinder to override a module in a parent
      * configuration.
      */
     public void testOverriding1() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
@@ -899,6 +1485,39 @@
         assertTrue(cf2.findModule("m1").isPresent());
     }
 
+    /**
+     * Basic test of using the beforeFinder to override a module in a parent
+     * configuration.
+     */
+    public void testOverriding2() {
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build();
+        Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1");
+        assertTrue(cf1.modules().size() == 1);
+        assertTrue(cf1.findModule("m1").isPresent());
+
+        ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build();
+        Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2");
+        assertTrue(cf2.modules().size() == 1);
+        assertTrue(cf2.findModule("m2").isPresent());
+
+        ModuleDescriptor descriptor3 = ModuleDescriptor.module("m3").build();
+        Configuration cf3 = resolveRequires(ModuleUtils.finderOf(descriptor3), "m3");
+        assertTrue(cf3.modules().size() == 1);
+        assertTrue(cf3.findModule("m3").isPresent());
+
+        // override m2, m1 and m3 should be found in parent configurations
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor2);
+        Configuration cf4 = Configuration.resolveRequires(
+                finder,
+                List.of(cf1, cf2, cf3),
+                ModuleFinder.of(),
+                Set.of("m1", "m2", "m3"));
+        assertTrue(cf4.modules().size() == 1);
+        assertTrue(cf4.findModule("m2").isPresent());
+        ResolvedModule m2 = cf4.findModule("m2").get();
+        assertTrue(m2.configuration() == cf4);
+    }
+
 
     /**
      * Basic test of using the beforeFinder to override a module in the parent
@@ -906,18 +1525,18 @@
      * module in the parent is read.
      *
      * The test consists of two configurations:
-     * - Configuration cf1: m1, m2 requires public m1
+     * - Configuration cf1: m1, m2 requires transitive m1
      * - Configuration cf2: m1, m3 requires m2
      */
-    public void testOverriding2() {
+    public void testOverriding3() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -931,7 +1550,7 @@
         // cf2: m3 requires m2, m1
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -939,7 +1558,8 @@
 
         Configuration cf2 = resolveRequires(cf1, finder2, "m1", "m3");
 
-        assertTrue(cf2.parent().get() == cf1);
+        assertTrue(cf2.parents().size() == 1);
+        assertTrue(cf2.parents().get(0) == cf1);
 
         assertTrue(cf2.modules().size() == 2);
         assertTrue(cf2.findModule("m1").isPresent());
@@ -977,7 +1597,7 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testDirectDependencyNotFound() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").requires("m2").build();
+            = ModuleDescriptor.module("m1").requires("m2").build();
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
         resolveRequires(finder, "m1");
     }
@@ -989,9 +1609,9 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testTransitiveDependencyNotFound() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").requires("m2").build();
+            = ModuleDescriptor.module("m1").requires("m2").build();
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2").requires("m3").build();
+            = ModuleDescriptor.module("m2").requires("m3").build();
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
         resolveRequires(finder, "m1");
     }
@@ -1006,16 +1626,16 @@
         // service provider dependency (on m3) not found
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .requires("m3")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -1032,11 +1652,11 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testSimpleCycle() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").requires("m2").build();
+            = ModuleDescriptor.module("m1").requires("m2").build();
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2").requires("m3").build();
+            = ModuleDescriptor.module("m2").requires("m3").build();
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3").requires("m1").build();
+            = ModuleDescriptor.module("m3").requires("m1").build();
         ModuleFinder finder
             = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3);
         resolveRequires(finder, "m1");
@@ -1049,19 +1669,19 @@
     public void testCycleInProvider() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .uses("p.S")
                 .build();
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .requires("m3")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -1080,19 +1700,19 @@
     public void testPackageSuppliedByTwoOthers() {
 
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
                 .requires("m3")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
+            =  ModuleDescriptor.module("m2")
                 .exports("p")
                 .build();
 
         ModuleDescriptor descriptor3
-            =  new ModuleDescriptor.Builder("m3")
-                .exports("p", "m1")
+            =  ModuleDescriptor.module("m3")
+                .exports("p", Set.of("m1"))
                 .build();
 
         ModuleFinder finder
@@ -1104,45 +1724,44 @@
 
 
     /**
-     * Test the scenario where a module has a concealed package p and reads
+     * Test the scenario where a module contains a package p and reads
      * a module that exports package p.
      */
     @Test(expectedExceptions = { ResolutionException.class })
     public void testPackageSuppliedBySelfAndOther() {
 
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
-                .conceals("p")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
+            =  ModuleDescriptor.module("m2")
                 .exports("p")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
 
-        //  m1 contains package p, module m2 exports package p to m1
+        // m1 contains package p, module m2 exports package p to m1
         resolveRequires(finder, "m1");
     }
 
 
     /**
-     * Test the scenario where a module has a concealed package p and reads
-     * a module that also has a concealed package p.
+     * Test the scenario where a module contains a package p and reads
+     * a module that also contains a package p.
      */
-    public void testPackagePrivateToSelfAndOther() {
-
+    public void testContainsPackageInSelfAndOther() {
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
-                .conceals("p")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
-                .conceals("p")
+            =  ModuleDescriptor.module("m2")
+                .contains("p")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -1169,7 +1788,7 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testExportSamePackageAsBootLayer() {
         ModuleDescriptor descriptor
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("java.base")
                 .exports("java.lang")
                 .build();
@@ -1184,12 +1803,12 @@
 
 
     /**
-     * Test "uses p.S" where p is a concealed package in the same module.
+     * Test "uses p.S" where p is contained in the same module.
      */
-    public void testConcealedService1() {
+    public void testContainsService1() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
                 .uses("p.S")
                 .build();
 
@@ -1203,17 +1822,17 @@
 
 
     /**
-     * Test "uses p.S" where p is a concealed package in a different module.
+     * Test "uses p.S" where p is contained in a different module.
      */
     @Test(expectedExceptions = { ResolutionException.class })
-    public void testConcealedService2() {
+    public void testContainsService2() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .uses("p.S")
                 .build();
@@ -1226,13 +1845,13 @@
 
 
     /**
-     * Test "provides p.S" where p is a concealed package in the same module.
+     * Test "provides p.S" where p is contained in the same module.
      */
-    public void testConcealedService3() {
+    public void testContainsService3() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
-                .conceals("q")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
+                .contains("q")
                 .provides("p.S", "q.S1")
                 .build();
 
@@ -1246,19 +1865,19 @@
 
 
     /**
-     * Test "provides p.S" where p is a concealed package in a different module.
+     * Test "provides p.S" where p is contained in a different module.
      */
     @Test(expectedExceptions = { ResolutionException.class })
-    public void testConcealedService4() {
+    public void testContainsService4() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
-                .conceals("q")
+                .contains("q")
                 .provides("p.S", "q.S1")
                 .build();
 
@@ -1275,7 +1894,7 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testServiceTypePackageNotExported1() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .uses("p.S")
                 .build();
 
@@ -1292,8 +1911,8 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testServiceTypePackageNotExported2() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("q")
+            = ModuleDescriptor.module("m1")
+                .contains("q")
                 .provides("p.S", "q.T")
                 .build();
 
@@ -1310,13 +1929,13 @@
     @Test(expectedExceptions = { ResolutionException.class })
     public void testProviderPackageNotLocal() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .exports("q")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m1")
                 .provides("p.S", "q.T")
                 .build();
@@ -1334,7 +1953,7 @@
     public void testEmptyConfiguration() {
         Configuration cf = Configuration.empty();
 
-        assertFalse(cf.parent().isPresent());
+        assertTrue(cf.parents().isEmpty());
 
         assertTrue(cf.modules().isEmpty());
         assertFalse(cf.findModule("java.base").isPresent());
@@ -1389,7 +2008,7 @@
     public void testPlatformMatch(String s1, String s2) {
 
         ModuleDescriptor.Builder builder
-            = new ModuleDescriptor.Builder("m1").requires("m2");
+            = ModuleDescriptor.module("m1").requires("m2");
 
         String[] s = s1.split("-");
         if (!s[0].equals("*"))
@@ -1401,7 +2020,7 @@
 
         ModuleDescriptor descriptor1 = builder.build();
 
-        builder = new ModuleDescriptor.Builder("m2");
+        builder = ModuleDescriptor.module("m2");
 
         s = s2.split("-");
         if (!s[0].equals("*"))
@@ -1433,6 +2052,21 @@
     }
 
 
+    // no parents
+
+    @Test(expectedExceptions = { IllegalArgumentException.class })
+    public void testResolveRequiresWithNoParents() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration.resolveRequires(empty, List.of(), empty, Set.of());
+    }
+
+    @Test(expectedExceptions = { IllegalArgumentException.class })
+    public void testResolveRequiresAndUsesWithNoParents() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration.resolveRequiresAndUses(empty, List.of(), empty, Set.of());
+    }
+
+
     // null handling
 
     // finder1, finder2, roots
@@ -1449,6 +2083,31 @@
     }
 
     @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull3() {
+        Configuration empty = Configuration.empty();
+        Configuration.resolveRequires(null, List.of(empty),  ModuleFinder.of(), Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull4() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration.resolveRequires(empty, null, empty, Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull5() {
+        Configuration cf = Layer.boot().configuration();
+        Configuration.resolveRequires(ModuleFinder.of(), List.of(cf), null, Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresWithNull6() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration cf = Layer.boot().configuration();
+        Configuration.resolveRequires(empty, List.of(cf), empty, null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
     public void testResolveRequiresAndUsesWithNull1() {
         resolveRequiresAndUses((ModuleFinder) null, ModuleFinder.of());
     }
@@ -1459,6 +2118,31 @@
     }
 
     @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull3() {
+        Configuration empty = Configuration.empty();
+        Configuration.resolveRequiresAndUses(null, List.of(empty), ModuleFinder.of(), Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull4() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration.resolveRequiresAndUses(empty, null, empty, Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull5() {
+        Configuration cf = Layer.boot().configuration();
+        Configuration.resolveRequiresAndUses(ModuleFinder.of(), List.of(cf), null, Set.of());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testResolveRequiresAndUsesWithNull6() {
+        ModuleFinder empty = ModuleFinder.of();
+        Configuration cf = Layer.boot().configuration();
+        Configuration.resolveRequiresAndUses(empty, List.of(cf), empty, null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
     public void testFindModuleWithNull() {
         Configuration.empty().findModule(null);
     }
--- a/jdk/test/java/lang/module/ModuleDescriptorTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,28 +23,34 @@
 
 /**
  * @test
- * @modules java.base/jdk.internal.module
+ * @modules java.base/java.lang.module:open
+ *          java.base/jdk.internal.module
  * @run testng ModuleDescriptorTest
  * @summary Basic test for java.lang.module.ModuleDescriptor and its builder
  */
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 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.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.*;
 
@@ -72,7 +78,7 @@
     // requires
 
     private Requires requires(Set<Modifier> mods, String mn) {
-        return new Builder("m")
+        return ModuleDescriptor.module("m")
             .requires(mods, mn)
             .build()
             .requires()
@@ -80,19 +86,15 @@
             .next();
     }
 
-    public void testRequiresWithRequires() {
-        Requires r1 = requires(null, "foo");
-        ModuleDescriptor descriptor = new Builder("m").requires(r1).build();
-        Requires r2 = descriptor.requires().iterator().next();
-        assertEquals(r1, r2);
+    private Requires requires(String mn) {
+        return requires(Collections.emptySet(), mn);
     }
 
-    public void testRequiresWithNullModifiers() {
-        Requires r = requires(null, "foo");
-        assertEquals(r, r);
-        assertTrue(r.compareTo(r) == 0);
-        assertTrue(r.modifiers().isEmpty());
-        assertEquals(r.name(), "foo");
+    public void testRequiresWithRequires() {
+        Requires r1 = requires("foo");
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m").requires(r1).build();
+        Requires r2 = descriptor.requires().iterator().next();
+        assertEquals(r1, r2);
     }
 
     public void testRequiresWithNoModifiers() {
@@ -104,18 +106,18 @@
     }
 
     public void testRequiresWithOneModifier() {
-        Requires r = requires(EnumSet.of(PUBLIC), "foo");
+        Requires r = requires(EnumSet.of(TRANSITIVE), "foo");
         assertEquals(r, r);
         assertTrue(r.compareTo(r) == 0);
-        assertEquals(r.modifiers(), EnumSet.of(PUBLIC));
+        assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE));
         assertEquals(r.name(), "foo");
     }
 
     public void testRequiresWithTwoModifiers() {
-        Requires r = requires(EnumSet.of(PUBLIC, SYNTHETIC), "foo");
+        Requires r = requires(EnumSet.of(TRANSITIVE, SYNTHETIC), "foo");
         assertEquals(r, r);
         assertTrue(r.compareTo(r) == 0);
-        assertEquals(r.modifiers(), EnumSet.of(PUBLIC, SYNTHETIC));
+        assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, SYNTHETIC));
         assertEquals(r.name(), "foo");
     }
 
@@ -123,35 +125,35 @@
         Requires r = requires(EnumSet.allOf(Modifier.class), "foo");
         assertEquals(r, r);
         assertTrue(r.compareTo(r) == 0);
-        assertEquals(r.modifiers(), EnumSet.allOf(Modifier.class));
+        assertEquals(r.modifiers(), EnumSet.of(TRANSITIVE, STATIC, SYNTHETIC, MANDATED));
         assertEquals(r.name(), "foo");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
     public void testRequiresWithDuplicatesRequires() {
-        Requires r = requires(null, "foo");
-        new Builder("m").requires(r).requires(r);
+        Requires r = requires("foo");
+        ModuleDescriptor.module("m").requires(r).requires(r);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testRequiresSelfWithRequires() {
-        Requires r = requires(null, "foo");
-        new Builder("foo").requires(r);
+        Requires r = requires("foo");
+        ModuleDescriptor.module("foo").requires(r);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testRequiresSelfWithNoModifier() {
-        new Builder("m").requires("m");
+        ModuleDescriptor.module("m").requires("m");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testRequiresSelfWithOneModifier() {
-        new Builder("m").requires(PUBLIC, "m");
+        ModuleDescriptor.module("m").requires(Set.of(TRANSITIVE), "m");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testRequiresSelfWithAllModifiers() {
-        new Builder("m").requires(EnumSet.allOf(Modifier.class), "m");
+        ModuleDescriptor.module("m").requires(EnumSet.allOf(Modifier.class), "m");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
@@ -162,7 +164,7 @@
 
     @Test(expectedExceptions = NullPointerException.class)
     public void testRequiresWithNullRequires() {
-        new Builder("m").requires((Requires) null);
+        ModuleDescriptor.module("m").requires((Requires) null);
     }
 
     public void testRequiresCompare() {
@@ -174,9 +176,9 @@
     }
 
     public void testRequiresCompareWithDifferentModifiers() {
-        Requires r1 = requires(EnumSet.of(PUBLIC), "foo");
+        Requires r1 = requires(EnumSet.of(TRANSITIVE), "foo");
         Requires r2 = requires(EnumSet.of(SYNTHETIC), "foo");
-        int n = Integer.compare(1 << PUBLIC.ordinal(), 1 << SYNTHETIC.ordinal());
+        int n = Integer.compare(1 << TRANSITIVE.ordinal(), 1 << SYNTHETIC.ordinal());
         assertTrue(r1.compareTo(r2) == n);
         assertTrue(r2.compareTo(r1) == -n);
     }
@@ -188,6 +190,26 @@
         assertTrue(r2.compareTo(r1) == 0);
     }
 
+    public void testRequiresEqualsAndHashCode() {
+        Requires r1 = requires("foo");
+        Requires r2 = requires("foo");
+        assertEquals(r1, r2);
+        assertTrue(r1.hashCode() == r2.hashCode());
+
+        r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
+        r2 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
+        assertEquals(r1, r2);
+        assertTrue(r1.hashCode() == r2.hashCode());
+
+        r1 = requires("foo");
+        r2 = requires("bar");
+        assertNotEquals(r1, r2);
+
+        r1 = requires(EnumSet.allOf(Requires.Modifier.class), "foo");
+        r2 = requires(Set.of(), "foo");
+        assertNotEquals(r1, r2);
+    }
+
     public void testRequiresToString() {
         Requires r = requires(EnumSet.noneOf(Modifier.class), "foo");
         assertTrue(r.toString().contains("foo"));
@@ -196,9 +218,22 @@
 
     // exports
 
+    private Exports exports(Set<Exports.Modifier> mods, String pn) {
+        return ModuleDescriptor.module("foo")
+            .exports(mods, pn)
+            .build()
+            .exports()
+            .iterator()
+            .next();
+    }
+
     private Exports exports(String pn) {
-        return new Builder("foo")
-            .exports(pn)
+        return exports(Set.of(), pn);
+    }
+
+    private Exports exports(Set<Exports.Modifier> mods, String pn, String target) {
+        return ModuleDescriptor.module("foo")
+            .exports(mods, pn, Set.of(target))
             .build()
             .exports()
             .iterator()
@@ -206,17 +241,13 @@
     }
 
     private Exports exports(String pn, String target) {
-        return new Builder("foo")
-            .exports(pn, target)
-            .build()
-            .exports()
-            .iterator()
-            .next();
+        return exports(Set.of(), pn, target);
     }
 
+
     public void testExportsExports() {
         Exports e1 = exports("p");
-        ModuleDescriptor descriptor = new Builder("m").exports(e1).build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m").exports(e1).build();
         Exports e2 = descriptor.exports().iterator().next();
         assertEquals(e1, e2);
     }
@@ -224,6 +255,7 @@
     public void testExportsToAll() {
         Exports e = exports("p");
         assertEquals(e, e);
+        assertTrue(e.modifiers().isEmpty());
         assertEquals(e.source(), "p");
         assertFalse(e.isQualified());
         assertTrue(e.targets().isEmpty());
@@ -232,6 +264,7 @@
     public void testExportsToTarget() {
         Exports e = exports("p", "bar");
         assertEquals(e, e);
+        assertTrue(e.modifiers().isEmpty());
         assertEquals(e.source(), "p");
         assertTrue(e.isQualified());
         assertTrue(e.targets().size() == 1);
@@ -243,13 +276,14 @@
         targets.add("bar");
         targets.add("gus");
         Exports e
-            = new Builder("foo")
+            = ModuleDescriptor.module("foo")
                 .exports("p", targets)
                 .build()
                 .exports()
                 .iterator()
                 .next();
         assertEquals(e, e);
+        assertTrue(e.modifiers().isEmpty());
         assertEquals(e.source(), "p");
         assertTrue(e.isQualified());
         assertTrue(e.targets().size() == 2);
@@ -257,56 +291,94 @@
         assertTrue(e.targets().contains("gus"));
     }
 
+    public void testExportsToAllWithModifier() {
+        Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        assertEquals(e, e);
+        assertTrue(e.modifiers().size() == 1);
+        assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC));
+        assertEquals(e.source(), "p");
+        assertFalse(e.isQualified());
+        assertTrue(e.targets().isEmpty());
+    }
+
+    public void testExportsToTargetWithModifier() {
+        Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p", "bar");
+        assertEquals(e, e);
+        assertTrue(e.modifiers().size() == 1);
+        assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC));
+        assertEquals(e.source(), "p");
+        assertTrue(e.isQualified());
+        assertTrue(e.targets().size() == 1);
+        assertTrue(e.targets().contains("bar"));
+    }
+
     @Test(expectedExceptions = IllegalStateException.class)
     public void testExportsWithDuplicate1() {
         Exports e = exports("p");
-        new Builder("foo").exports(e).exports(e);
+        ModuleDescriptor.module("foo").exports(e).exports(e);
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
     public void testExportsWithDuplicate2() {
-        new Builder("foo").exports("p").exports("p");
+        ModuleDescriptor.module("foo").exports("p").exports("p");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
-    public void testExportsWithConcealedPackage() {
-        new Builder("foo").conceals("p").exports("p");
+    public void testExportsOnContainedPackage() {
+        ModuleDescriptor.module("foo").contains("p").exports("p");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
-    public void testExportsToTargetWithConcealedPackage() {
-        new Builder("foo").conceals("p").exports("p", "bar");
+    public void testExportsToTargetOnContainedPackage() {
+        ModuleDescriptor.module("foo").contains("p").exports("p", Set.of("bar"));
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class )
     public void testExportsWithEmptySet() {
-        new Builder("foo").exports("p", Collections.emptySet());
+        ModuleDescriptor.module("foo").exports("p", Collections.emptySet());
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testExportsWithBadName(String pn, String ignore) {
-        new Builder("foo").exports(pn);
+        ModuleDescriptor.module("foo").exports(pn);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testExportsWithNullExports() {
-        new Builder("foo").exports((Exports)null);
-    }
-
-    @Test(expectedExceptions = IllegalArgumentException.class )
-    public void testExportsWithNullTarget() {
-        new Builder("foo").exports("p", (String) null);
+        ModuleDescriptor.module("foo").exports((Exports) null);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testExportsWithNullTargets() {
-        new Builder("foo").exports("p", (Set<String>) null);
+        ModuleDescriptor.module("foo").exports("p", (Set<String>) null);
+    }
+
+    public void testExportsEqualsAndHashCode() {
+        Exports e1, e2;
+
+        e1 = exports("p");
+        e2 = exports("p");
+        assertEquals(e1, e2);
+        assertTrue(e1.hashCode() == e2.hashCode());
+
+        e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        e2 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        assertEquals(e1, e2);
+        assertTrue(e1.hashCode() == e2.hashCode());
+
+        e1 = exports("p");
+        e2 = exports("q");
+        assertNotEquals(e1, e2);
+
+        e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        e2 = exports(Set.of(), "p");
+        assertNotEquals(e1, e2);
     }
 
     public void testExportsToString() {
-        String s = new Builder("foo")
-            .exports("p1", "bar")
+        String s = ModuleDescriptor.module("foo")
+            .exports("p1", Set.of("bar"))
             .build()
             .exports()
             .iterator()
@@ -317,11 +389,188 @@
     }
 
 
+    // opens
+
+    private Opens opens(Set<Opens.Modifier> mods, String pn) {
+        return ModuleDescriptor.module("foo")
+                .opens(mods, pn)
+                .build()
+                .opens()
+                .iterator()
+                .next();
+    }
+
+    private Opens opens(String pn) {
+        return opens(Set.of(), pn);
+    }
+
+    private Opens opens(Set<Opens.Modifier> mods, String pn, String target) {
+        return ModuleDescriptor.module("foo")
+                .opens(mods, pn, Set.of(target))
+                .build()
+                .opens()
+                .iterator()
+                .next();
+    }
+
+    private Opens opens(String pn, String target) {
+        return opens(Set.of(), pn, target);
+    }
+
+    public void testOpensOpens() {
+        Opens o1 = opens("p");
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m").opens(o1).build();
+        Opens o2 = descriptor.opens().iterator().next();
+        assertEquals(o1, o2);
+    }
+
+    public void testOpensToAll() {
+        Opens o = opens("p");
+        assertEquals(o, o);
+        assertTrue(o.modifiers().isEmpty());
+        assertEquals(o.source(), "p");
+        assertFalse(o.isQualified());
+        assertTrue(o.targets().isEmpty());
+    }
+
+
+    public void testOpensToTarget() {
+        Opens o = opens("p", "bar");
+        assertEquals(o, o);
+        assertTrue(o.modifiers().isEmpty());
+        assertEquals(o.source(), "p");
+        assertTrue(o.isQualified());
+        assertTrue(o.targets().size() == 1);
+        assertTrue(o.targets().contains("bar"));
+    }
+
+    public void testOpensToTargets() {
+        Set<String> targets = new HashSet<>();
+        targets.add("bar");
+        targets.add("gus");
+        Opens o = ModuleDescriptor.module("foo")
+                .opens("p", targets)
+                .build()
+                .opens()
+                .iterator()
+                .next();
+        assertEquals(o, o);
+        assertTrue(o.modifiers().isEmpty());
+        assertEquals(o.source(), "p");
+        assertTrue(o.isQualified());
+        assertTrue(o.targets().size() == 2);
+        assertTrue(o.targets().contains("bar"));
+        assertTrue(o.targets().contains("gus"));
+    }
+
+    /*
+
+    public void testOpensToAllWithModifier() {
+        Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p");
+        assertEquals(e, e);
+        assertTrue(e.modifiers().size() == 1);
+        assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC));
+        assertEquals(e.source(), "p");
+        assertFalse(e.isQualified());
+        assertTrue(e.targets().isEmpty());
+    }
+
+    public void testOpensToTargetWithModifier() {
+        Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p", Set.of("bar"));
+        assertEquals(e, e);
+        assertTrue(e.modifiers().size() == 1);
+        assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC));
+        assertEquals(e.source(), "p");
+        assertTrue(e.isQualified());
+        assertTrue(e.targets().size() == 1);
+        assertTrue(e.targets().contains("bar"));
+    }
+
+
+    */
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensWithDuplicate1() {
+        Opens o = opens("p");
+        ModuleDescriptor.module("foo").opens(o).opens(o);
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensWithDuplicate2() {
+        ModuleDescriptor.module("foo").opens("p").opens("p");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensOnContainedPackage() {
+        ModuleDescriptor.module("foo").contains("p").opens("p");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensToTargetOnContainedPackage() {
+        ModuleDescriptor.module("foo").contains("p").opens("p", Set.of("bar"));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class )
+    public void testOpensWithEmptySet() {
+        ModuleDescriptor.module("foo").opens("p", Collections.emptySet());
+    }
+
+    @Test(dataProvider = "invalidjavaidentifiers",
+            expectedExceptions = IllegalArgumentException.class )
+    public void testOpensWithBadName(String pn, String ignore) {
+        ModuleDescriptor.module("foo").opens(pn);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class )
+    public void testOpensWithNullExports() {
+        ModuleDescriptor.module("foo").opens((Opens) null);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class )
+    public void testOpensWithNullTargets() {
+        ModuleDescriptor.module("foo").opens("p", (Set<String>) null);
+    }
+
+    public void testOpensEqualsAndHashCode() {
+        Opens o1, o2;
+
+        o1 = opens("p");
+        o2 = opens("p");
+        assertEquals(o1, o2);
+        assertTrue(o1.hashCode() == o1.hashCode());
+
+        o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p");
+        o2 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p");
+        assertEquals(o1, o2);
+        assertTrue(o1.hashCode() == o2.hashCode());
+
+        o1 = opens("p");
+        o2 = opens("q");
+        assertNotEquals(o1, o2);
+
+        o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p");
+        o2 = opens(Set.of(), "p");
+        assertNotEquals(o1, o2);
+    }
+
+    public void testOpensToString() {
+        String s = ModuleDescriptor.module("foo")
+                .opens("p1", Set.of("bar"))
+                .build()
+                .opens()
+                .iterator()
+                .next()
+                .toString();
+        assertTrue(s.contains("p1"));
+        assertTrue(s.contains("bar"));
+    }
+
+
     // uses
 
     public void testUses() {
         Set<String> uses
-            = new Builder("foo")
+            = ModuleDescriptor.module("foo")
                 .uses("p.S")
                 .uses("q.S")
                 .build()
@@ -333,126 +582,148 @@
 
     @Test(expectedExceptions = IllegalStateException.class)
     public void testUsesWithDuplicate() {
-        new Builder("foo").uses("p.S").uses("p.S");
+        ModuleDescriptor.module("foo").uses("p.S").uses("p.S");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testUsesWithBadName(String service, String ignore) {
-        new Builder("foo").uses(service);
+        ModuleDescriptor.module("foo").uses(service);
     }
 
 
     // provides
 
     private Provides provides(String st, String pc) {
-        return new Builder("foo")
+        return ModuleDescriptor.module("foo")
             .provides(st, pc)
             .build()
             .provides()
-            .values()
             .iterator()
             .next();
     }
 
     public void testProvidesWithProvides() {
         Provides p1 = provides("p.S", "q.S1");
-        ModuleDescriptor descriptor = new Builder("m").provides(p1).build();
-        Provides p2 = descriptor.provides().get("p.S");
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m")
+                .provides(p1)
+                .build();
+        Provides p2 = descriptor.provides().iterator().next();
         assertEquals(p1, p2);
     }
 
+
     public void testProvides() {
-        Set<String> pns = new HashSet<>();
-        pns.add("q.P1");
-        pns.add("q.P2");
-
-        Map<String, Provides> map
-            = new Builder("foo")
-                .provides("p.S", pns)
+        Set<Provides> set = ModuleDescriptor.module("foo")
+                .provides("p.S", List.of("q.P1", "q.P2"))
                 .build()
                 .provides();
-        assertTrue(map.size() == 1);
+        assertTrue(set.size() == 1);
 
-        Provides p = map.values().iterator().next();
+        Provides p = set.iterator().next();
         assertEquals(p, p);
+        assertEquals(p.service(), "p.S");
         assertTrue(p.providers().size() == 2);
-        assertTrue(p.providers().contains("q.P1"));
-        assertTrue(p.providers().contains("q.P2"));
+        assertEquals(p.providers().get(0), "q.P1");
+        assertEquals(p.providers().get(1), "q.P2");
     }
 
     @Test(expectedExceptions = IllegalStateException.class )
     public void testProvidesWithDuplicateProvides() {
         Provides p = provides("p.S", "q.S2");
-        new Builder("m").provides("p.S", "q.S1").provides(p);
+        ModuleDescriptor.module("m").provides("p.S", "q.S1").provides(p);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class )
     public void testProvidesWithEmptySet() {
-        new Builder("foo").provides("p.Service", Collections.emptySet());
+        ModuleDescriptor.module("foo").provides("p.Service", Collections.emptyList());
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testProvidesWithBadService(String service, String ignore) {
-        new Builder("foo").provides(service, "p.Provider");
+        ModuleDescriptor.module("foo").provides(service, "p.Provider");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testProvidesWithBadProvider(String provider, String ignore) {
-        new Builder("foo").provides("p.Service", provider);
+        ModuleDescriptor.module("foo").provides("p.Service", provider);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testProvidesWithNullProvides() {
-        new Builder("foo").provides((Provides)null);
+        ModuleDescriptor.module("foo").provides((Provides) null);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testProvidesWithNullProviders() {
-        new Builder("foo").provides("p.S", (Set<String>) null);
+        ModuleDescriptor.module("foo").provides("p.S", (List<String>) null);
+    }
+
+    public void testProvidesEqualsAndHashCode() {
+        Provides p1, p2;
+
+        p1 = provides("p.S", "q.S1");
+        p2 = provides("p.S", "q.S1");
+        assertEquals(p1, p2);
+        assertTrue(p1.hashCode() == p2.hashCode());
+
+        p1 = provides("p.S", "q.S1");
+        p2 = provides("p.S", "q.S2");
+        assertNotEquals(p1, p2);
+
+        p1 = provides("p.S", "q.S1");
+        p2 = provides("p.S2", "q.S1");
+        assertNotEquals(p1, p2);
     }
 
-
-    // conceals
+    // contains
 
-    public void testConceals() {
-        Set<String> conceals
-            = new Builder("foo").conceals("p").conceals("q").build().conceals();
-        assertTrue(conceals.size() == 2);
-        assertTrue(conceals.contains("p"));
-        assertTrue(conceals.contains("q"));
+    public void testContains() {
+        Set<String> packages = ModuleDescriptor.module("foo")
+                .contains("p")
+                .contains("q")
+                .build()
+                .packages();
+        assertTrue(packages.size() == 2);
+        assertTrue(packages.contains("p"));
+        assertTrue(packages.contains("q"));
     }
 
-    public void testConcealsWithEmptySet() {
-        Set<String> conceals
-            = new Builder("foo").conceals(Collections.emptySet()).build().conceals();
-        assertTrue(conceals.size() == 0);
+    public void testContainsWithEmptySet() {
+        Set<String> packages = ModuleDescriptor.module("foo")
+                .contains(Collections.emptySet())
+                .build()
+                .packages();
+        assertTrue(packages.size() == 0);
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
-    public void testConcealsWithDuplicate() {
-        new Builder("foo").conceals("p").conceals("p");
+    public void testContainsWithDuplicate() {
+        ModuleDescriptor.module("foo").contains("p").contains("p");
     }
 
     @Test(expectedExceptions = IllegalStateException.class)
-    public void testConcealsWithExportedPackage() {
-        new Builder("foo").exports("p").conceals("p");
+    public void testContainsWithExportedPackage() {
+        ModuleDescriptor.module("foo").exports("p").contains("p");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
-    public void testConcealsWithBadName(String pn, String ignore) {
-        new Builder("foo").conceals(pn);
+    public void testContainsWithBadName(String pn, String ignore) {
+        ModuleDescriptor.module("foo").contains(pn);
     }
 
 
     // packages
 
     public void testPackages() {
-        Set<String> packages
-            = new Builder("foo").exports("p").conceals("q").build().packages();
+        Set<String> packages = ModuleDescriptor.module("foo")
+                .exports("p")
+                .contains("q")
+                .build()
+                .packages();
         assertTrue(packages.size() == 2);
         assertTrue(packages.contains("p"));
         assertTrue(packages.contains("q"));
@@ -462,14 +733,14 @@
     // name
 
     public void testModuleName() {
-        String mn = new Builder("foo").build().name();
+        String mn = ModuleDescriptor.module("foo").build().name();
         assertEquals(mn, "foo");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testBadModuleName(String mn, String ignore) {
-        new Builder(mn);
+        ModuleDescriptor.module(mn);
     }
 
 
@@ -477,67 +748,107 @@
 
     public void testVersion1() {
         Version v1 = Version.parse("1.0");
-        Version v2 = new Builder("foo").version(v1).build().version().get();
+        Version v2 = ModuleDescriptor.module("foo")
+                .version(v1)
+                .build()
+                .version()
+                .get();
         assertEquals(v1, v2);
     }
 
     public void testVersion2() {
         String vs = "1.0";
-        Version v1 = new Builder("foo").version(vs).build().version().get();
+        Version v1 = ModuleDescriptor.module("foo")
+                .version(vs)
+                .build()
+                .version()
+                .get();
         Version v2 = Version.parse(vs);
         assertEquals(v1, v2);
     }
 
     @Test(expectedExceptions = NullPointerException.class )
     public void testNullVersion1() {
-        new Builder("foo").version((Version)null);
+        ModuleDescriptor.module("foo").version((Version) null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class )
     public void testNullVersion2() {
-        new Builder("foo").version((String)null);
+        ModuleDescriptor.module("foo").version((String) null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class )
     public void testEmptyVersion() {
-        new Builder("foo").version("");
-    }
-
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateVersion1() {
-        Version v = Version.parse("2.0");
-        new Builder("foo").version("1.0").version(v);
-    }
-
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateVersion2() {
-        new Builder("foo").version("1.0").version("2.0");
+        ModuleDescriptor.module("foo").version("");
     }
 
 
     // toNameAndVersion
 
     public void testToNameAndVersion() {
-        ModuleDescriptor md1 = new Builder("foo").build();
+        ModuleDescriptor md1 = ModuleDescriptor.module("foo").build();
         assertEquals(md1.toNameAndVersion(), "foo");
 
-        ModuleDescriptor md2 = new Builder("foo").version("1.0").build();
+        ModuleDescriptor md2 = ModuleDescriptor.module("foo").version("1.0").build();
         assertEquals(md2.toNameAndVersion(), "foo@1.0");
     }
 
 
-    // isAutomatic
+    // open modules
+
+    public void testOpenModules() {
+        ModuleDescriptor descriptor = ModuleDescriptor.openModule("m")
+                .requires("java.base")
+                .contains("p")
+                .build();
+        assertTrue(descriptor.isOpen());
+        assertTrue(descriptor.packages().size() == 1);
+        assertTrue(descriptor.packages().contains("p"));
+        assertTrue(descriptor.exports().isEmpty());
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensOnWeakModule1() {
+        ModuleDescriptor.openModule("foo").opens("p");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void testOpensOnWeakModule2() {
+        ModuleDescriptor.openModule("foo").opens("p", Set.of("bar"));
+    }
+
+    public void testIsOpen() {
+        assertFalse(ModuleDescriptor.module("m").build().isOpen());
+        assertFalse(ModuleDescriptor.automaticModule("m").build().isOpen());
+        assertTrue(ModuleDescriptor.openModule("m").build().isOpen());
+    }
+
+
+    // automatic modules
+
     public void testIsAutomatic() {
-        ModuleDescriptor descriptor = new Builder("foo").build();
-        assertFalse(descriptor.isAutomatic());
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build();
+        assertFalse(descriptor1.isAutomatic());
+
+        ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build();
+        assertFalse(descriptor2.isAutomatic());
+
+        ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build();
+        assertTrue(descriptor3.isAutomatic());
     }
 
     // isSynthetic
     public void testIsSynthetic() {
         assertFalse(Object.class.getModule().getDescriptor().isSynthetic());
 
-        ModuleDescriptor descriptor = new Builder("foo").build();
-        assertFalse(descriptor.isSynthetic());
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build();
+        assertFalse(descriptor1.isSynthetic());
+
+        ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build();
+        assertFalse(descriptor2.isSynthetic());
+
+        ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build();
+        assertFalse(descriptor3.isSynthetic());
     }
 
 
@@ -545,92 +856,71 @@
 
     public void testMainClass() {
         String mainClass
-            = new Builder("foo").mainClass("p.Main").build().mainClass().get();
+            = ModuleDescriptor.module("foo").mainClass("p.Main").build().mainClass().get();
         assertEquals(mainClass, "p.Main");
     }
 
     @Test(dataProvider = "invalidjavaidentifiers",
           expectedExceptions = IllegalArgumentException.class )
     public void testMainClassWithBadName(String mainClass, String ignore) {
-        Builder builder = new Builder("foo");
+        Builder builder = ModuleDescriptor.module("foo");
         builder.mainClass(mainClass);
     }
 
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateMainClass() {
-        new Builder("foo").mainClass("p.Main").mainClass("p.Main");
-    }
-
 
     // osName
 
     public void testOsName() {
-        String osName = new Builder("foo").osName("Linux").build().osName().get();
+        String osName = ModuleDescriptor.module("foo").osName("Linux").build().osName().get();
         assertEquals(osName, "Linux");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testNullOsName() {
-        new Builder("foo").osName(null);
+        ModuleDescriptor.module("foo").osName(null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testEmptyOsName() {
-        new Builder("foo").osName("");
-    }
-
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateOsName() {
-        new Builder("foo").osName("Linux").osName("Linux");
+        ModuleDescriptor.module("foo").osName("");
     }
 
 
     // osArch
 
     public void testOsArch() {
-        String osArch = new Builder("foo").osName("arm").build().osName().get();
+        String osArch = ModuleDescriptor.module("foo").osName("arm").build().osName().get();
         assertEquals(osArch, "arm");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testNullOsArch() {
-        new Builder("foo").osArch(null);
+        ModuleDescriptor.module("foo").osArch(null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testEmptyOsArch() {
-        new Builder("foo").osArch("");
-    }
-
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateOsArch() {
-        new Builder("foo").osArch("arm").osArch("arm");
+        ModuleDescriptor.module("foo").osArch("");
     }
 
 
     // osVersion
 
     public void testOsVersion() {
-        String osVersion = new Builder("foo").osName("11.2").build().osName().get();
+        String osVersion = ModuleDescriptor.module("foo").osName("11.2").build().osName().get();
         assertEquals(osVersion, "11.2");
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testNullOsVersion() {
-        new Builder("foo").osVersion(null);
+        ModuleDescriptor.module("foo").osVersion(null);
     }
 
     @Test(expectedExceptions = IllegalArgumentException.class)
     public void testEmptyOsVersion() {
-        new Builder("foo").osVersion("");
+        ModuleDescriptor.module("foo").osVersion("");
     }
 
-    @Test(expectedExceptions = IllegalStateException.class)
-    public void testDuplicateOsVersion() {
-        new Builder("foo").osVersion("11.2").osVersion("11.2");
-    }
-
-
     // reads
 
     private static InputStream EMPTY_INPUT_STREAM = new InputStream() {
@@ -647,7 +937,8 @@
         }
     };
 
-    public void testRead() throws Exception {
+    // basic test reading module-info.class
+    public void testRead1() throws Exception {
         Module base = Object.class.getModule();
 
         try (InputStream in = base.getResourceAsStream("module-info.class")) {
@@ -664,9 +955,80 @@
         }
     }
 
-    public void testReadsWithPackageFinder() {
-        // TBD: Need way to write a module-info.class without a
-        // ConcealedPackages attribute
+    /**
+     * 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
+     */
+    public void testReadsWithPackageFinder() throws Exception {
+        ModuleDescriptor descriptor = ModuleDescriptor.module("foo")
+                .requires("java.base")
+                .build();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ModuleInfoWriter.write(descriptor, baos);
+        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
+
+        descriptor = ModuleDescriptor.read(bb, () -> Set.of("p", "q"));
+
+        assertTrue(descriptor.packages().size() == 2);
+        assertTrue(descriptor.packages().contains("p"));
+        assertTrue(descriptor.packages().contains("q"));
+    }
+
+    /**
+     * Test ModuleDescriptor with a packager finder that doesn't return the
+     * complete set of packages.
+     */
+    @Test(expectedExceptions = InvalidModuleDescriptorException.class)
+    public void testReadsWithBadPackageFinder() throws Exception {
+        ModuleDescriptor descriptor = ModuleDescriptor.module("foo")
+                .requires("java.base")
+                .exports("p")
+                .build();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ModuleInfoWriter.write(descriptor, baos);
+        ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
+
+        // package finder returns a set that doesn't include p
+        ModuleDescriptor.read(bb, () -> Set.of("q"));
     }
 
     @Test(expectedExceptions = InvalidModuleDescriptorException.class)
@@ -689,7 +1051,7 @@
     @Test(expectedExceptions = InvalidModuleDescriptorException.class)
     public void testReadOfJavaBaseWithRequires() {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("java.base")
+            = ModuleDescriptor.module("java.base")
                 .requires("other")
                 .build();
         ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
@@ -699,7 +1061,7 @@
     // The requires table must have an entry for java.base
     @Test(expectedExceptions = InvalidModuleDescriptorException.class)
     public void testReadWithEmptyRequires() {
-        ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1").build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build();
         ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
         ModuleDescriptor.read(bb);
     }
@@ -708,14 +1070,13 @@
     @Test(expectedExceptions = InvalidModuleDescriptorException.class)
     public void testReadWithNoRequiresBase() {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
         ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
         ModuleDescriptor.read(bb);
     }
 
-
     public void testReadWithNull() throws Exception {
         Module base = Object.class.getModule();
 
@@ -751,22 +1112,22 @@
     // equals/hashCode/compareTo/toString
 
     public void testEqualsAndHashCode() {
-        ModuleDescriptor md1 = new Builder("foo").build();
-        ModuleDescriptor md2 = new Builder("foo").build();
+        ModuleDescriptor md1 = ModuleDescriptor.module("foo").build();
+        ModuleDescriptor md2 = ModuleDescriptor.module("foo").build();
         assertEquals(md1, md1);
         assertEquals(md1.hashCode(), md2.hashCode());
     }
 
     public void testCompare() {
-        ModuleDescriptor md1 = new Builder("foo").build();
-        ModuleDescriptor md2 = new Builder("bar").build();
+        ModuleDescriptor md1 = ModuleDescriptor.module("foo").build();
+        ModuleDescriptor md2 = ModuleDescriptor.module("bar").build();
         int n = "foo".compareTo("bar");
         assertTrue(md1.compareTo(md2) == n);
         assertTrue(md2.compareTo(md1) == -n);
     }
 
     public void testToString() {
-        String s = new Builder("m1").requires("m2").exports("p1").build().toString();
+        String s = ModuleDescriptor.module("m1").requires("m2").exports("p1").build().toString();
         assertTrue(s.contains("m1"));
         assertTrue(s.contains("m2"));
         assertTrue(s.contains("p1"));
--- a/jdk/test/java/lang/module/ModuleFinderTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/module/ModuleFinderTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -335,7 +335,7 @@
 
         ModuleFinder finder = ModuleFinder.of(jar);
         Optional<ModuleReference> mref = finder.find("m");
-        assertTrue(mref.isPresent(), "m not found");
+        assertTrue(mref.isPresent(), "m1 not found");
 
         ModuleDescriptor descriptor = mref.get().descriptor();
 
@@ -748,7 +748,7 @@
             vs = mid.substring(i+1);
         }
         ModuleDescriptor.Builder builder
-            = new ModuleDescriptor.Builder(mn).requires("java.base");
+            = ModuleDescriptor.module(mn).requires("java.base");
         if (vs != null)
             builder.version(vs);
         return builder.build();
--- a/jdk/test/java/lang/module/ModuleReferenceTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/module/ModuleReferenceTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -45,10 +45,10 @@
 
     public void testBasic() throws Exception {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("m")
+            = ModuleDescriptor.module("m")
                 .exports("p")
                 .exports("q")
-                .conceals("p.internal")
+                .contains("p.internal")
                 .build();
 
         URI uri = URI.create("module:/m");
@@ -76,7 +76,7 @@
 
     public void testNullLocation() {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("m")
+            = ModuleDescriptor.module("m")
                 .exports("p")
                 .build();
         Supplier<ModuleReader> supplier = makeSupplier();
@@ -86,7 +86,7 @@
 
     @Test(expectedExceptions = { NullPointerException.class })
     public void testNullSupplier() throws Exception {
-        ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m").build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m").build();
         URI location = URI.create("module:/m");
         new ModuleReference(descriptor, location, null);
     }
@@ -94,11 +94,11 @@
 
     public void testEqualsAndHashCode() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .build();
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .exports("p")
                 .build();
 
@@ -121,7 +121,7 @@
 
 
     public void testToString() {
-        ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1").build();
+        ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build();
         URI uri = URI.create("module:/m1");
         Supplier<ModuleReader> supplier = makeSupplier();
         ModuleReference mref = new ModuleReference(descriptor, uri, supplier);
--- a/jdk/test/java/lang/module/MultiReleaseJarTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/module/MultiReleaseJarTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -80,7 +80,7 @@
     public void testBasic() throws Exception {
         String name = "m1";
 
-        ModuleDescriptor descriptor = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .build();
 
@@ -117,12 +117,12 @@
     public void testModuleInfoInVersionedSection() throws Exception {
         String name = "m1";
 
-        ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .build();
 
         // module descriptor for versioned section
-        ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor2 = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .requires("jdk.unsupported")
                 .build();
@@ -188,12 +188,12 @@
     public void testModuleReader() throws Exception {
         String name = "m1";
 
-        ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor1 = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .build();
 
         // module descriptor for versioned section
-        ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder(name)
+        ModuleDescriptor descriptor2 = ModuleDescriptor.module(name)
                 .requires("java.base")
                 .requires("jdk.unsupported")
                 .build();
--- a/jdk/test/java/lang/ref/FinalizerHistogramTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/ref/FinalizerHistogramTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -31,6 +31,7 @@
 /*
  * @test
  * @summary Unit test for FinalizerHistogram
+ * @modules java.base/java.lang.ref:open
  * @run main FinalizerHistogramTest
  */
 
--- a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,8 @@
 /**
  * @test
  * @build ModuleSetAccessibleTest
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/java.lang:open
+ *          java.base/jdk.internal.misc:+open
  * @run testng ModuleSetAccessibleTest
  * @summary Test java.lang.reflect.AccessibleObject with modules
  */
@@ -142,81 +143,6 @@
 
 
     /**
-     * Test that only public members of java.lang.reflect.Module can be make
-     * accessible.
-     */
-    public void testJavaLangReflectModule() throws Exception {
-
-        // non-public constructor
-        Constructor<?> ctor
-            = Module.class.getDeclaredConstructor(ClassLoader.class,
-                                                  ModuleDescriptor.class);
-        AccessibleObject[] ctors = { ctor };
-
-        try {
-            ctor.setAccessible(true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        try {
-            AccessibleObject.setAccessible(ctors, true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        // should succeed
-        ctor.setAccessible(false);
-        AccessibleObject.setAccessible(ctors, false);
-
-
-        // public method
-        Method method = Module.class.getMethod("addReads", Module.class);
-        AccessibleObject[] methods = { method };
-        method.setAccessible(true);
-        AccessibleObject.setAccessible(methods, true);
-        method.setAccessible(false);
-        AccessibleObject.setAccessible(methods, false);
-
-        // non-public method
-        method = Module.class.getDeclaredMethod("implAddReadsNoSync", Module.class);
-        methods[0] = method;
-
-        try {
-            method.setAccessible(true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        try {
-            AccessibleObject.setAccessible(methods, true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        // should succeed
-        method.setAccessible(false);
-        AccessibleObject.setAccessible(methods, false);
-
-
-        // non-public field
-        Field field = Module.class.getDeclaredField("name");
-        AccessibleObject[] fields = { field };
-
-        try {
-            field.setAccessible(true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        try {
-            AccessibleObject.setAccessible(fields, true);
-            assertTrue(false);
-        } catch (InaccessibleObjectException expected) { }
-
-        // should succeed
-        field.setAccessible(false);
-        AccessibleObject.setAccessible(fields, false);
-
-    }
-
-
-    /**
      * Test that the Class constructor cannot be make accessible.
      */
     public void testJavaLangClass() throws Exception {
--- a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -32,12 +32,14 @@
 
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleFinder;
 import java.lang.reflect.Layer;
 import java.lang.reflect.LayerInstantiationException;
 import java.lang.reflect.Module;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -53,7 +55,7 @@
     public void testEmpty() {
         Layer emptyLayer = Layer.empty();
 
-        assertFalse(emptyLayer.parent().isPresent());
+        assertTrue(emptyLayer.parents().isEmpty());
 
         assertTrue(emptyLayer.configuration() == Configuration.empty());
 
@@ -97,8 +99,9 @@
         // findLoader
         assertTrue(bootLayer.findLoader("java.base") == null);
 
-        // parent
-        assertTrue(bootLayer.parent().get() == Layer.empty());
+        // parents
+        assertTrue(bootLayer.parents().size() == 1);
+        assertTrue(bootLayer.parents().get(0) == Layer.empty());
     }
 
 
@@ -107,18 +110,18 @@
      */
     public void testLayerOnEmpty() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .exports("p1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("m3")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .build();
 
         ModuleFinder finder
@@ -178,8 +181,9 @@
             assertTrue(false);
         } catch (IllegalArgumentException ignore) { }
 
-        // parent
-        assertTrue(layer.parent().get() == Layer.empty());
+        // parents
+        assertTrue(layer.parents().size() == 1);
+        assertTrue(layer.parents().get(0) == Layer.empty());
     }
 
 
@@ -188,14 +192,14 @@
      */
     public void testLayerOnBoot() {
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("m2")
                 .requires("java.base")
                 .exports("p1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
+            = ModuleDescriptor.module("m2")
                 .requires("java.base")
                 .build();
 
@@ -241,8 +245,9 @@
         assertTrue(layer.findLoader("m2") == loader);
         assertTrue(layer.findLoader("java.base") == null);
 
-        // parent
-        assertTrue(layer.parent().get() == Layer.boot());
+        // parents
+        assertTrue(layer.parents().size() == 1);
+        assertTrue(layer.parents().get(0) == Layer.boot());
     }
 
 
@@ -250,16 +255,16 @@
      * Exercise Layer defineModules with a configuration of two modules that
      * have the same module-private package.
      */
-    public void testSameConcealedPackage() {
+    public void testPackageContainedInSelfAndOther() {
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
-                .conceals("p")
+                .contains("p")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .conceals("p")
+            = ModuleDescriptor.module("m2")
+                .contains("p")
                 .build();
 
         ModuleFinder finder
@@ -288,22 +293,22 @@
 
         // m1 reads m2, m2 exports p to m1
         ModuleDescriptor descriptor1
-            =  new ModuleDescriptor.Builder("m1")
+            =  ModuleDescriptor.module("m1")
                 .requires("m2")
                 .build();
         ModuleDescriptor descriptor2
-            =  new ModuleDescriptor.Builder("m2")
-                .exports("p", "m1")
+            =  ModuleDescriptor.module("m2")
+                .exports("p", Set.of("m1"))
                 .build();
 
         // m3 reads m4, m4 exports p to m3
         ModuleDescriptor descriptor3
-            =  new ModuleDescriptor.Builder("m3")
+            =  ModuleDescriptor.module("m3")
                 .requires("m4")
                 .build();
         ModuleDescriptor descriptor4
-            =  new ModuleDescriptor.Builder("m4")
-                .exports("p", "m3")
+            =  ModuleDescriptor.module("m4")
+                .exports("p", Set.of("m3"))
                 .build();
 
         ModuleFinder finder
@@ -325,7 +330,7 @@
         map.put("m1", loader1);
         map.put("m2", loader1);
         map.put("m3", loader2);
-        map.put("m3", loader2);
+        map.put("m4", loader2);
         Layer.empty().defineModules(cf, map::get);
 
         // same loader
@@ -338,20 +343,20 @@
 
 
     /**
-     * Exercise Layer defineModules with a configuration that contains a module
-     * that has a concealed package that is the same name as a non-exported
-     * package in a parent layer.
+     * Exercise Layer defineModules with a configuration with a module that
+     * contains a package that is the same name as a non-exported package in
+     * a parent layer.
      */
-    public void testConcealSamePackageAsBootLayer() {
+    public void testContainsSamePackageAsBootLayer() {
 
         // check assumption that java.base contains sun.launcher
         ModuleDescriptor base = Object.class.getModule().getDescriptor();
-        assertTrue(base.conceals().contains("sun.launcher"));
+        assertTrue(base.packages().contains("sun.launcher"));
 
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                .requires("java.base")
-               .conceals("sun.launcher")
+               .contains("sun.launcher")
                .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor);
@@ -370,20 +375,20 @@
      * Test layers with implied readability.
      *
      * The test consists of three configurations:
-     * - Configuration/layer1: m1, m2 requires public m1
+     * - Configuration/layer1: m1, m2 requires transitive m1
      * - Configuration/layer2: m3 requires m1
      */
     public void testImpliedReadabilityWithLayers1() {
 
-        // cf1: m1 and m2, m2 requires public m1
+        // cf1: m1 and m2, m2 requires transitive m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -397,7 +402,7 @@
         // cf2: m3, m3 requires m2
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -408,8 +413,11 @@
         ClassLoader cl2 = new ClassLoader() { };
         Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
 
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == layer1);
+        assertTrue(layer1.parents().size() == 1);
+        assertTrue(layer1.parents().get(0) == Layer.empty());
+
+        assertTrue(layer2.parents().size() == 1);
+        assertTrue(layer2.parents().get(0) == layer1);
 
         Module m1 = layer2.findModule("m1").get();
         Module m2 = layer2.findModule("m2").get();
@@ -442,14 +450,14 @@
      *
      * The test consists of three configurations:
      * - Configuration/layer1: m1
-     * - Configuration/layer2: m2 requires public m3, m3 requires m2
+     * - Configuration/layer2: m2 requires transitive m3, m3 requires m2
      */
     public void testImpliedReadabilityWithLayers2() {
 
         // cf1: m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -460,15 +468,15 @@
         Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
 
 
-        // cf2: m2, m3: m2 requires public m1, m3 requires m2
+        // cf2: m2, m3: m2 requires transitive m1, m3 requires m2
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -479,8 +487,11 @@
         ClassLoader cl2 = new ClassLoader() { };
         Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
 
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == layer1);
+        assertTrue(layer1.parents().size() == 1);
+        assertTrue(layer1.parents().get(0) == Layer.empty());
+
+        assertTrue(layer2.parents().size() == 1);
+        assertTrue(layer2.parents().get(0) == layer1);
 
         Module m1 = layer2.findModule("m1").get();
         Module m2 = layer2.findModule("m2").get();
@@ -509,7 +520,7 @@
      *
      * The test consists of three configurations:
      * - Configuration/layer1: m1
-     * - Configuration/layer2: m2 requires public m1
+     * - Configuration/layer2: m2 requires transitive m1
      * - Configuration/layer3: m3 requires m1
      */
     public void testImpliedReadabilityWithLayers3() {
@@ -517,7 +528,7 @@
         // cf1: m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
@@ -528,11 +539,11 @@
         Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
 
 
-        // cf2: m2 requires public m1
+        // cf2: m2 requires transitive m1
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
@@ -546,7 +557,7 @@
         // cf3: m3 requires m2
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
+            = ModuleDescriptor.module("m3")
                 .requires("m2")
                 .build();
 
@@ -557,9 +568,14 @@
         ClassLoader cl3 = new ClassLoader() { };
         Layer layer3 = layer2.defineModules(cf3, mn -> cl3);
 
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == layer1);
-        assertTrue(layer3.parent().get() == layer2);
+        assertTrue(layer1.parents().size() == 1);
+        assertTrue(layer1.parents().get(0) == Layer.empty());
+
+        assertTrue(layer2.parents().size() == 1);
+        assertTrue(layer2.parents().get(0) == layer1);
+
+        assertTrue(layer3.parents().size() == 1);
+        assertTrue(layer3.parents().get(0) == layer2);
 
         Module m1 = layer3.findModule("m1").get();
         Module m2 = layer3.findModule("m2").get();
@@ -587,20 +603,20 @@
      * Test layers with implied readability.
      *
      * The test consists of two configurations:
-     * - Configuration/layer1: m1, m2 requires public m1
-     * - Configuration/layer2: m3 requires public m2, m4 requires m3
+     * - Configuration/layer1: m1, m2 requires transitive m1
+     * - Configuration/layer2: m3 requires transitive m2, m4 requires m3
      */
     public void testImpliedReadabilityWithLayers4() {
 
-        // cf1: m1, m2 requires public m1
+        // cf1: m1, m2 requires transitive m1
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1")
+            = ModuleDescriptor.module("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
                 .build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
@@ -611,15 +627,15 @@
         Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1);
 
 
-        // cf2: m3 requires public m2, m4 requires m3
+        // cf2: m3 requires transitive m2, m4 requires m3
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3")
-                .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m2")
+            = ModuleDescriptor.module("m3")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2")
                 .build();
 
         ModuleDescriptor descriptor4
-            = new ModuleDescriptor.Builder("m4")
+            = ModuleDescriptor.module("m4")
                 .requires("m3")
                 .build();
 
@@ -631,8 +647,11 @@
         ClassLoader cl2 = new ClassLoader() { };
         Layer layer2 = layer1.defineModules(cf2, mn -> cl2);
 
-        assertTrue(layer1.parent().get() == Layer.empty());
-        assertTrue(layer2.parent().get() == layer1);
+        assertTrue(layer1.parents().size() == 1);
+        assertTrue(layer1.parents().get(0) == Layer.empty());
+
+        assertTrue(layer2.parents().size() == 1);
+        assertTrue(layer2.parents().get(0) == layer1);
 
         Module m1 = layer2.findModule("m1").get();
         Module m2 = layer2.findModule("m2").get();
@@ -675,7 +694,7 @@
     public void testModuleAlreadyDefinedToLoader() {
 
         ModuleDescriptor md
-            = new ModuleDescriptor.Builder("m")
+            = ModuleDescriptor.module("m")
                 .requires("java.base")
                 .build();
 
@@ -704,14 +723,14 @@
     public void testPackageAlreadyInNamedModule() {
 
         ModuleDescriptor md1
-            = new ModuleDescriptor.Builder("m1")
-                .conceals("p")
+            = ModuleDescriptor.module("m1")
+                .contains("p")
                 .requires("java.base")
                 .build();
 
         ModuleDescriptor md2
-            = new ModuleDescriptor.Builder("m2")
-                .conceals("p")
+            = ModuleDescriptor.module("m2")
+                .contains("p")
                 .requires("java.base")
                 .build();
 
@@ -749,8 +768,8 @@
         assertFalse(c.getModule().isNamed());  // in unnamed module
 
         ModuleDescriptor md
-            = new ModuleDescriptor.Builder("m")
-                .conceals(c.getPackageName())
+            = ModuleDescriptor.module("m")
+                .contains(c.getPackageName())
                 .requires("java.base")
                 .build();
 
@@ -768,7 +787,7 @@
      */
     public void testLayerWithJavaBase() {
         ModuleDescriptor descriptor
-            = new ModuleDescriptor.Builder("java.base")
+            = ModuleDescriptor.module("java.base")
                 .exports("java.lang")
                 .build();
 
@@ -782,12 +801,7 @@
         ClassLoader scl = ClassLoader.getSystemClassLoader();
 
         try {
-            Layer.boot().defineModules(cf, loader -> null );
-            assertTrue(false);
-        } catch (LayerInstantiationException e) { }
-
-        try {
-            Layer.boot().defineModules(cf, loader -> new ClassLoader() { });
+            Layer.boot().defineModules(cf, mn -> new ClassLoader() { });
             assertTrue(false);
         } catch (LayerInstantiationException e) { }
 
@@ -804,13 +818,81 @@
 
 
     /**
+     * Attempt to create a Layer with a module containing a "java." package.
+     * This should only be allowed when the module is defined to the platform
+     * class loader.
+     */
+    @Test(enabled = false)
+    public void testLayerWithJavaPackage() {
+        ModuleDescriptor descriptor
+            = ModuleDescriptor.module("foo")
+                .contains("java.foo")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor);
+
+        Configuration cf = Layer.boot()
+                .configuration()
+                .resolveRequires(finder, ModuleFinder.of(), Set.of("foo"));
+        assertTrue(cf.modules().size() == 1);
+
+        ClassLoader pcl = ClassLoader.getPlatformClassLoader();
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        try {
+            Layer.boot().defineModules(cf, mn -> new ClassLoader() { });
+            assertTrue(false);
+        } catch (LayerInstantiationException e) { }
+
+        try {
+            Layer.boot().defineModulesWithOneLoader(cf, scl);
+            assertTrue(false);
+        } catch (LayerInstantiationException e) { }
+
+        try {
+            Layer.boot().defineModulesWithManyLoaders(cf, scl);
+            assertTrue(false);
+        } catch (LayerInstantiationException e) { }
+
+        // create layer with module defined to platform class loader
+        Layer layer = Layer.boot().defineModules(cf, mn -> pcl);
+        Optional<Module> om = layer.findModule("foo");
+        assertTrue(om.isPresent());
+        Module foo = om.get();
+        assertTrue(foo.getClassLoader() == pcl);
+        assertTrue(foo.getPackages().length == 1);
+        assertTrue(foo.getPackages()[0].equals("java.foo"));
+    }
+
+
+    /**
+     * Attempt to create a Layer with a module defined to the boot loader
+     */
+    @Test(expectedExceptions = { LayerInstantiationException.class })
+    public void testLayerWithBootLoader() {
+        ModuleDescriptor descriptor
+            = ModuleDescriptor.module("m1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor);
+
+        Configuration cf = Layer.boot()
+            .configuration()
+            .resolveRequires(finder, ModuleFinder.of(), Set.of("m1"));
+        assertTrue(cf.modules().size() == 1);
+
+        Layer.boot().defineModules(cf, mn -> null );
+    }
+
+
+    /**
      * Parent of configuration != configuration of parent Layer
      */
     @Test(expectedExceptions = { IllegalArgumentException.class })
     public void testIncorrectParent1() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .requires("java.base")
                 .build();
 
@@ -831,7 +913,7 @@
     public void testIncorrectParent2() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1")
+            = ModuleDescriptor.module("m1")
                 .build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
--- a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,6 +30,8 @@
  * @summary Tests for java.lang.reflect.Layer@createWithXXX methods
  */
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
@@ -38,8 +40,10 @@
 import java.lang.reflect.LayerInstantiationException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Module;
+import java.net.URL;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -263,10 +267,10 @@
     public void testOverlappingPackages() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").exports("p").build();
+            = ModuleDescriptor.module("m1").exports("p").build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2").exports("p").build();
+            = ModuleDescriptor.module("m2").exports("p").build();
 
         ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
 
@@ -297,10 +301,10 @@
     public void testSplitDelegation() {
 
         ModuleDescriptor descriptor1
-            = new ModuleDescriptor.Builder("m1").exports("p").build();
+            = ModuleDescriptor.module("m1").exports("p").build();
 
         ModuleDescriptor descriptor2
-            = new ModuleDescriptor.Builder("m2").exports("p").build();
+            = ModuleDescriptor.module("m2").exports("p").build();
 
         ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
 
@@ -312,10 +316,10 @@
         checkLayer(layer1, "m1", "m2");
 
         ModuleDescriptor descriptor3
-            = new ModuleDescriptor.Builder("m3").requires("m1").build();
+            = ModuleDescriptor.module("m3").requires("m1").build();
 
         ModuleDescriptor descriptor4
-            = new ModuleDescriptor.Builder("m4").requires("m2").build();
+            = ModuleDescriptor.module("m4").requires("m2").build();
 
         ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4);
 
@@ -568,6 +572,48 @@
     }
 
 
+    /**
+     * Basic test of resource loading with a class loader created by
+     * Layer.defineModulesWithOneLoader.
+     */
+    public void testResourcesOneLoader() throws Exception {
+        Configuration cf = resolveRequires("m1");
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl);
+        ClassLoader loader = layer.findLoader("m1");
+        testResourceLoading(loader, "p/Main.class");
+    }
+
+    /**
+     * Basic test of resource loading with a class loader created by
+     * Layer.defineModulesWithOneLoader.
+     */
+    public void testResourcesManyLoaders() throws Exception {
+        Configuration cf = resolveRequires("m1");
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl);
+        ClassLoader loader = layer.findLoader("m1");
+        testResourceLoading(loader, "p/Main.class");
+    }
+
+    /**
+     * Test that a resource is located by a class loader.
+     */
+    private void testResourceLoading(ClassLoader loader, String name)
+        throws IOException
+    {
+        URL url = loader.getResource(name);
+        assertNotNull(url);
+
+        try (InputStream in = loader.getResourceAsStream(name)) {
+            assertNotNull(in);
+        }
+
+        Enumeration<URL> urls = loader.getResources(name);
+        assertTrue(urls.hasMoreElements());
+    }
+
+
     // -- supporting methods --
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,196 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @build LayerControllerTest ModuleUtils
+ * @run testng LayerControllerTest
+ * @summary Basic tests for java.lang.reflect.Layer.Controller
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.util.List;
+import java.util.Set;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+@Test
+public class LayerControllerTest {
+
+    /**
+     * Creates a Controller for a module layer containing modules m1 and m2.
+     * Module m1 contains p1, reads java.base, does not export/open any package
+     * Module m2 contains p2, reads java.base, does not export/open any package
+     */
+    private Layer.Controller createTestLayer() {
+        ModuleDescriptor descriptor1
+            = ModuleDescriptor.module("m1")
+                .contains("p1")
+                .requires("java.base")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = ModuleDescriptor.module("m2")
+                .requires("java.base")
+                .contains("p2")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+        Layer bootLayer = Layer.boot();
+
+        Configuration cf = bootLayer.configuration()
+                .resolveRequires(finder, ModuleFinder.of(), Set.of("m1", "m2"));
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer.Controller controller
+                = Layer.defineModulesWithOneLoader(cf, List.of(bootLayer), scl);
+
+        Layer layer = controller.layer();
+
+        assertTrue(layer.modules().size() == 2);
+        assertTrue(layer.findModule("m1").isPresent());
+        assertTrue(layer.findModule("m2").isPresent());
+
+        return controller;
+    }
+
+    /**
+     * Basic test of Layer.Controller to update modules m1 and m2 to read and
+     * open packages to each other.
+     */
+    public void testBasic() {
+        Layer.Controller controller = createTestLayer();
+        Layer layer = controller.layer();
+        Module m1 = layer.findModule("m1").orElseThrow(RuntimeException::new);
+        Module m2 = layer.findModule("m2").orElseThrow(RuntimeException::new);
+
+        assertFalse(m1.canRead(m2));
+        assertFalse(m1.isExported("p1"));
+        assertFalse(m1.isOpen("p1"));
+        assertFalse(m1.isExported("p1", m2));
+        assertFalse(m1.isOpen("p1", m2));
+
+        assertFalse(m2.canRead(m1));
+        assertFalse(m2.isExported("p2"));
+        assertFalse(m2.isOpen("p2"));
+        assertFalse(m2.isExported("p2", m1));
+        assertFalse(m2.isOpen("p2", m1));
+
+        // update m1 to read m2
+        assertTrue(controller.addReads(m1, m2) == controller);
+        assertTrue(m1.canRead(m2));
+        assertFalse(m2.canRead(m1));
+
+        // update m2 to read m1
+        assertTrue(controller.addReads(m2, m1) == controller);
+        assertTrue(m1.canRead(m2));
+        assertTrue(m1.canRead(m1));
+
+        // update m1 to open p1 to m2
+        assertTrue(controller.addOpens(m1, "p1", m2) == controller);
+        assertTrue(m1.isExported("p1", m2));
+        assertTrue(m1.isOpen("p1", m2));
+        assertFalse(m1.isExported("p1"));
+        assertFalse(m1.isOpen("p1"));
+
+        // update m2 to open p2 to m1
+        assertTrue(controller.addOpens(m2, "p2", m1) == controller);
+        assertTrue(m2.isExported("p2", m1));
+        assertTrue(m2.isOpen("p2", m1));
+        assertFalse(m2.isExported("p2"));
+        assertFalse(m2.isOpen("p2"));
+    }
+
+    /**
+     * Test invalid argument handling
+     */
+    public void testBadArguments() {
+        Layer.Controller controller = createTestLayer();
+        Layer layer = controller.layer();
+        Module m1 = layer.findModule("m1").orElseThrow(RuntimeException::new);
+        Module m2 = layer.findModule("m2").orElseThrow(RuntimeException::new);
+        Module base = Object.class.getModule();
+
+        // java.base is not in layer
+        try {
+            controller.addReads(base, m2);
+            assertTrue(false);
+        } catch (IllegalArgumentException expected) { }
+
+        // java.base is not in layer
+        try {
+            controller.addOpens(base, "java.lang", m2);
+            assertTrue(false);
+        } catch (IllegalArgumentException expected) { }
+
+        // m1 does not contain java.lang
+        try {
+            controller.addOpens(m1, "java.lang", m2);
+            assertTrue(false);
+        } catch (IllegalArgumentException expected) { }
+    }
+
+    /**
+     * Test null handling
+     */
+    public void testNulls() {
+        Layer.Controller controller = createTestLayer();
+        Layer layer = controller.layer();
+        Module m1 = layer.findModule("m1").orElseThrow(RuntimeException::new);
+        Module m2 = layer.findModule("m2").orElseThrow(RuntimeException::new);
+        assertTrue(m1 != null);
+        assertTrue(m2 != null);
+
+        try {
+            controller.addReads(null, m2);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            controller.addReads(m1, null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            controller.addOpens(null, "p1", m2);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            controller.addOpens(m1, null, m2);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+
+        try {
+            controller.addOpens(m1, "p1", null);
+            assertTrue(false);
+        } catch (NullPointerException expected) { }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,157 @@
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Module;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import jdk.internal.module.ClassFileAttributes;
+import jdk.internal.org.objectweb.asm.AnnotationVisitor;
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @modules java.base/jdk.internal.org.objectweb.asm
+ *          java.base/jdk.internal.module
+ *          java.xml
+ * @run testng AnnotationsTest
+ * @summary Basic test of annotations on modules
+ */
+
+public class AnnotationsTest {
+
+    /**
+     * Test that there are no annotations on an unnamed module.
+     */
+    @Test
+    public void testUnnamedModule() {
+        Module module = this.getClass().getModule();
+        assertTrue(module.getAnnotations().length == 0);
+    }
+
+    /**
+     * Test loading a module with a RuntimeVisibleAnnotation attribute.
+     * The test copies the module-info.class for java.xml, adds the attribute,
+     * and then loads the updated module.
+     */
+    @Test
+    public void testNamedModule() throws IOException {
+
+        // "deprecate" java.xml
+        Path dir = Files.createTempDirectory("mods");
+        deprecateModule("java.xml", true, "9", dir);
+
+        // "load" the cloned java.xml
+        Module module = loadModule(dir, "java.xml");
+
+        // check the annotation is present
+        assertTrue(module.isAnnotationPresent(Deprecated.class));
+        Deprecated d = module.getAnnotation(Deprecated.class);
+        assertNotNull(d, "@Deprecated not found");
+        assertTrue(d.forRemoval());
+        assertEquals(d.since(), "9");
+        Annotation[] a = module.getAnnotations();
+        assertTrue(a.length == 1);
+        assertTrue(a[0] instanceof Deprecated);
+    }
+
+
+    /**
+     * Copy the module-info.class for the given module, add the
+     * Deprecated annotation, and write the updated module-info.class
+     * to a directory.
+     */
+    static void deprecateModule(String name,
+                                boolean forRemoval,
+                                String since,
+                                Path output) throws IOException {
+        Module module = Layer.boot().findModule(name).orElse(null);
+        assertNotNull(module, name + " not found");
+
+        InputStream in = module.getResourceAsStream("module-info.class");
+        assertNotNull(in, "No module-info.class for " + name);
+
+        try (in) {
+            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                             + ClassWriter.COMPUTE_FRAMES);
+
+            ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, cw) { };
+
+            ClassReader cr = new ClassReader(in);
+
+            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);
+
+            AnnotationVisitor annotationVisitor
+                = cv.visitAnnotation("Ljava/lang/Deprecated;", true);
+            annotationVisitor.visit("forRemoval", forRemoval);
+            annotationVisitor.visit("since", since);
+            annotationVisitor.visitEnd();
+
+            byte[] bytes = cw.toByteArray();
+            Path mi = output.resolve("module-info.class");
+            Files.write(mi, bytes);
+        }
+    }
+
+    /**
+     * Load the module of the given name in the given directory into a
+     * child layer.
+     */
+    static Module loadModule(Path dir, String name) throws IOException {
+        ModuleFinder finder = ModuleFinder.of(dir);
+
+        Layer bootLayer = Layer.boot();
+
+        Configuration cf = bootLayer.configuration()
+                .resolveRequires(finder, ModuleFinder.of(), Set.of(name));
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
+
+        Module module = layer.findModule(name).orElse(null);
+        assertNotNull(module, name + " not loaded");
+        return module;
+    }
+}
--- a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -174,8 +174,24 @@
         // isExported
         assertTrue(base.isExported("java.lang"));
         assertTrue(base.isExported("java.lang", thisModule));
+        assertTrue(base.isExported("java.lang", base));
+        assertFalse(base.isExported("jdk.internal.misc"));
+        assertFalse(base.isExported("jdk.internal.misc", thisModule));
+        assertTrue(base.isExported("jdk.internal.misc", base));
         assertFalse(base.isExported("java.wombat"));
         assertFalse(base.isExported("java.wombat", thisModule));
+        assertFalse(base.isExported("java.wombat", base));
+
+        // isOpen
+        assertFalse(base.isOpen("java.lang"));
+        assertFalse(base.isOpen("java.lang", thisModule));
+        assertTrue(base.isOpen("java.lang", base));
+        assertFalse(base.isOpen("jdk.internal.misc"));
+        assertFalse(base.isOpen("jdk.internal.misc", thisModule));
+        assertTrue(base.isOpen("jdk.internal.misc", base));
+        assertFalse(base.isOpen("java.wombat"));
+        assertFalse(base.isOpen("java.wombat", thisModule));
+        assertFalse(base.isOpen("java.wombat", base));
     }
 
 
--- a/jdk/test/java/lang/reflect/Module/WithSecurityManager.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/Module/WithSecurityManager.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @modules java.logging
+ * @modules jdk.compiler
  * @summary Test java.lang.reflect.Module methods that specify permission checks
  * @run main/othervm -Djava.security.policy=${test.src}/allow.policy WithSecurityManager allow
  * @run main/othervm WithSecurityManager deny
@@ -47,8 +47,8 @@
 public class WithSecurityManager {
 
     // a module that will be loaded into a child layer
-    static final String ANOTHER_MODULE          = "java.logging";
-    static final String ANOTHER_MODULE_RESOURCE = "java/util/logging/Logger.class";
+    static final String ANOTHER_MODULE          = "jdk.compiler";
+    static final String ANOTHER_MODULE_RESOURCE = "com/sun/tools/javac/Main.class";
 
     public static void main(String[] args) throws IOException {
         boolean allow = args[0].equals("allow");
@@ -144,4 +144,4 @@
             throw new RuntimeException();
     }
 
-}
\ No newline at end of file
+}
--- a/jdk/test/java/lang/reflect/Module/access/AccessTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/AccessTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -38,8 +38,8 @@
  * @modules jdk.compiler
  * @build AccessTest CompilerUtils jdk.testlibrary.*
  * @run testng AccessTest
- * @summary Driver for test that checks access to public members in exported
- *          and non-exported packages.
+ * @summary Driver for test that checks access to access to types in
+ *          exported and non-exported packages.
  */
 
 @Test
@@ -74,6 +74,7 @@
         int exitValue
             = executeTestJava("--module-path", MODS_DIR.toString(),
                               "--add-modules", "target",
+                              "-Dsun.reflect.enableStrictMode=true",
                               "-m", "test/test.Main")
                 .outputTo(System.out)
                 .errorTo(System.out)
--- a/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,5 +22,6 @@
  */
 
 module target {
-    exports p;
+    exports p1;
+    exports p2;
 }
--- a/jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +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.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package p;
-
-public class Exported {
-
-    /**
-     * Public constructor
-     */
-    public Exported() { }
-
-    /**
-     * Public field
-     */
-    public static Object field;
-
-    /**
-     * Public method
-     */
-    public static void run() {
-    }
-}
--- a/jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +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.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package p;
-
-import java.lang.reflect.Module;
-
-public class Helper {
-    Helper() { }
-
-    public static void exportPackage(String pn, Module who) {
-        Helper.class.getModule().addExports(pn, who);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Helper.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package p1;
+
+import java.lang.reflect.Module;
+
+/**
+ * Helper class in target module to allow test invoke addExports[Private]
+ */
+
+public class Helper {
+    Helper() { }
+
+    public static void addExports(String pn, Module who) {
+        Helper.class.getModule().addExports(pn, who);
+    }
+
+    public static void addOpens(String pn, Module who) {
+        Helper.class.getModule().addOpens(pn, who);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/p1/Public.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package p1;
+
+public class Public {
+
+    // public constructor
+    public Public() { }
+
+    // non-public constructor
+    private Public(Void ignore) { }
+
+    // public field
+    public static Object f1;
+
+    // non-public field
+    private static Object f2;
+
+    // public method
+    public static void foo() { }
+
+    // non-public method
+    private static void bar() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/p2/NonPublic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package p2;
+
+class NonPublic {
+
+    // public constructor
+    public NonPublic() { }
+
+    // non-public constructor
+    private NonPublic(Void ignore) { }
+
+    // public field
+    public static Object f1;
+
+    // non-public field
+    private static Object f2;
+
+    // public method
+    public static void foo() { }
+
+    // non-public method
+    private static void bar() { }
+}
--- a/jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +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.
- *
- * 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 q;
-
-public class Internal {
-
-    /**
-     * Public constructor
-     */
-    public Internal() { }
-
-    /**
-     * Public field
-     */
-    public static Object field;
-
-    /**
-     * Public method
-     */
-    public static void run() {
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/q1/Public.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package q1;
+
+public class Public {
+
+    // public constructor
+    public Public() { }
+
+    // non-public constructor
+    private Public(Void ignore) { }
+
+    // public field
+    public static Object f1;
+
+    // non-public field
+    private static Object f2;
+
+    // public method
+    public static void foo() { }
+
+    // non-public method
+    private static void bar() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/target/q2/NonPublic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package q2;
+
+class NonPublic {
+
+    // public constructor
+    public NonPublic() { }
+
+    // non-public constructor
+    private NonPublic(Void ignore) { }
+
+    // public field
+    public static Object f1;
+
+    // non-public field
+    private static Object f2;
+
+    // public method
+    public static void foo() { }
+
+    // non-public method
+    private static void bar() { }
+}
--- a/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,166 +23,351 @@
 
 package test;
 
+import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
-import java.lang.reflect.InaccessibleObjectException;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Method;
 import java.lang.reflect.Module;
-import java.util.Optional;
 
 /**
- * Test access to public members in exported and non-exported packages.
+ * Test access to public/non-public members of public/non-public classes in
+ * exported and non-exported packages.
  */
 
 public class Main {
 
     public static void main(String[] args) throws Exception {
+        testPublicClassInExportedPackage();
+        testNonPublicClassInExportedPackage();
+        testPublicClassInNonExportedPackage();
+        testNonPublicClassInNonExportedPackage();
+    }
 
+    static void testPublicClassInExportedPackage() throws Exception {
         Module thisModule = Main.class.getModule();
-        assertTrue(thisModule.isNamed());
+        Module targetModule = getTargetModule();
+
+        assertTrue(targetModule.isExported("p1"));
+        assertTrue(targetModule.isExported("p1", thisModule));
+        assertTrue(targetModule.isExported("p1", targetModule));
+
+        assertFalse(targetModule.isOpen("p1"));
+        assertFalse(targetModule.isOpen("p1", thisModule));
+        assertTrue(targetModule.isOpen("p1", targetModule));
+
+        Class<?> clazz = Class.forName("p1.Public");
+        Constructor<?> ctor1 = clazz.getConstructor();   // public
+        Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class); // non-public
+
+        Field f1 = clazz.getField("f1");    // public
+        Field f2 = clazz.getDeclaredField("f2");    // non-public
+
+        Method m1 = clazz.getMethod("foo");  // public
+        Method m2 = clazz.getDeclaredMethod("bar");  // non-public
 
-        Optional<Module> om = Layer.boot().findModule("target");
-        assertTrue(om.isPresent());
+        tryAccessConstructor(ctor1, true);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, true);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, true);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, false);
+
+        targetAddOpens("p1", thisModule);
 
-        Module target = om.get();
+        tryAccessConstructor(ctor1, true);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, true);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, true);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, true);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, true);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, true);
+    }
+
+    static void testNonPublicClassInExportedPackage() throws Exception {
+        Module thisModule = Main.class.getModule();
+        Module targetModule = getTargetModule();
 
-        assertTrue(target.isExported("p"));
-        assertTrue(target.isExported("p", thisModule));
+        assertTrue(targetModule.isExported("p2"));
+        assertTrue(targetModule.isExported("p2", thisModule));
+        assertTrue(targetModule.isExported("p2", targetModule));
+
+        assertFalse(targetModule.isOpen("p2"));
+        assertFalse(targetModule.isOpen("p2", thisModule));
+        assertTrue(targetModule.isOpen("p1", targetModule));
+
+        Class<?> clazz = Class.forName("p2.NonPublic");
+        Constructor<?> ctor1 = clazz.getConstructor();
+        Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class);
+
+        Field f1 = clazz.getField("f1");    // public
+        Field f2 = clazz.getDeclaredField("f2");    // non-public
+
+        Method m1 = clazz.getMethod("foo");  // public
+        Method m2 = clazz.getDeclaredMethod("bar");  // non-public
+
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
+
+        targetAddExports("p2", thisModule);
 
-        assertFalse(target.isExported("q"));
-        assertFalse(target.isExported("q", thisModule));
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
 
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
+
+        targetAddOpens("p2", thisModule);
 
-        // thisModule does not read the target module
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
 
-        assertFalse(thisModule.canRead(target));
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, true);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, true);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, true);
+    }
+
+    static void testPublicClassInNonExportedPackage() throws Exception {
+        Module thisModule = Main.class.getModule();
+        Module targetModule = getTargetModule();
 
-        tryAccessPublicMembers("p.Exported", true);
-        tryAccessPublicMembers("q.Internal", false);
+        assertFalse(targetModule.isExported("q1"));
+        assertFalse(targetModule.isExported("q1", thisModule));
+        assertTrue(targetModule.isExported("q1", targetModule));
+
+        assertFalse(targetModule.isOpen("q1"));
+        assertFalse(targetModule.isOpen("q1", thisModule));
+        assertTrue(targetModule.isOpen("q1", targetModule));
+
+        Class<?> clazz = Class.forName("q1.Public");
+        Constructor<?> ctor1 = clazz.getConstructor();  // public
+        Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class);  // non-public
+
+        Field f1 = clazz.getField("f1");    // public
+        Field f2 = clazz.getDeclaredField("f2");    // non-public
 
+        Method m1 = clazz.getMethod("foo");  // public
+        Method m2 = clazz.getDeclaredMethod("bar");  // non-public
 
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
 
-        // thisModule reads the target module
+        targetAddExports("q1", thisModule);
+
+        tryAccessConstructor(ctor1, true);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, true);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, true);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, false);
 
-        thisModule.addReads(target);
-        assertTrue(thisModule.canRead(target));
+        targetAddOpens("q1", thisModule);
+
+        tryAccessConstructor(ctor1, true);
+        tryAccessConstructor(ctor1, false);
+        tryAccessMethod(m1, true);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, true);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(ctor2, true);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, true);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, true);
+    }
 
-        tryAccessPublicMembers("p.Exported", true);
-        tryAccessPublicMembers("q.Internal", false);
+    static void testNonPublicClassInNonExportedPackage() throws Exception {
+        Module thisModule = Main.class.getModule();
+        Module targetModule = getTargetModule();
+
+        assertFalse(targetModule.isExported("q2"));
+        assertFalse(targetModule.isExported("q2", thisModule));
+        assertTrue(targetModule.isExported("q2", targetModule));
+
+        assertFalse(targetModule.isOpen("q2"));
+        assertFalse(targetModule.isOpen("q2", thisModule));
+        assertTrue(targetModule.isOpen("q2", targetModule));
 
+        Class<?> clazz = Class.forName("q2.NonPublic");
+        Constructor<?> ctor1 = clazz.getConstructor();  // public
+        Constructor<?> ctor2 = clazz.getDeclaredConstructor(Void.class);  // non-public
 
+        Field f1 = clazz.getField("f1");    // public
+        Field f2 = clazz.getDeclaredField("f2");    // non-public
 
-        // change target module to export its internal package to thisModule
+        Method m1 = clazz.getMethod("foo");  // public
+        Method m2 = clazz.getDeclaredMethod("bar");  // non-public
+
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
 
-        targetAddExports("q", thisModule);
-        assertFalse(target.isExported("q"));
-        assertTrue(target.isExported("q", thisModule));
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
+
+        targetAddExports("q2", thisModule);
+
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
 
-        tryAccessPublicMembers("p.Exported", true);
-        tryAccessPublicMembers("q.Internal", true);
+        trySetAccessible(ctor1, false);
+        trySetAccessible(ctor2, false);
+        trySetAccessible(m1, false);
+        trySetAccessible(m2, false);
+        trySetAccessible(f1, false);
+        trySetAccessible(f2, false);
+
+        targetAddOpens("q2", thisModule);
+
+        tryAccessConstructor(ctor1, false);
+        tryAccessConstructor(ctor2, false);
+        tryAccessMethod(m1, false);
+        tryAccessMethod(m2, false);
+        tryAccessObjectField(f1, false);
+        tryAccessObjectField(f2, false);
+
+        trySetAccessible(ctor1, true);
+        trySetAccessible(m1, true);
+        trySetAccessible(m2, true);
+        trySetAccessible(f1, true);
+        trySetAccessible(f2, true);
     }
 
 
-    /**
-     * Attempt to access public members in a target class.
-     */
-    static void tryAccessPublicMembers(String cn, boolean shouldSucceed)
-        throws Exception
-    {
-
-        Class<?> clazz = Class.forName(cn);
-
-        Module thisModule = Main.class.getModule();
-        Module targetModule = clazz.getModule();
+    static Module getTargetModule() {
+        return Layer.boot().findModule("target").get();
+    }
 
-        // check if the target class is in an exported package
-        String pn = cn.substring(0, cn.lastIndexOf('.'));
-        boolean exported = targetModule.isExported(pn, thisModule);
-        assertTrue(exported == shouldSucceed);
-        boolean shouldFail = !shouldSucceed;
-
-
-        // Class.newInstance
-
-        try {
-            clazz.newInstance();
-            assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
-        }
-
-
-        // Constructor.newInstance and Constructor.setAccessible
-
-        Constructor<?> ctor = clazz.getConstructor();
+    static void tryAccessConstructor(Constructor<?> ctor, boolean shouldSucceed) {
         try {
             ctor.newInstance();
             assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            assertFalse(shouldSucceed);
         }
-        try {
-            ctor.setAccessible(true);
-            assertTrue(shouldSucceed);
-            ctor.newInstance();
-        } catch (InaccessibleObjectException e) {
-            assertTrue(shouldFail);
-        }
+    }
 
-
-        // Method.invoke and Method.setAccessible
-
-        Method m = clazz.getDeclaredMethod("run");
+    static void tryAccessMethod(Method method, boolean shouldSucceed) {
         try {
-            m.invoke(null);
-            assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
-        }
-        try {
-            m.setAccessible(true);
+            method.invoke(null);
             assertTrue(shouldSucceed);
-            m.invoke(null);
-        } catch (InaccessibleObjectException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            e.printStackTrace();
+            assertFalse(shouldSucceed);
         }
+    }
 
-        // Field.get, Field.set and Field.setAccessible
-
-        Field f = clazz.getDeclaredField("field");
+    static void tryAccessObjectField(Field f, boolean shouldSucceed) {
         try {
             f.get(null);
             assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            assertFalse(shouldSucceed);
         }
         try {
-            f.set(null, 100);
+            f.set(null, new Object());
             assertTrue(shouldSucceed);
-        } catch (IllegalAccessException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            assertFalse(shouldSucceed);
         }
+    }
+
+    static void trySetAccessible(AccessibleObject ao, boolean shouldSucceed) {
         try {
-            f.setAccessible(true);
-            f.get(null);
-            f.set(null, 100);
+            ao.setAccessible(true);
             assertTrue(shouldSucceed);
-        } catch (InaccessibleObjectException e) {
-            assertTrue(shouldFail);
+        } catch (Exception e) {
+            assertFalse(shouldSucceed);
         }
-
     }
 
     /**
      * Update target module to export a package to the given module.
      */
     static void targetAddExports(String pn, Module who) throws Exception {
-        Class<?> helper = Class.forName("p.Helper");
-        Method m = helper.getMethod("exportPackage", String.class, Module.class);
+        Class<?> helper = Class.forName("p1.Helper");
+        Method m = helper.getMethod("addExports", String.class, Module.class);
         m.invoke(null, pn, who);
     }
 
+    /**
+     * Update target module to open a package to the given module.
+     */
+    static void targetAddOpens(String pn, Module who) throws Exception {
+        Class<?> helper = Class.forName("p1.Helper");
+        Method m = helper.getMethod("addOpens", String.class, Module.class);
+        m.invoke(null, pn, who);
+    }
 
     static void assertTrue(boolean expr) {
         if (!expr) throw new RuntimeException();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/Basic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,77 @@
+/*
+ * 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
+ * @library src
+ * @build m/* Basic
+ * @run testng/othervm Basic
+ * @summary Basic test for annotations on modules
+ */
+
+import java.lang.reflect.Module;
+import java.util.Arrays;
+
+import p.annotation.Foo;
+import p.annotation.Bar;
+import p.annotation.Baz;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class Basic {
+
+    final Module module = Foo.class.getModule();
+
+    /**
+     * {@code @Foo} does not have RUNTIME retention policy.
+     */
+    @Test
+    public void testInvisibleAnnotation() {
+        assertFalse(module.isAnnotationPresent(Foo.class));
+        assertNull(module.getAnnotation(Foo.class));
+    }
+
+    /**
+     * {@code @Bar} has RUNTIME retention policy and value "bar"
+     */
+    @Test
+    public void testBarAnnotation() {
+        assertTrue(module.isAnnotationPresent(Bar.class));
+        Bar bar = module.getAnnotation(Bar.class);
+        assertNotNull(bar);
+        assertEquals(bar.value(), "bar");
+    }
+
+    /**
+     * {@code @Baz} has RUNTIME retention policy has a repeating value
+     */
+    @Test
+    public void testBazAnnotation() {
+        assertTrue(module.isAnnotationPresent(Baz.class));
+        Baz baz = module.getAnnotation(Baz.class);
+        assertNotNull(baz);
+        String[] expected = { "one", "two", "three" };
+        assertTrue(Arrays.equals(baz.value(), expected));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,31 @@
+/*
+ * 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 p.annotation.*;
+
+@Foo
+@Bar("bar")
+@Baz({"one", "two", "three"})
+module m {
+    exports p.annotation;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Bar.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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 p.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.MODULE;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value={MODULE})
+public @interface Bar {
+   String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Baz.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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 p.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.MODULE;
+
+@Target(value={MODULE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Baz {
+   String[] value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Module/annotation/src/m/p/annotation/Foo.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * 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 p.annotation;
+
+import java.lang.annotation.Target;
+import static java.lang.annotation.ElementType.MODULE;
+
+@Target(value={MODULE})
+public @interface Foo {}
--- a/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,6 +22,6 @@
  */
 
 module m3 {
-    requires public m2;
+    requires transitive m2;
     exports p.three;
 }
--- a/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,7 +23,7 @@
 
 module test {
     requires m1;
-    requires m3;   // requires public m2
+    requires m3;   // requires transitive m2
 
     exports jdk.test;
 }
--- a/jdk/test/java/net/Authenticator/B4933582.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/net/Authenticator/B4933582.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, 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
@@ -21,6 +21,15 @@
  * questions.
  */
 
+/*
+ * @test
+ * @bug 4933582
+ * @library ../../../sun/net/www/httptest
+ * @modules java.base/sun.net.www
+ *          java.base/sun.net.www.protocol.http
+ * @build HttpCallback HttpTransaction TestHttpServer B4933582
+ * @run main/othervm B4933582
+ */
 import java.io.*;
 import java.net.*;
 import java.util.*;
@@ -44,7 +53,7 @@
         req.orderlyClose();
     }
 
-    static boolean firstTime = true;
+    static volatile boolean firstTime = true;
 
     public void request (HttpTransaction req) {
         try {
@@ -114,43 +123,67 @@
         URL url = new URL (u);
         System.out.println ("client opening connection to: " + u);
         URLConnection urlc = url.openConnection ();
-        InputStream is = urlc.getInputStream ();
-        read (is);
-        is.close();
+        try(InputStream is = urlc.getInputStream ()) {
+            read (is);
+        }
     }
 
     static TestHttpServer server;
 
     public static void main (String[] args) throws Exception {
-        firstTime = args[0].equals ("first");
         MyAuthenticator auth = new MyAuthenticator ();
         Authenticator.setDefault (auth);
         CacheImpl cache;
         try {
-            if (firstTime) {
-                server = new TestHttpServer (new B4933582(), 1, 10, 0);
-                cache = new CacheImpl (server.getLocalPort());
-            } else {
-                cache = new CacheImpl ();
-                server = new TestHttpServer(new B4933582(), 1, 10, cache.getPort());
-            }
+            server = new TestHttpServer (new B4933582(), 1, 10, 0);
+            cache = new CacheImpl (server.getLocalPort());
             AuthCacheValue.setAuthCache (cache);
-            System.out.println ("Server: listening on port: " + server.getLocalPort());
             client ("http://localhost:"+server.getLocalPort()+"/d1/foo.html");
-        } catch (Exception e) {
+        } finally {
             if (server != null) {
                 server.terminate();
             }
-            throw e;
         }
+
         int f = auth.getCount();
-        if (firstTime && f != 1) {
-            except ("Authenticator was called "+f+" times. Should be 1");
+        if (f != 1) {
+            except("Authenticator was called " + f + " times. Should be 1");
         }
-        if (!firstTime && f != 0) {
-            except ("Authenticator was called "+f+" times. Should be 0");
+
+        firstTime = false;
+
+        int retries = 0;
+        cache = new CacheImpl();
+        while (true) {
+            try {
+                server = new TestHttpServer(new B4933582(), 1, 10,
+                        cache.getPort());
+                break;
+            } catch (BindException e) {
+                if (retries++ < 5) {
+                    Thread.sleep(200L);
+                    System.out.println("BindException \"" + e.getMessage()
+                            + "\", retrying...");
+                    continue;
+                } else {
+                    throw e;
+                }
+            }
         }
-        server.terminate();
+
+        try {
+            AuthCacheValue.setAuthCache(cache);
+            client("http://localhost:" + server.getLocalPort() + "/d1/foo.html");
+        } finally {
+            if (server != null) {
+                server.terminate();
+            }
+        }
+
+        f = auth.getCount();
+        if (f != 1) {
+            except("Authenticator was called " + f + " times. Should be 1");
+        }
     }
 
     public static void except (String s) {
@@ -163,7 +196,7 @@
             super ();
         }
 
-        int count = 0;
+        volatile int count = 0;
 
         public PasswordAuthentication getPasswordAuthentication () {
             PasswordAuthentication pw;
@@ -178,7 +211,7 @@
     }
 
     static class CacheImpl extends AuthCacheImpl {
-        HashMap map;
+        HashMap<String,LinkedList<AuthCacheValue>> map;
         int port; // need to store the port number the server is using
 
         CacheImpl () throws IOException {
@@ -190,20 +223,18 @@
             this.port = port;
             File src = new File ("cache.ser");
             if (src.exists()) {
-                ObjectInputStream is = new ObjectInputStream (
-                    new FileInputStream (src)
-                );
-                try {
-                    map = (HashMap)is.readObject ();
+                try (ObjectInputStream is = new ObjectInputStream(
+                        new FileInputStream(src))) {
+                    map = (HashMap<String,LinkedList<AuthCacheValue>>)is
+                              .readObject();
                     this.port = (Integer)is.readObject ();
                     System.out.println ("read port from file " + port);
                 } catch (ClassNotFoundException e) {
                     assert false;
                 }
-                is.close();
                 System.out.println ("setMap from cache.ser");
             } else {
-                map = new HashMap();
+                map = new HashMap<>();
             }
             setMap (map);
         }
@@ -213,20 +244,22 @@
         }
 
         private void writeMap () {
+            File dst = new File("cache.ser");
             try {
-                File dst = new File ("cache.ser");
                 dst.delete();
                 if (!dst.createNewFile()) {
                     return;
                 }
-                ObjectOutputStream os = new ObjectOutputStream (
-                        new FileOutputStream (dst)
-                );
+            } catch (IOException e) {
+            }
+
+            try (ObjectOutputStream os = new ObjectOutputStream(
+                    new FileOutputStream(dst))) {
                 os.writeObject(map);
                 os.writeObject(port);
-                System.out.println ("wrote port " + port);
-                os.close();
-            } catch (IOException e) {}
+                System.out.println("wrote port " + port);
+            } catch (IOException e) {
+            }
         }
 
         public void put (String pkey, AuthCacheValue value) {
--- a/jdk/test/java/net/Authenticator/B4933582.sh	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-#
-# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# @test
-# @bug 4933582
-
-OS=`uname -s`
-case "$OS" in
-  SunOS | Linux | Darwin | AIX )
-    PS=":"
-    FS="/"
-    ;;
-  CYGWIN* )
-    PS=";"
-    FS="/"
-    ;;
-  Windows* )
-    PS=";"
-    FS="\\"
-    ;;
-  * )
-    echo "Unrecognized system!"
-    exit 1;
-    ;;
-esac
-
-EXTRAOPTS="--add-exports java.base/sun.net.www=ALL-UNNAMED --add-exports java.base/sun.net.www.protocol.http=ALL-UNNAMED"
-export EXTRAOPTS
-
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . \
-    -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest" ${TESTSRC}${FS}B4933582.java
-rm -f cache.ser auth.save
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 first
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 second
--- a/jdk/test/java/net/InterfaceAddress/Equals.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/net/InterfaceAddress/Equals.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,7 @@
 
 /* @test
  * @bug 6628576
+ * @modules java.base/java.net:open
  * @summary InterfaceAddress.equals() NPE when broadcast field == null
  */
 
--- a/jdk/test/java/nio/Buffer/Basic.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/nio/Buffer/Basic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,7 +27,8 @@
  *      4526177 4463011 4660660 4661219 4663521 4782970 4804304 4938424 6231529
  *      6221101 6234263 6535542 6591971 6593946 6795561 7190219 7199551 8065556
  *      8149469
- * @modules java.base/jdk.internal.misc
+ * @modules java.base/java.nio:open
+ *          java.base/jdk.internal.misc
  * @author Mark Reinhold
  */
 
--- a/jdk/test/java/nio/channels/Selector/TemporarySelector.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/nio/channels/Selector/TemporarySelector.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,7 +23,7 @@
 
 /* @test
  * @bug 6645197
- * @run main/othervm -Xmx5m TemporarySelector
+ * @run main/othervm -Xmx16m TemporarySelector
  * @summary Timed read with socket adaptor throws ClosedSelectorException if temporary selector GC'ed.
  */
 import java.io.IOException;
--- a/jdk/test/java/nio/channels/Selector/Wakeup.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/nio/channels/Selector/Wakeup.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -24,14 +24,14 @@
 /* @test
  * @bug 6405995
  * @summary Unit test for selector wakeup and interruption
- * @library ..
+ * @library .. /lib/testlibrary/
  */
 
 import java.io.*;
 import java.net.*;
 import java.nio.*;
 import java.nio.channels.*;
-import java.util.Random;
+import java.util.concurrent.CyclicBarrier;
 
 public class Wakeup {
 
@@ -44,91 +44,112 @@
     }
 
     static class Sleeper extends TestThread {
+        private static final long TIMEOUT = jdk.testlibrary.Utils.adjustTimeout(20_000);
+
+        // barrier is used to synchronize sleeper thread and checking
+        // thread which is the main thread: when go() get to the end,
+        // then start checking the sleeper's status.
+        private static CyclicBarrier barrier = new CyclicBarrier(2);
+        private static int wakeups = 0;
+        private static int waits = 0;
+
+        volatile boolean interruptBeforeSelect = false;
         volatile boolean started = false;
-        volatile int entries = 0;
-        volatile int wakeups = 0;
         volatile boolean wantInterrupt = false;
-        volatile boolean gotInterrupt = false;
-        volatile Exception exception = null;
         volatile boolean closed = false;
         Object gate = new Object();
 
         Selector sel;
 
-        Sleeper(Selector sel) {
+        Sleeper(Selector sel, boolean wantInterrupt, boolean interruptBeforeSelect) {
             super("Sleeper", System.err);
             this.sel = sel;
+            this.wantInterrupt = wantInterrupt;
+            this.interruptBeforeSelect = interruptBeforeSelect;
         }
 
         public void go() throws Exception {
             started = true;
-            for (;;) {
+            if (interruptBeforeSelect) {
                 synchronized (gate) { }
-                entries++;
-                try {
-                    sel.select();
-                } catch (ClosedSelectorException x) {
-                    closed = true;
+            }
+            wakeups++;
+            System.err.println("Wakeup, selecting, " + wakeups);
+            try {
+                sel.select();
+            } catch (ClosedSelectorException x) {
+                closed = true;
+            }
+            boolean intr = Thread.currentThread().isInterrupted();
+            System.err.println("Wakeup " + wakeups
+                               + (closed ? " (closed)" : "")
+                               + (intr ? " (intr)" : ""));
+            if (closed)
+                return;
+            if (wantInterrupt) {
+                while (!Thread.interrupted())
+                    Thread.yield();
+            }
+            System.err.println("Wakeup, waiting, " + wakeups);
+            barrier.await();
+            System.err.println("Wakeup, wait successfully, " + wakeups);
+        }
+
+        void check(boolean close) throws Exception {
+            waits++;
+            System.err.println("waiting sleeper, " + waits);
+            if (!close) {
+                barrier.await();
+                System.err.println("wait barrier successfully, " + waits);
+            }
+            if (finish(TIMEOUT) == 0)
+                throw new Exception("Test failed");
+            if (this.closed != close)
+                throw new Exception("Selector was closed");
+        }
+
+        void check() throws Exception {
+            check(false);
+        }
+
+        static Sleeper createSleeper(Selector sel, boolean wantInterrupt,
+                boolean interruptBeforeSelect) throws Exception {
+            if (!wantInterrupt && interruptBeforeSelect) {
+                throw new RuntimeException("Wrong parameters!");
+            }
+
+            Sleeper sleeper = new Sleeper(sel, wantInterrupt, interruptBeforeSelect);
+
+            if (interruptBeforeSelect) {
+                synchronized(sleeper.gate) {
+                    sleeper.start();
+                    while (!sleeper.started)
+                        sleep(50);
+                    sleeper.interrupt();
                 }
-                boolean intr = Thread.currentThread().isInterrupted();
-                wakeups++;
-                System.err.println("Wakeup " + wakeups
-                                   + (closed ? " (closed)" : "")
-                                   + (intr ? " (intr)" : ""));
-                if (wakeups > 1000)
-                    throw new Exception("Too many wakeups");
-                if (closed)
-                    return;
+            } else {
+                sleeper.start();
+                while (!sleeper.started)
+                    sleep(50);
                 if (wantInterrupt) {
-                    while (!Thread.interrupted())
-                        Thread.yield();
-                    gotInterrupt = true;
-                    wantInterrupt = false;
+                    sleep(50);
+                    sleeper.interrupt();
                 }
             }
+            return sleeper;
         }
-
     }
 
-    private static int checkedWakeups = 0;
+    static Sleeper newSleeper(Selector sel) throws Exception {
+        return Sleeper.createSleeper(sel, false, false);
+    }
 
-    private static void check(Sleeper sleeper, boolean intr)
-        throws Exception
-    {
-        checkedWakeups++;
-        if (sleeper.wakeups > checkedWakeups) {
-            sleeper.finish(100);
-            throw new Exception("Sleeper has run ahead");
-        }
-        int n = 0;
-        while (sleeper.wakeups < checkedWakeups) {
-            sleep(50);
-            if ((n += 50) > 1000) {
-                sleeper.finish(100);
-                throw new Exception("Sleeper appears to be dead ("
-                                    + checkedWakeups + ")");
-            }
-        }
-        if (sleeper.wakeups > checkedWakeups) {
-            sleeper.finish(100);
-            throw new Exception("Too many wakeups: Expected "
-                                + checkedWakeups
-                                + ", got " + sleeper.wakeups);
-        }
-        if (intr) {
-            n = 0;
-            // Interrupts can sometimes be delayed, so wait
-            while (!sleeper.gotInterrupt) {
-                sleep(50);
-                if ((n += 50) > 1000) {
-                    sleeper.finish(100);
-                    throw new Exception("Interrupt never delivered");
-                }
-            }
-            sleeper.gotInterrupt = false;
-        }
-        System.err.println("Check " + checkedWakeups
-                           + (intr ? " (intr " + n + ")" : ""));
+    static Sleeper newSleeperWantInterrupt(Selector sel) throws Exception {
+        return Sleeper.createSleeper(sel, true, false);
+    }
+
+    static Sleeper newSleeperWantInterruptBeforeSelect(Selector sel) throws Exception {
+        return Sleeper.createSleeper(sel, true, true);
     }
 
     public static void main(String[] args) throws Exception {
@@ -138,60 +159,37 @@
         // Wakeup before select
         sel.wakeup();
 
-        Sleeper sleeper = new Sleeper(sel);
-
-        sleeper.start();
-        while (!sleeper.started)
-            sleep(50);
-
-        check(sleeper, false);          // 1
+        Sleeper sleeper = newSleeper(sel); // 1
+        sleeper.check();
 
         for (int i = 2; i < 5; i++) {
             // Wakeup during select
+            sleeper = newSleeper(sel);
             sel.wakeup();
-            check(sleeper, false);      // 2 .. 4
+            sleeper.check();         // 2 .. 4
         }
 
         // Double wakeup
-        synchronized (sleeper.gate) {
-            sel.wakeup();
-            check(sleeper, false);      // 5
-            sel.wakeup();
-            sel.wakeup();
-        }
-        check(sleeper, false);          // 6
+        sel.wakeup();
+        sel.wakeup();
+        sleeper = newSleeper(sel);
+        sleeper.check();            // 5
 
         // Interrupt
-        synchronized (sleeper.gate) {
-            sleeper.wantInterrupt = true;
-            sleeper.interrupt();
-            check(sleeper, true);       // 7
-        }
+        sleeper = newSleeperWantInterrupt(sel);
+        sleeper.check();            // 6
 
         // Interrupt before select
-        while (sleeper.entries < 8)
-            Thread.yield();
-        synchronized (sleeper.gate) {
-            sel.wakeup();
-            check(sleeper, false);      // 8
-            sleeper.wantInterrupt = true;
-            sleeper.interrupt();
-            sleep(50);
-        }
-        check(sleeper, true);           // 9
+        sleeper = newSleeperWantInterruptBeforeSelect(sel);
+        sleeper.check();            // 7
 
         // Close during select
-        while (sleeper.entries < 10)
-            Thread.yield();
-        synchronized (sleeper.gate) {
-            sel.close();
-            check(sleeper, false);      // 10
-        }
+        sleeper = newSleeper(sel);
+        sel.close();
+        sleeper.check();           // 8
 
-        if (sleeper.finish(200) == 0)
-            throw new Exception("Test failed");
-        if (!sleeper.closed)
-            throw new Exception("Selector not closed");
+        sleeper = newSleeper(sel);
+        sleeper.check(true);
     }
 
 }
--- a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh	Thu Dec 01 21:39:49 2016 +0000
@@ -109,7 +109,8 @@
 
 go() {
     echo ''
-    sh -xc "$JAVA ${TESTVMOPTS} --add-exports java.base/sun.nio.ch=ALL-UNNAMED $DFLAG \
+    sh -xc "$JAVA ${TESTVMOPTS} --add-opens java.base/java.io=ALL-UNNAMED \
+            --add-opens java.base/sun.nio.ch=ALL-UNNAMED $DFLAG \
         $1 $2 $3 $4 $5 $6 $7 $8" 2>&1
     if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
 }
--- a/jdk/test/java/nio/file/etc/Exceptions.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/nio/file/etc/Exceptions.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,7 @@
 
 /* @test
  * @bug 4313887 6881498
+ * @modules java.base/java.lang:open
  * @summary Miscellenous tests on exceptions in java.nio.file
  */
 
--- a/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/rmi/activation/Activatable/checkActivateRef/CheckActivateRef.java	Thu Dec 01 21:39:49 2016 +0000
@@ -37,7 +37,7 @@
  *
  * @library ../../../testlibrary
  * @modules java.rmi/sun.rmi.registry
- *          java.rmi/sun.rmi.server
+ *          java.rmi/sun.rmi.server:+open
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
  *          java.base/sun.nio.ch
--- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,9 +93,8 @@
             obj = new CallbackImpl();
             Callback proxy =
                 (Callback) UnicastRemoteObject.exportObject(obj, 0);
-            Registry registry =
-                LocateRegistry.createRegistry(
-                    TestLibrary.INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT);
+            Registry registry = TestLibrary.createRegistryOnEphemeralPort();
+            int registryPort = TestLibrary.getRegistryPort(registry);
             registry.bind("Callback", proxy);
 
             /*
@@ -107,7 +106,8 @@
                                    TestLibrary.INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT);
             rmid.addOptions(
                 "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED",
-                "-Djava.nio.channels.spi.SelectorProvider=InheritedChannelNotServerSocket$SP");
+                "-Djava.nio.channels.spi.SelectorProvider=InheritedChannelNotServerSocket$SP",
+                "-Dtest.java.rmi.rmidViaInheritedChannel.registry.port=" + registryPort);
             rmid.start();
 
             /*
@@ -181,8 +181,9 @@
                  */
                 try {
                     System.err.println("notify test...");
-                    Registry registry =
-                        LocateRegistry.getRegistry(TestLibrary.INHERITEDCHANNELNOTSERVERSOCKET_REGISTRY_PORT);
+                    int registryPort = Integer.getInteger(
+                            "test.java.rmi.rmidViaInheritedChannel.registry.port", 0);
+                    Registry registry = LocateRegistry.getRegistry(registryPort);
                     Callback obj = (Callback) registry.lookup("Callback");
                     obj.notifyTest();
                 } catch (NotBoundException nbe) {
--- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,226 +0,0 @@
-/*
- * Copyright (c) 2003, 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.
- *
- * 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 4295885 6824141
- * @summary rmid should be startable from inetd
- * @author Ann Wollrath
- *
- * @library ../../testlibrary
- * @modules java.base/sun.nio.ch
- *          java.rmi/sun.rmi.registry
- *          java.rmi/sun.rmi.server
- *          java.rmi/sun.rmi.transport
- *          java.rmi/sun.rmi.transport.tcp
- * @build TestLibrary RMID ActivationLibrary
- * @run main/othervm/timeout=240 RmidViaInheritedChannel
- * @key intermittent
- */
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.ServerSocket;
-import java.net.ProtocolFamily;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
-import java.rmi.Remote;
-import java.rmi.NotBoundException;
-import java.rmi.activation.ActivationGroup;
-import java.rmi.activation.ActivationSystem;
-import java.rmi.registry.LocateRegistry;
-import java.rmi.registry.Registry;
-import java.rmi.server.UnicastRemoteObject;
-import static java.net.StandardSocketOptions.SO_REUSEADDR;
-import static java.net.StandardSocketOptions.SO_REUSEPORT;
-
-public class RmidViaInheritedChannel implements Callback {
-    private static final Object lock = new Object();
-    private static boolean notified = false;
-
-    private RmidViaInheritedChannel() {}
-
-    public void notifyTest() {
-        synchronized (lock) {
-            notified = true;
-            System.err.println("notification received.");
-            lock.notifyAll();
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        System.setProperty("java.rmi.activation.port",
-                           Integer.toString(TestLibrary.RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT));
-        RMID rmid = null;
-        Callback obj = null;
-
-        try {
-            /*
-             * Export callback object and bind in registry.
-             */
-            System.err.println("export callback object and bind in registry");
-            obj = new RmidViaInheritedChannel();
-            Callback proxy = (Callback)
-                UnicastRemoteObject.exportObject(obj, 0);
-            Registry registry =
-                LocateRegistry.createRegistry(
-                    TestLibrary.RMIDVIAINHERITEDCHANNEL_REGISTRY_PORT);
-            registry.bind("Callback", proxy);
-
-            /*
-             * Start rmid.
-             */
-            System.err.println("start rmid with inherited channel");
-            RMID.removeLog();
-            rmid = RMID.createRMID(System.out, System.err, true, false,
-                                   TestLibrary.RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT);
-            rmid.addOptions(
-                "--add-exports=java.base/sun.nio.ch=ALL-UNNAMED",
-                "-Djava.nio.channels.spi.SelectorProvider=RmidViaInheritedChannel$RmidSelectorProvider");
-            if (System.getProperty("os.name").startsWith("Windows") &&
-                System.getProperty("os.version").startsWith("5."))
-            {
-                /* Windows XP/2003 or older
-                 * Need to expand ephemeral range to include RMI test ports
-                 */
-                rmid.addOptions(new String[]{
-                    "-Djdk.net.ephemeralPortRange.low=1024",
-                    "-Djdk.net.ephemeralPortRange.high=64000"
-                });
-            }
-            rmid.start();
-
-            /*
-             * Get activation system and wait to be notified via callback
-             * from rmid's selector provider.
-             */
-            System.err.println("get activation system");
-            ActivationSystem system = ActivationGroup.getSystem();
-            System.err.println("ActivationSystem = " + system);
-            synchronized (lock) {
-                while (!notified) {
-                    lock.wait();
-                }
-            }
-            System.err.println("TEST PASSED");
-
-        } finally {
-            if (obj != null) {
-                UnicastRemoteObject.unexportObject(obj, true);
-            }
-            if (rmid != null) {
-                rmid.cleanup();
-            }
-        }
-    }
-
-    public static class RmidSelectorProvider extends SelectorProvider {
-
-        private final SelectorProvider provider;
-        private ServerSocketChannel channel = null;
-
-        public RmidSelectorProvider() {
-            provider =  sun.nio.ch.DefaultSelectorProvider.create();
-        }
-
-        public DatagramChannel openDatagramChannel()
-            throws IOException
-        {
-            return provider.openDatagramChannel();
-        }
-
-        public DatagramChannel openDatagramChannel(ProtocolFamily family)
-            throws IOException
-        {
-            return provider.openDatagramChannel(family);
-        }
-
-        public Pipe openPipe()
-            throws IOException
-        {
-            return provider.openPipe();
-        }
-
-        public AbstractSelector openSelector()
-            throws IOException
-        {
-            return provider.openSelector();
-        }
-
-        public ServerSocketChannel openServerSocketChannel()
-            throws IOException
-        {
-            return provider.openServerSocketChannel();
-        }
-
-        public SocketChannel openSocketChannel()
-             throws IOException
-        {
-            return provider.openSocketChannel();
-        }
-
-        public synchronized Channel inheritedChannel() throws IOException {
-            System.err.println("RmidSelectorProvider.inheritedChannel");
-            if (channel == null) {
-                /*
-                 * Create server socket channel and bind server socket.
-                 */
-                channel = ServerSocketChannel.open();
-                ServerSocket serverSocket = channel.socket();
-
-                // Enable SO_REUSEADDR before binding
-                serverSocket.setOption(SO_REUSEADDR, true);
-
-                // Enable SO_REUSEPORT, if supported, before binding
-                if (serverSocket.supportedOptions().contains(SO_REUSEPORT)) {
-                    serverSocket.setOption(SO_REUSEPORT, true);
-                }
-
-                serverSocket.bind(
-                     new InetSocketAddress(InetAddress.getLocalHost(),
-                     TestLibrary.RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT));
-                System.err.println("serverSocket = " + serverSocket);
-
-                /*
-                 * Notify test that inherited channel was created.
-                 */
-                try {
-                    System.err.println("notify test...");
-                    Registry registry =
-                        LocateRegistry.getRegistry(TestLibrary.RMIDVIAINHERITEDCHANNEL_REGISTRY_PORT);
-                    Callback obj = (Callback) registry.lookup("Callback");
-                    obj.notifyTest();
-                } catch (NotBoundException nbe) {
-                    throw (IOException)
-                        new IOException("callback object not bound").
-                            initCause(nbe);
-                }
-            }
-            return channel;
-        }
-    }
-}
-
-interface Callback extends Remote {
-    void notifyTest() throws IOException;
-}
--- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/rmid.security.policy	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/rmid.security.policy	Thu Dec 01 21:39:49 2016 +0000
@@ -3,4 +3,5 @@
     permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
     permission java.net.SocketPermission "*", "connect,accept";
     permission java.util.PropertyPermission "java.rmi.activation.port", "write";
+    permission java.util.PropertyPermission "test.java.rmi.rmidViaInheritedChannel.registry.port", "read";
 };
--- a/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,7 +30,7 @@
  * rather than pinning it indefinitely.
  * @author Peter Jones
  *
- * @modules java.rmi/sun.rmi.transport
+ * @modules java.rmi/sun.rmi.transport:+open
  * @build DGCAckFailure DGCAckFailure_Stub
  * @run main/othervm DGCAckFailure
  */
--- a/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/rmi/server/RMIClassLoader/useCodebaseOnlyDefault/UseCodebaseOnlyDefault.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,7 +27,7 @@
  * @summary Tests proper parsing and defaulting of the
  * "java.rmi.server.useCodebaseOnly" property.
  *
- * @modules java.rmi/sun.rmi.server
+ * @modules java.rmi/sun.rmi.server:+open
  * @run main/othervm UseCodebaseOnlyDefault true
  * @run main/othervm -Djava.rmi.server.useCodebaseOnly=xyzzy UseCodebaseOnlyDefault true
  * @run main/othervm -Djava.rmi.server.useCodebaseOnly UseCodebaseOnlyDefault true
--- a/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/rmi/server/getRemoteClass/GetRemoteClass.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,7 +29,7 @@
  *
  * @library ../../testlibrary
  * @modules java.rmi/sun.rmi.registry
- *          java.rmi/sun.rmi.server
+ *          java.rmi/sun.rmi.server:+open
  *          java.rmi/sun.rmi.transport
  *          java.rmi/sun.rmi.transport.tcp
  * @build TestLibrary
--- a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java	Thu Dec 01 21:39:49 2016 +0000
@@ -77,7 +77,7 @@
                 TestParams.defaultPolicy +
                 " --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED" +
                 " --add-exports java.rmi/sun.rmi.server=ALL-UNNAMED" +
-                " --add-exports java.rmi/sun.rmi.transport=ALL-UNNAMED" +
+                " --add-opens java.rmi/sun.rmi.transport=ALL-UNNAMED" +
                 " --add-exports java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" +
                 " -Djava.rmi.dgc.leaseValue=500000" +
                 "  -Dsun.rmi.dgc.checkInterval=" +
--- a/jdk/test/java/security/SecureRandom/ApiTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/security/SecureRandom/ApiTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -195,10 +195,10 @@
             case "AES-128":
             case "AES-192":
             case "AES-256":
-                int algoStrength = Integer.parseInt(alg.replaceAll("AES-", ""));
-                int maxStrengthSupported = Cipher.getMaxAllowedKeyLength("AES");
-                if (strength > maxStrengthSupported
-                        || algoStrength > maxStrengthSupported) {
+                int algoStrength = Integer.parseInt(alg.substring("AES-".length()));
+                int maxAESStrength = Cipher.getMaxAllowedKeyLength("AES");
+                if (strength > algoStrength
+                        || algoStrength > maxAESStrength) {
                     error = false;
                 }
                 break;
--- a/jdk/test/java/security/modules/ModularTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/security/modules/ModularTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -164,7 +164,7 @@
         final Builder builder;
         if (moduleType == MODULE_TYPE.EXPLICIT) {
             System.out.format(" %nGenerating ModuleDescriptor object");
-            builder = new Builder(moduleName).exports(pkg);
+            builder = ModuleDescriptor.module(moduleName).exports(pkg);
             if (isService && serviceInterface != null && serviceImpl != null) {
                 builder.provides(serviceInterface, serviceImpl);
             } else {
--- a/jdk/test/java/security/testlibrary/Proc.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/security/testlibrary/Proc.java	Thu Dec 01 21:39:49 2016 +0000
@@ -257,7 +257,8 @@
 
         if (hasModules) {
             Stream.of(jdk.internal.misc.VM.getRuntimeArguments())
-                    .filter(arg -> arg.startsWith("--add-exports="))
+                    .filter(arg -> arg.startsWith("--add-exports=") ||
+                                   arg.startsWith("--add-opens="))
                     .forEach(cmd::add);
         }
 
--- a/jdk/test/java/time/TEST.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/time/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -4,3 +4,4 @@
 modules = jdk.localedata
 lib.dirs = ../../lib/testlibrary
 lib.build = jdk.testlibrary.RandomFactory
+modules = java.base/java.time:open java.base/java.time.chrono:open java.base/java.time.zone:open
--- a/jdk/test/java/util/ArrayList/ArrayManagement.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/ArrayList/ArrayManagement.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8146568
  * @summary brittle white box test of internal array management
+ * @modules java.base/java.util:open
  * @run testng ArrayManagement
  */
 
--- a/jdk/test/java/util/ArrayList/IteratorMicroBenchmark.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/ArrayList/IteratorMicroBenchmark.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,21 +22,36 @@
  */
 
 /*
- * This is not a regression test, but a micro-benchmark.
- * Be patient; this runs for half an hour!
+ * @test
+ * @summary micro-benchmark correctness mode
+ * @run main IteratorMicroBenchmark iterations=1 size=8 warmup=0
+ */
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Spliterator;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+/**
+ * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
  *
- * I have run this as follows:
- *
- * for f in -client -server; do mergeBench dolphin . jr -dsa -da $f IteratorMicroBenchmark.java; done
- *
+ * To run this in micro-benchmark mode, simply run as a normal java program.
+ * Be patient; this program runs for a very long time.
+ * For faster runs, restrict execution using command line args.
  *
  * @author Martin Buchholz
  */
-
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.regex.Pattern;
-
 public class IteratorMicroBenchmark {
     abstract static class Job {
         private final String name;
@@ -45,17 +60,28 @@
         public abstract void work() throws Throwable;
     }
 
-    private static void collectAllGarbage() {
-        final java.util.concurrent.CountDownLatch drained
-            = new java.util.concurrent.CountDownLatch(1);
+    static double warmupSeconds;
+    static long warmupNanos;
+
+    // --------------- GC finalization infrastructure ---------------
+
+    /** No guarantees, but effective in practice. */
+    static void forceFullGc() {
+        CountDownLatch finalizeDone = new CountDownLatch(1);
+        WeakReference<?> ref = new WeakReference<Object>(new Object() {
+            protected void finalize() { finalizeDone.countDown(); }});
         try {
-            System.gc();        // enqueue finalizable objects
-            new Object() { protected void finalize() {
-                drained.countDown(); }};
-            System.gc();        // enqueue detector
-            drained.await();    // wait for finalizer queue to drain
-            System.gc();        // cleanup finalized objects
-        } catch (InterruptedException e) { throw new Error(e); }
+            for (int i = 0; i < 10; i++) {
+                System.gc();
+                if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
+                    System.runFinalization(); // try to pick up stragglers
+                    return;
+                }
+            }
+        } catch (InterruptedException unexpected) {
+            throw new AssertionError("unexpected InterruptedException");
+        }
+        throw new AssertionError("failed to do a \"full\" gc");
     }
 
     /**
@@ -65,23 +91,22 @@
      * Returns array of average times per job per run.
      */
     private static long[] time0(Job ... jobs) throws Throwable {
-        final long warmupNanos = 10L * 1000L * 1000L * 1000L;
         long[] nanoss = new long[jobs.length];
         for (int i = 0; i < jobs.length; i++) {
-            collectAllGarbage();
-            long t0 = System.nanoTime();
-            long t;
-            int j = 0;
-            do { jobs[i].work(); j++; }
-            while ((t = System.nanoTime() - t0) < warmupNanos);
-            nanoss[i] = t/j;
+            if (warmupNanos > 0) forceFullGc();
+            Job job = jobs[i];
+            long totalTime;
+            int runs = 0;
+            long startTime = System.nanoTime();
+            do { job.work(); runs++; }
+            while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
+            nanoss[i] = totalTime/runs;
         }
         return nanoss;
     }
 
     private static void time(Job ... jobs) throws Throwable {
-
-        long[] warmup = time0(jobs); // Warm up run
+        if (warmupSeconds > 0.0) time0(jobs); // Warm up run
         long[] nanoss = time0(jobs); // Real timing run
         long[] milliss = new long[jobs.length];
         double[] ratios = new double[jobs.length];
@@ -126,12 +151,17 @@
 
     private static int intArg(String[] args, String keyword, int defaultValue) {
         String val = keywordValue(args, keyword);
-        return val == null ? defaultValue : Integer.parseInt(val);
+        return (val == null) ? defaultValue : Integer.parseInt(val);
+    }
+
+    private static double doubleArg(String[] args, String keyword, double defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Double.parseDouble(val);
     }
 
     private static Pattern patternArg(String[] args, String keyword) {
         String val = keywordValue(args, keyword);
-        return val == null ? null : Pattern.compile(val);
+        return (val == null) ? null : Pattern.compile(val);
     }
 
     private static Job[] filter(Pattern filter, Job[] jobs) {
@@ -166,26 +196,33 @@
                     public void remove()     {        it.remove(); }};}};
     }
 
-    /**
-     * Usage: [iterations=N] [size=N] [filter=REGEXP]
-     */
     public static void main(String[] args) throws Throwable {
-        final int iterations = intArg(args, "iterations", 100000);
+        final int iterations = intArg(args, "iterations", 100_000);
         final int size       = intArg(args, "size", 1000);
+        warmupSeconds        = doubleArg(args, "warmup", 7.0);
         final Pattern filter = patternArg(args, "filter");
 
+        warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
+
+//         System.out.printf(
+//             "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
+//             iterations, size, warmupSeconds, filter);
+
         final ConcurrentSkipListMap<Integer,Integer> m
             = new ConcurrentSkipListMap<Integer,Integer>();
-        final Vector<Integer> v = new Vector<Integer>(size);
         final ArrayList<Integer> al = new ArrayList<Integer>(size);
 
         // Populate collections with random data
-        final Random rnd = new Random();
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
         for (int i = 0; i < size; i++) {
             m.put(rnd.nextInt(size), rnd.nextInt(size));
-            v.add(rnd.nextInt(size));
+            al.add(rnd.nextInt(size));
         }
-        al.addAll(v);
+        final Vector<Integer> v = new Vector<Integer>(al);
+        final ArrayDeque<Integer> ad = new ArrayDeque<Integer>(al);
+        // shuffle ArrayDeque elements so they wrap
+        for (int i = 0, n = rnd.nextInt(size); i < n; i++)
+            ad.addLast(ad.removeFirst());
 
         // Also test "short" collections
         final int shortSize = 5;
@@ -222,6 +259,15 @@
                         for (int j = 0; j < size; ++j)
                             sum += a[j];
                         check.sum(sum);}}},
+            new Job("descending array loop") {
+                public void work() throws Throwable {
+                    Integer[] a = al.toArray(new Integer[0]);
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        int size = a.length;
+                        for (int j = size - 1; j >= 0; j--)
+                            sum += a[j];
+                        check.sum(sum);}}},
             new Job("Vector get loop") {
                 public void work() throws Throwable {
                     for (int i = 0; i < iterations; i++) {
@@ -334,6 +380,13 @@
                         for (Integer n : al)
                             sum += n;
                         check.sum(sum);}}},
+            new Job("ArrayDeque iterate for loop") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        for (Integer n : ad)
+                            sum += n;
+                        check.sum(sum);}}},
             new Job("ArrayList descending listIterator loop") {
                 public void work() throws Throwable {
                     for (int i = 0; i < iterations; i++) {
@@ -350,6 +403,137 @@
                         while (it.hasNext())
                             sum += it.next();
                         check.sum(sum);}}},
+            new Job("ArrayDeque.descendingIterator() loop") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        Iterator<Integer> it = ad.descendingIterator();
+                        while (it.hasNext())
+                            sum += it.next();
+                        check.sum(sum);}}},
+            new Job("ArrayList.forEach") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.forEach(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.forEach") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.forEach(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("Vector.forEach") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.forEach(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.iterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.iterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.descendingIterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.descendingIterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.iterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.iterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("Vector.iterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.iterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.spliterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.spliterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.spliterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.spliterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("Vector.spliterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.spliterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.spliterator().tryAdvance()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        Spliterator<Integer> spliterator = al.spliterator();
+                        do {} while (spliterator.tryAdvance(n -> sum[0] += n));
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.spliterator().tryAdvance()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        Spliterator<Integer> spliterator = ad.spliterator();
+                        do {} while (spliterator.tryAdvance(n -> sum[0] += n));
+                        check.sum(sum[0]);}}},
+            new Job("Vector.spliterator().tryAdvance()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        Spliterator<Integer> spliterator = v.spliterator();
+                        do {} while (spliterator.tryAdvance(n -> sum[0] += n));
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
+            new Job("Vector.removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList subList .removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    List<Integer> sl = asSubList(al);
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        sl.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
             new Job("ArrayList subList get loop") {
                 public void work() throws Throwable {
                     List<Integer> sl = asSubList(al);
@@ -442,7 +626,61 @@
                         int sum = 0;
                         for (Map.Entry<Integer,Integer> e : m.entrySet())
                             sum += e.getKey();
-                        deoptimize(sum);}}}
+                        deoptimize(sum);}}},
+            new Job("ArrayList.toArray()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Object o : al.toArray())
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("ArrayList.toArray(a)") {
+                public void work() throws Throwable {
+                    Integer[] a = new Integer[size];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        al.toArray(a);
+                        for (Object o : a)
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.toArray()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Object o : ad.toArray())
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("ArrayDeque.toArray(a)") {
+                public void work() throws Throwable {
+                    Integer[] a = new Integer[size];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        ad.toArray(a);
+                        for (Object o : a)
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("Vector.toArray()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Object o : v.toArray())
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job("Vector.toArray(a)") {
+                public void work() throws Throwable {
+                    Integer[] a = new Integer[size];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        v.toArray(a);
+                        for (Object o : a)
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
         };
 
         time(filter(filter, jobs));
--- a/jdk/test/java/util/Calendar/StampOverflow.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/Calendar/StampOverflow.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 4404619 6348819
  * @summary Make sure that Calendar doesn't cause nextStamp overflow.
+ * @modules java.base/java.util:open
  */
 
 import java.lang.reflect.*;
--- a/jdk/test/java/util/Collection/CollectionDefaults.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/Collection/CollectionDefaults.java	Thu Dec 01 21:39:49 2016 +0000
@@ -60,9 +60,19 @@
     public static final Predicate<Integer> pEven = x -> 0 == x % 2;
     public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
 
+    private static final int SIZE = 100;
+
     private static final List<Function<Collection<Integer>, Collection<Integer>>> TEST_SUPPLIERS = Arrays.asList(
             // Collection
             ExtendsAbstractCollection<Integer>::new,
+            java.util.ArrayDeque<Integer>::new,
+            java.util.concurrent.ConcurrentLinkedDeque<Integer>::new,
+            java.util.concurrent.ConcurrentLinkedQueue<Integer>::new,
+            java.util.concurrent.LinkedBlockingDeque<Integer>::new,
+            java.util.concurrent.LinkedBlockingQueue<Integer>::new,
+            java.util.concurrent.LinkedTransferQueue<Integer>::new,
+            (coll) -> new java.util.concurrent.ArrayBlockingQueue<Integer>(
+                3 * SIZE, false, coll),
 
             // Lists
             java.util.ArrayList<Integer>::new,
@@ -80,8 +90,6 @@
             ExtendsAbstractSet<Integer>::new
        );
 
-    private static final int SIZE = 100;
-
     @DataProvider(name="setProvider", parallel=true)
     public static Iterator<Object[]> setCases() {
         final List<Object[]> cases = new LinkedList<>();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/IteratorMicroBenchmark.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2007, 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
+ * @summary micro-benchmark correctness mode
+ * @run main IteratorMicroBenchmark iterations=1 size=8 warmup=0
+ */
+
+import static java.util.stream.Collectors.summingInt;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Spliterator;
+import java.util.Vector;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+/**
+ * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
+ *
+ * To run this in micro-benchmark mode, simply run as a normal java program.
+ * Be patient; this program runs for a very long time.
+ * For faster runs, restrict execution using command line args.
+ *
+ * This is an interface based version of ArrayList/IteratorMicroBenchmark
+ *
+ * @author Martin Buchholz
+ */
+public class IteratorMicroBenchmark {
+    abstract static class Job {
+        private final String name;
+        public Job(String name) { this.name = name; }
+        public String name() { return name; }
+        public abstract void work() throws Throwable;
+    }
+
+    final int iterations;
+    final int size;             // number of elements in collections
+    final double warmupSeconds;
+    final long warmupNanos;
+    final Pattern filter;       // select subset of Jobs to run
+    final boolean reverse;      // reverse order of Jobs
+    final boolean shuffle;      // randomize order of Jobs
+
+    IteratorMicroBenchmark(String[] args) {
+        iterations    = intArg(args, "iterations", 10_000);
+        size          = intArg(args, "size", 1000);
+        warmupSeconds = doubleArg(args, "warmup", 7.0);
+        filter        = patternArg(args, "filter");
+        reverse       = booleanArg(args, "reverse");
+        shuffle       = booleanArg(args, "shuffle");
+
+        warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
+    }
+
+    // --------------- GC finalization infrastructure ---------------
+
+    /** No guarantees, but effective in practice. */
+    static void forceFullGc() {
+        CountDownLatch finalizeDone = new CountDownLatch(1);
+        WeakReference<?> ref = new WeakReference<Object>(new Object() {
+            protected void finalize() { finalizeDone.countDown(); }});
+        try {
+            for (int i = 0; i < 10; i++) {
+                System.gc();
+                if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
+                    System.runFinalization(); // try to pick up stragglers
+                    return;
+                }
+            }
+        } catch (InterruptedException unexpected) {
+            throw new AssertionError("unexpected InterruptedException");
+        }
+        throw new AssertionError("failed to do a \"full\" gc");
+    }
+
+    /**
+     * Runs each job for long enough that all the runtime compilers
+     * have had plenty of time to warm up, i.e. get around to
+     * compiling everything worth compiling.
+     * Returns array of average times per job per run.
+     */
+    long[] time0(List<Job> jobs) throws Throwable {
+        final int size = jobs.size();
+        long[] nanoss = new long[size];
+        for (int i = 0; i < size; i++) {
+            if (warmupNanos > 0) forceFullGc();
+            Job job = jobs.get(i);
+            long totalTime;
+            int runs = 0;
+            long startTime = System.nanoTime();
+            do { job.work(); runs++; }
+            while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
+            nanoss[i] = totalTime/runs;
+        }
+        return nanoss;
+    }
+
+    void time(List<Job> jobs) throws Throwable {
+        if (warmupNanos > 0) time0(jobs); // Warm up run
+        final int size = jobs.size();
+        final long[] nanoss = time0(jobs); // Real timing run
+        final long[] milliss = new long[size];
+        final double[] ratios = new double[size];
+
+        final String nameHeader   = "Method";
+        final String millisHeader = "Millis";
+        final String ratioHeader  = "Ratio";
+
+        int nameWidth   = nameHeader.length();
+        int millisWidth = millisHeader.length();
+        int ratioWidth  = ratioHeader.length();
+
+        for (int i = 0; i < size; i++) {
+            nameWidth = Math.max(nameWidth, jobs.get(i).name().length());
+
+            milliss[i] = nanoss[i]/(1000L * 1000L);
+            millisWidth = Math.max(millisWidth,
+                                   String.format("%d", milliss[i]).length());
+
+            ratios[i] = (double) nanoss[i] / (double) nanoss[0];
+            ratioWidth = Math.max(ratioWidth,
+                                  String.format("%.3f", ratios[i]).length());
+        }
+
+        String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
+                                      nameWidth, millisWidth, ratioWidth);
+        String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
+                                            nameWidth, millisWidth, ratioWidth);
+        System.out.printf(headerFormat, "Method", "Millis", "Ratio");
+
+        // Print out absolute and relative times, calibrated against first job
+        for (int i = 0; i < size; i++)
+            System.out.printf(format, jobs.get(i).name(), milliss[i], ratios[i]);
+    }
+
+    private static String keywordValue(String[] args, String keyword) {
+        for (String arg : args)
+            if (arg.startsWith(keyword))
+                return arg.substring(keyword.length() + 1);
+        return null;
+    }
+
+    private static int intArg(String[] args, String keyword, int defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Integer.parseInt(val);
+    }
+
+    private static double doubleArg(String[] args, String keyword, double defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Double.parseDouble(val);
+    }
+
+    private static Pattern patternArg(String[] args, String keyword) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? null : Pattern.compile(val);
+    }
+
+    private static boolean booleanArg(String[] args, String keyword) {
+        String val = keywordValue(args, keyword);
+        if (val == null || val.equals("false")) return false;
+        if (val.equals("true")) return true;
+        throw new IllegalArgumentException(val);
+    }
+
+    private static List<Job> filter(Pattern filter, List<Job> jobs) {
+        if (filter == null) return jobs;
+        ArrayList<Job> newJobs = new ArrayList<>();
+        for (Job job : jobs)
+            if (filter.matcher(job.name()).find())
+                newJobs.add(job);
+        return newJobs;
+    }
+
+    private static void deoptimize(int sum) {
+        if (sum == 42)
+            System.out.println("the answer");
+    }
+
+    private static <T> List<T> asSubList(List<T> list) {
+        return list.subList(0, list.size());
+    }
+
+    private static <T> Iterable<T> backwards(final List<T> list) {
+        return new Iterable<T>() {
+            public Iterator<T> iterator() {
+                return new Iterator<T>() {
+                    final ListIterator<T> it = list.listIterator(list.size());
+                    public boolean hasNext() { return it.hasPrevious(); }
+                    public T next()          { return it.previous(); }
+                    public void remove()     {        it.remove(); }};}};
+    }
+
+    // Checks for correctness *and* prevents loop optimizations
+    class Check {
+        private int sum;
+        public void sum(int sum) {
+            if (this.sum == 0)
+                this.sum = sum;
+            if (this.sum != sum)
+                throw new AssertionError("Sum mismatch");
+        }
+    }
+    volatile Check check = new Check();
+
+    public static void main(String[] args) throws Throwable {
+        new IteratorMicroBenchmark(args).run();
+    }
+
+    void run() throws Throwable {
+//         System.out.printf(
+//             "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
+//             iterations, size, warmupSeconds, filter);
+
+        final ArrayList<Integer> al = new ArrayList<Integer>(size);
+
+        // Populate collections with random data
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        for (int i = 0; i < size; i++)
+            al.add(rnd.nextInt(size));
+
+        final ArrayDeque<Integer> ad = new ArrayDeque<>(al);
+        final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<>(al.size());
+        abq.addAll(al);
+
+        // shuffle circular array elements so they wrap
+        for (int i = 0, n = rnd.nextInt(size); i < n; i++) {
+            ad.addLast(ad.removeFirst());
+            abq.add(abq.remove());
+        }
+
+        ArrayList<Job> jobs = new ArrayList<>(Arrays.asList());
+
+        List.of(al, ad, abq,
+                new LinkedList<>(al),
+                new PriorityQueue<>(al),
+                new Vector<>(al),
+                new ConcurrentLinkedQueue<>(al),
+                new ConcurrentLinkedDeque<>(al),
+                new LinkedBlockingQueue<>(al),
+                new LinkedBlockingDeque<>(al),
+                new LinkedTransferQueue<>(al),
+                new PriorityBlockingQueue<>(al))
+            .stream()
+            .forEach(x -> {
+                         jobs.addAll(collectionJobs(x));
+                         if (x instanceof Deque)
+                             jobs.addAll(dequeJobs((Deque<Integer>)x));
+                     });
+
+        if (reverse) Collections.reverse(jobs);
+        if (shuffle) Collections.shuffle(jobs);
+
+        time(filter(filter, jobs));
+    }
+
+    List<Job> collectionJobs(Collection<Integer> x) {
+        String klazz = x.getClass().getSimpleName();
+        return List.of(
+            new Job(klazz + " iterate for loop") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        for (Integer n : x)
+                            sum += n;
+                        check.sum(sum);}}},
+            new Job(klazz + " .iterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.iterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .spliterator().tryAdvance()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        Spliterator<Integer> spliterator = x.spliterator();
+                        do {} while (spliterator.tryAdvance(n -> sum[0] += n));
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .spliterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.spliterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .removeIf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.removeIf(n -> { sum[0] += n; return false; });
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .forEach") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.forEach(n -> sum[0] += n);
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .toArray()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Object o : x.toArray())
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .toArray(a)") {
+                public void work() throws Throwable {
+                    Integer[] a = new Integer[x.size()];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.toArray(a);
+                        for (Object o : a)
+                            sum[0] += (Integer) o;
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .toArray(empty)") {
+                public void work() throws Throwable {
+                    Integer[] empty = new Integer[0];
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        for (Integer o : x.toArray(empty))
+                            sum[0] += o;
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " .stream().collect") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        check.sum(x.stream()
+                                  .collect(summingInt(e -> e)));}}},
+            new Job(klazz + " .parallelStream().collect") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        check.sum(x.parallelStream()
+                                  .collect(summingInt(e -> e)));}}});
+    }
+
+    List<Job> dequeJobs(Deque<Integer> x) {
+        String klazz = x.getClass().getSimpleName();
+        return List.of(
+            new Job(klazz + " .descendingIterator() loop") {
+                public void work() throws Throwable {
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        Iterator<Integer> it = x.descendingIterator();
+                        while (it.hasNext())
+                            sum += it.next();
+                        check.sum(sum);}}},
+            new Job(klazz + " .descendingIterator().forEachRemaining()") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.descendingIterator().forEachRemaining(n -> sum[0] += n);
+                        check.sum(sum[0]);}}});
+    }
+}
--- a/jdk/test/java/util/Collection/MOAT.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/Collection/MOAT.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
  *          4802647 7123424 8024709
  * @summary Run many tests on many Collection and Map implementations
  * @author  Martin Buchholz
+ * @modules java.base/java.util:open
  * @run main MOAT
  * @key randomness
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/RemoveMicroBenchmark.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2007, 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
+ * @summary micro-benchmark correctness mode
+ * @run main RemoveMicroBenchmark iterations=1 size=8 warmup=0
+ */
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Vector;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentLinkedDeque;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+import java.util.function.Supplier;
+
+/**
+ * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
+ *
+ * To run this in micro-benchmark mode, simply run as a normal java program.
+ * Be patient; this program runs for a very long time.
+ * For faster runs, restrict execution using command line args.
+ *
+ * @author Martin Buchholz
+ */
+public class RemoveMicroBenchmark {
+    abstract static class Job {
+        private final String name;
+        public Job(String name) { this.name = name; }
+        public String name() { return name; }
+        public abstract void work() throws Throwable;
+    }
+
+    final int iterations;
+    final int size;             // number of elements in collections
+    final double warmupSeconds;
+    final long warmupNanos;
+    final Pattern filter;       // select subset of Jobs to run
+    final boolean reverse;      // reverse order of Jobs
+    final boolean shuffle;      // randomize order of Jobs
+
+    RemoveMicroBenchmark(String[] args) {
+        iterations    = intArg(args, "iterations", 10_000);
+        size          = intArg(args, "size", 1000);
+        warmupSeconds = doubleArg(args, "warmup", 7.0);
+        filter        = patternArg(args, "filter");
+        reverse       = booleanArg(args, "reverse");
+        shuffle       = booleanArg(args, "shuffle");
+
+        warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
+    }
+
+    // --------------- GC finalization infrastructure ---------------
+
+    /** No guarantees, but effective in practice. */
+    static void forceFullGc() {
+        CountDownLatch finalizeDone = new CountDownLatch(1);
+        WeakReference<?> ref = new WeakReference<Object>(new Object() {
+            protected void finalize() { finalizeDone.countDown(); }});
+        try {
+            for (int i = 0; i < 10; i++) {
+                System.gc();
+                if (finalizeDone.await(1L, TimeUnit.SECONDS) && ref.get() == null) {
+                    System.runFinalization(); // try to pick up stragglers
+                    return;
+                }
+            }
+        } catch (InterruptedException unexpected) {
+            throw new AssertionError("unexpected InterruptedException");
+        }
+        throw new AssertionError("failed to do a \"full\" gc");
+    }
+
+    /**
+     * Runs each job for long enough that all the runtime compilers
+     * have had plenty of time to warm up, i.e. get around to
+     * compiling everything worth compiling.
+     * Returns array of average times per job per run.
+     */
+    long[] time0(List<Job> jobs) throws Throwable {
+        final int size = jobs.size();
+        long[] nanoss = new long[size];
+        for (int i = 0; i < size; i++) {
+            if (warmupNanos > 0) forceFullGc();
+            Job job = jobs.get(i);
+            long totalTime;
+            int runs = 0;
+            long startTime = System.nanoTime();
+            do { job.work(); runs++; }
+            while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
+            nanoss[i] = totalTime/runs;
+        }
+        return nanoss;
+    }
+
+    void time(List<Job> jobs) throws Throwable {
+        if (warmupNanos > 0) time0(jobs); // Warm up run
+        final int size = jobs.size();
+        final long[] nanoss = time0(jobs); // Real timing run
+        final long[] milliss = new long[size];
+        final double[] ratios = new double[size];
+
+        final String nameHeader   = "Method";
+        final String millisHeader = "Millis";
+        final String ratioHeader  = "Ratio";
+
+        int nameWidth   = nameHeader.length();
+        int millisWidth = millisHeader.length();
+        int ratioWidth  = ratioHeader.length();
+
+        for (int i = 0; i < size; i++) {
+            nameWidth = Math.max(nameWidth, jobs.get(i).name().length());
+
+            milliss[i] = nanoss[i]/(1000L * 1000L);
+            millisWidth = Math.max(millisWidth,
+                                   String.format("%d", milliss[i]).length());
+
+            ratios[i] = (double) nanoss[i] / (double) nanoss[0];
+            ratioWidth = Math.max(ratioWidth,
+                                  String.format("%.3f", ratios[i]).length());
+        }
+
+        String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
+                                      nameWidth, millisWidth, ratioWidth);
+        String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
+                                            nameWidth, millisWidth, ratioWidth);
+        System.out.printf(headerFormat, "Method", "Millis", "Ratio");
+
+        // Print out absolute and relative times, calibrated against first job
+        for (int i = 0; i < size; i++)
+            System.out.printf(format, jobs.get(i).name(), milliss[i], ratios[i]);
+    }
+
+    private static String keywordValue(String[] args, String keyword) {
+        for (String arg : args)
+            if (arg.startsWith(keyword))
+                return arg.substring(keyword.length() + 1);
+        return null;
+    }
+
+    private static int intArg(String[] args, String keyword, int defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Integer.parseInt(val);
+    }
+
+    private static double doubleArg(String[] args, String keyword, double defaultValue) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? defaultValue : Double.parseDouble(val);
+    }
+
+    private static Pattern patternArg(String[] args, String keyword) {
+        String val = keywordValue(args, keyword);
+        return (val == null) ? null : Pattern.compile(val);
+    }
+
+    private static boolean booleanArg(String[] args, String keyword) {
+        String val = keywordValue(args, keyword);
+        if (val == null || val.equals("false")) return false;
+        if (val.equals("true")) return true;
+        throw new IllegalArgumentException(val);
+    }
+
+    private static List<Job> filter(Pattern filter, List<Job> jobs) {
+        if (filter == null) return jobs;
+        ArrayList<Job> newJobs = new ArrayList<>();
+        for (Job job : jobs)
+            if (filter.matcher(job.name()).find())
+                newJobs.add(job);
+        return newJobs;
+    }
+
+    private static void deoptimize(int sum) {
+        if (sum == 42)
+            System.out.println("the answer");
+    }
+
+    private static <T> List<T> asSubList(List<T> list) {
+        return list.subList(0, list.size());
+    }
+
+    private static <T> Iterable<T> backwards(final List<T> list) {
+        return new Iterable<T>() {
+            public Iterator<T> iterator() {
+                return new Iterator<T>() {
+                    final ListIterator<T> it = list.listIterator(list.size());
+                    public boolean hasNext() { return it.hasPrevious(); }
+                    public T next()          { return it.previous(); }
+                    public void remove()     {        it.remove(); }};}};
+    }
+
+    // Checks for correctness *and* prevents loop optimizations
+    class Check {
+        private int sum;
+        public void sum(int sum) {
+            if (this.sum == 0)
+                this.sum = sum;
+            if (this.sum != sum)
+                throw new AssertionError("Sum mismatch");
+        }
+    }
+    volatile Check check = new Check();
+
+    public static void main(String[] args) throws Throwable {
+        new RemoveMicroBenchmark(args).run();
+    }
+
+    void run() throws Throwable {
+//         System.out.printf(
+//             "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
+//             iterations, size, warmupSeconds, filter);
+
+        final ArrayList<Integer> al = new ArrayList<Integer>(size);
+
+        // Populate collections with random data
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        for (int i = 0; i < size; i++)
+            al.add(rnd.nextInt(size));
+
+        ArrayList<Job> jobs = new ArrayList<>();
+
+        List.<Collection<Integer>>of(
+            new ArrayList<>(),
+            new LinkedList<>(),
+            new Vector<>(),
+            new ArrayDeque<>(),
+            new PriorityQueue<>(),
+            new ArrayBlockingQueue<>(al.size()),
+            new ConcurrentLinkedQueue<>(),
+            new ConcurrentLinkedDeque<>(),
+            new LinkedBlockingQueue<>(),
+            new LinkedBlockingDeque<>(),
+            new LinkedTransferQueue<>(),
+            new PriorityBlockingQueue<>())
+            .stream().forEach(
+                x -> {
+                    String klazz = x.getClass().getSimpleName();
+                    jobs.addAll(collectionJobs(klazz, () -> x, al));
+                    if (x instanceof Queue) {
+                        Queue<Integer> queue = (Queue<Integer>) x;
+                        jobs.addAll(queueJobs(klazz, () -> queue, al));
+                    }
+                    if (x instanceof Deque) {
+                        Deque<Integer> deque = (Deque<Integer>) x;
+                        jobs.addAll(dequeJobs(klazz, () -> deque, al));
+                    }
+                    if (x instanceof BlockingQueue) {
+                        BlockingQueue<Integer> q = (BlockingQueue<Integer>) x;
+                        jobs.addAll(blockingQueueJobs(klazz, () -> q, al));
+                    }
+                    if (x instanceof BlockingDeque) {
+                        BlockingDeque<Integer> q = (BlockingDeque<Integer>) x;
+                        jobs.addAll(blockingDequeJobs(klazz, () -> q, al));
+                    }
+                    if (x instanceof List) {
+                        List<Integer> list = (List<Integer>) x;
+                        jobs.addAll(
+                            collectionJobs(
+                                klazz + " subList",
+                                () -> list.subList(0, x.size()),
+                                al));
+                    }
+                });
+
+        if (reverse) Collections.reverse(jobs);
+        if (shuffle) Collections.shuffle(jobs);
+
+        time(filter(filter, jobs));
+    }
+
+    Collection<Integer> universeRecorder(int[] sum) {
+        return new ArrayList<>() {
+            public boolean contains(Object x) {
+                sum[0] += (Integer) x;
+                return true;
+            }};
+    }
+
+    Collection<Integer> emptyRecorder(int[] sum) {
+        return new ArrayList<>() {
+            public boolean contains(Object x) {
+                sum[0] += (Integer) x;
+                return false;
+            }};
+    }
+
+    List<Job> collectionJobs(
+        String description,
+        Supplier<Collection<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " .removeIf") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        x.removeIf(n -> { sum[0] += n; return true; });
+                        check.sum(sum[0]);}}},
+            new Job(description + " .removeAll") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    Collection<Integer> universe = universeRecorder(sum);
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        x.removeAll(universe);
+                        check.sum(sum[0]);}}},
+            new Job(description + " .retainAll") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    Collection<Integer> empty = emptyRecorder(sum);
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        x.retainAll(empty);
+                        check.sum(sum[0]);}}},
+            new Job(description + " Iterator.remove") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        Iterator<Integer> it = x.iterator();
+                        while (it.hasNext()) {
+                            sum[0] += it.next();
+                            it.remove();
+                        }
+                        check.sum(sum[0]);}}},
+            new Job(description + " clear") {
+                public void work() throws Throwable {
+                    Collection<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        x.forEach(e -> sum[0] += e);
+                        x.clear();
+                        check.sum(sum[0]);}}});
+    }
+
+    List<Job> queueJobs(
+        String description,
+        Supplier<Queue<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " poll()") {
+                public void work() throws Throwable {
+                    Queue<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.poll()) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}});
+    }
+
+    List<Job> dequeJobs(
+        String description,
+        Supplier<Deque<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " descendingIterator().remove") {
+                public void work() throws Throwable {
+                    Deque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        Iterator<Integer> it = x.descendingIterator();
+                        while (it.hasNext()) {
+                            sum[0] += it.next();
+                            it.remove();
+                        }
+                        check.sum(sum[0]);}}},
+            new Job(description + " pollFirst()") {
+                public void work() throws Throwable {
+                    Deque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.pollFirst()) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}},
+            new Job(description + " pollLast()") {
+                public void work() throws Throwable {
+                    Deque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.pollLast()) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}});
+    }
+
+    List<Job> blockingQueueJobs(
+        String description,
+        Supplier<BlockingQueue<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " drainTo(sink)") {
+                public void work() throws Throwable {
+                    BlockingQueue<Integer> x = supplier.get();
+                    ArrayList<Integer> sink = new ArrayList<>();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        sink.clear();
+                        x.addAll(al);
+                        x.drainTo(sink);
+                        sink.forEach(e -> sum[0] += e);
+                        check.sum(sum[0]);}}},
+            new Job(description + " drainTo(sink, n)") {
+                public void work() throws Throwable {
+                    BlockingQueue<Integer> x = supplier.get();
+                    ArrayList<Integer> sink = new ArrayList<>();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        sink.clear();
+                        x.addAll(al);
+                        x.drainTo(sink, al.size());
+                        sink.forEach(e -> sum[0] += e);
+                        check.sum(sum[0]);}}});
+    }
+
+    List<Job> blockingDequeJobs(
+        String description,
+        Supplier<BlockingDeque<Integer>> supplier,
+        ArrayList<Integer> al) {
+        return List.of(
+            new Job(description + " timed pollFirst()") {
+                public void work() throws Throwable {
+                    BlockingDeque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.pollFirst(0L, TimeUnit.DAYS)) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}},
+            new Job(description + " timed pollLast()") {
+                public void work() throws Throwable {
+                    BlockingDeque<Integer> x = supplier.get();
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(al);
+                        for (Integer e; (e = x.pollLast(0L, TimeUnit.DAYS)) != null; )
+                            sum[0] += e;
+                        check.sum(sum[0]);}}});
+    }
+}
--- a/jdk/test/java/util/Collections/SyncSubMutexes.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/Collections/SyncSubMutexes.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,7 @@
  * @bug 8048209
  * @summary Check that Collections.synchronizedNavigableSet().tailSet() is using
  * the same lock object as it's source.
+ * @modules java.base/java.util:open
  * @run testng SyncSubMutexes
  */
 import java.lang.reflect.Field;
--- a/jdk/test/java/util/Currency/CurrencyTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/Currency/CurrencyTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,8 @@
  * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531
  *    6488442 7036905 8008577 8039317 8074350 8074351 8150324
  * @summary Basic tests for Currency class.
- * @modules jdk.localedata
+ * @modules java.base/java.util:open
+ *          jdk.localedata
  */
 
 import java.io.ByteArrayInputStream;
--- a/jdk/test/java/util/Currency/ValidateISO4217.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/Currency/ValidateISO4217.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,8 @@
  * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759
  *      8039317 8074350 8074351 8145952
  * @summary Validate ISO 4217 data for Currency class.
+ * @modules java.base/java.util:open
+ *          jdk.localedata
  */
 
 /*
--- a/jdk/test/java/util/EnumSet/OneUniverse.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/EnumSet/OneUniverse.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug     6276988
  * @summary All enum constants in a class should share a single "universe".
+ * @modules java.base/java.util:open
  */
 
 import java.lang.reflect.Field;
--- a/jdk/test/java/util/Hashtable/DeserializedLength.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/Hashtable/DeserializedLength.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
  * @test
  * @bug 8068427
  * @summary Hashtable deserialization reconstitutes table with wrong capacity
+ * @modules java.base/java.util:open
  */
 public class DeserializedLength {
 
--- a/jdk/test/java/util/IdentityHashMap/Capacity.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/IdentityHashMap/Capacity.java	Thu Dec 01 21:39:49 2016 +0000
@@ -38,6 +38,7 @@
  * @bug 6904367
  * @summary IdentityHashMap reallocates storage when inserting expected
  *          number of elements
+ * @modules java.base/java.util:open
  * @run testng Capacity
  * @key randomness
  */
--- a/jdk/test/java/util/Locale/bug6312358.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/Locale/bug6312358.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
  * @bug 6312358
  * @summary Verify that an NPE is thrown by issueing Locale.getInstance() with
  *      any argument being null.
+ * @modules java.base/java.util:open
  */
 
 import java.lang.reflect.InvocationTargetException;
--- a/jdk/test/java/util/ResourceBundle/ReferencesTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/ResourceBundle/ReferencesTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,6 +23,7 @@
 /*
  * @test
  * @bug 4405807
+ * @modules java.base/java.util:open
  * @run main/othervm -Xms10m ReferencesTest
  * @summary Verify that references from ResourceBundle cache don't prevent
  * class loader reclamation.
--- a/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh	Thu Dec 01 21:39:49 2016 +0000
@@ -71,7 +71,8 @@
 echo 'jdk.test.Main should load bundles local to named module "test".'
 $JAVA -p mods -m test/jdk.test.Main de fr ja zh-tw en de || STATUS=1
 
-echo "jdk.test.Main should NOT load bundles from the jar file specified by the class-path."
-$JAVA -cp extra.jar -p mods -m test/jdk.test.Main vi && STATUS=1
+echo "jdk.test.Main should load bundles from the jar file specified by the class-path."
+$JAVA -cp extra.jar -p mods -m test/jdk.test.Main vi || STATUS=1
+
 
 exit $STATUS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,64 @@
+/*
+ * 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.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        int errors = 0;
+        for (String loctag : args) {
+            Locale locale = Locale.forLanguageTag(loctag);
+            if (locale.equals(Locale.ROOT)) {
+                continue;
+            }
+            ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources",
+                                                         locale);
+            String tag = locale.toLanguageTag(); // normalized
+            String value = rb.getString("key");
+            System.out.println(rb.getBaseBundleName() + ": locale = " + tag + ", value = " + value);
+            if (!value.startsWith(tag + ':')) {
+                System.out.println("ERROR: " + value + " expected: " + tag);
+                errors++;
+            }
+
+            // inaccessible bundles
+            try {
+                ResourceBundle.getBundle("jdk.test.internal.resources.Foo", locale);
+                System.out.println("ERROR: jdk.test.internal.resources.Foo should not be accessible");
+                errors++;
+            } catch (MissingResourceException e) {
+                e.printStackTrace();
+
+                Throwable cause = e.getCause();
+                System.out.println("Expected: " +
+                    (cause != null ? cause.getMessage() : e.getMessage()));
+            }
+        }
+        if (errors > 0) {
+            throw new RuntimeException(errors + " errors");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.internal.resources;
+
+import java.util.ListResourceBundle;
+
+public class Foo extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_de.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.internal.resources;
+
+import java.util.ListResourceBundle;
+
+public class Foo_de extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "de: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_en.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.internal.resources;
+
+import java.util.ListResourceBundle;
+
+public class Foo_en extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "en: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_fr.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.internal.resources;
+
+import java.util.ListResourceBundle;
+
+public class Foo_fr extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "fr: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_ja.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=ja: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=zh: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/internal/resources/Foo_zh_TW.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=zh-TW: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "root: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_de.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_de extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "de: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_en.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_en extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "en: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_fr.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.resources;
+
+import java.util.ListResourceBundle;
+
+public class MyResources_fr extends ListResourceBundle {
+    @Override
+    public Object[][] getContents() {
+        return new Object[][] {
+            { "key", "fr: message" }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_ja.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=ja: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=zh: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/jdk/test/resources/MyResources_zh_TW.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+key=zh-TW: message
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/src/bundles/module-info.java	Thu Dec 01 21:39:49 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 bundles {
+    opens jdk.test.resources;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/unnamed/unnamed.sh	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,74 @@
+#
+# 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
+# @summary Test unnamed module to find resource bundles exported
+#          from a named module 
+
+
+set -e
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVAC="$COMPILEJAVA/bin/javac"
+JAVA="$TESTJAVA/bin/java"
+
+rm -rf mods
+
+mkdir -p mods/test
+
+B=bundles
+mkdir -p mods/$B
+CLASSES="`find $TESTSRC/src/$B -name '*.java'`"
+if [ "x$CLASSES" != x ]; then
+    $JAVAC -g -d mods --module-source-path $TESTSRC/src $CLASSES
+fi
+PROPS="`(cd $TESTSRC/src/$B; find . -name '*.properties')`"
+if [ "x$PROPS" != x ]; then
+    for P in $PROPS
+    do
+      D=`dirname $P`
+      mkdir -p mods/$B/$D
+      cp $TESTSRC/src/$B/$P mods/$B/$D/
+    done
+fi
+
+mkdir classes
+$JAVAC -d classes $TESTSRC/Main.java
+
+# access resource bundles that are exported private unconditionally
+$JAVA -cp classes --module-path mods --add-modules bundles \
+      Main de fr ja zh-tw en de
+
+# --add-exports can't open resources 
+$JAVA -cp classes --module-path mods --add-modules bundles \
+      --add-opens bundles/jdk.test.internal.resources=ALL-UNNAMED \
+      Main de fr ja zh-tw en de
+
+exit $?
--- a/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh	Thu Dec 01 21:39:49 2016 +0000
@@ -111,9 +111,9 @@
 runJava -cp mods/named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \
     jdk.test.resources.props.MyResources true
 runJava -cp mods/named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \
-    jdk.test.resources.classes.MyResources false
+    jdk.test.resources.classes.MyResources true
 runJava -cp mods/named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \
-    jdk.test.resources.props.MyResources false
+    jdk.test.resources.props.MyResources true
 
 # Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg
 # both of which specify an unnamed module with ResourceBundle.getBundle.
@@ -171,13 +171,13 @@
 
 # Add mods/exported.named.bundles to the class path.
 runJava -cp mods/exported.named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \
-    jdk.test.resources.exported.classes.MyResources false
+    jdk.test.resources.exported.classes.MyResources true
 runJava -cp mods/exported.named.bundles -p mods -m test/jdk.test.TestWithNoModuleArg \
-    jdk.test.resources.exported.props.MyResources false
+    jdk.test.resources.exported.props.MyResources true
 runJava -cp mods/exported.named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \
-    jdk.test.resources.exported.classes.MyResources false
+    jdk.test.resources.exported.classes.MyResources true
 runJava -cp mods/exported.named.bundles -p mods -m embargo/jdk.embargo.TestWithNoModuleArg \
-    jdk.test.resources.exported.props.MyResources false
+    jdk.test.resources.exported.props.MyResources true
 
 # Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg
 # which specify an unnamed module with ResourceBundle.getBundle.
--- a/jdk/test/java/util/ServiceLoader/Basic.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2005, 2012, 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.*;
-import java.util.*;
-
-
-public class Basic {
-
-    private static PrintStream out = System.err;
-
-    private static <T> Set<T> setOf(Iterable<T> it) {
-        Set<T> s = new HashSet<T>();
-        for (T t : it)
-            s.add(t);
-        return s;
-    }
-
-    private static <T> void checkEquals(Set<T> s1, Set<T> s2, boolean eq) {
-        if (s1.equals(s2) != eq)
-            throw new RuntimeException(String.format("%b %s : %s",
-                                                     eq, s1, s2));
-    }
-
-    abstract static class TestLoader {
-        String name;
-
-        TestLoader(String name) { this.name = name; }
-
-        abstract ServiceLoader<FooService> load();
-    }
-
-    static TestLoader tcclLoader = new TestLoader("Thread context class loader") {
-        ServiceLoader<FooService> load() {
-            return ServiceLoader.load(FooService.class);
-        }
-    };
-
-    static TestLoader systemClLoader = new TestLoader("System class loader") {
-        ServiceLoader<FooService> load() {
-            return ServiceLoader.load(FooService.class, ClassLoader.getSystemClassLoader());
-        }
-    };
-
-    static TestLoader nullClLoader = new TestLoader("null (defer to system class loader)") {
-        ServiceLoader<FooService> load() {
-            return ServiceLoader.load(FooService.class, null);
-        }
-    };
-
-    public static void main(String[] args) {
-        for (TestLoader tl : Arrays.asList(tcclLoader, systemClLoader, nullClLoader)) {
-            test(tl);
-        }
-    }
-
-    static void test(TestLoader tl) {
-        ServiceLoader<FooService> sl = tl.load();
-        out.format("%s: %s%n", tl.name, sl);
-
-        // Providers are cached
-        Set<FooService> ps = setOf(sl);
-        checkEquals(ps, setOf(sl), true);
-
-        // The cache can be flushed and reloaded
-        sl.reload();
-        checkEquals(ps, setOf(sl), false);
-
-    }
-}
--- a/jdk/test/java/util/ServiceLoader/FooProvider1.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2005, 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.
- */
-
-public class FooProvider1 extends FooService { }
--- a/jdk/test/java/util/ServiceLoader/FooProvider2.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2005, 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.
- */
-
-public class FooProvider2 extends FooService { }
--- a/jdk/test/java/util/ServiceLoader/FooProvider3.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2005, 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.
- */
-
-public class FooProvider3 extends FooService { }
--- a/jdk/test/java/util/ServiceLoader/FooService.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2005, 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.
- */
-
-public abstract class FooService { }
--- a/jdk/test/java/util/ServiceLoader/Load.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2005, 2006, 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.*;
-import java.util.*;
-
-
-public class Load {
-
-    private static PrintStream out = System.err;
-
-    public static void main(String[] args) throws Exception {
-
-        boolean installedOnly = false;
-
-        List<String> expected = new ArrayList<String>(Arrays.asList(args));
-        if (!expected.isEmpty() && expected.get(0).equals("-i")) {
-            expected.remove(0);
-            installedOnly = true;
-        }
-        if (expected.isEmpty())
-            throw new Exception("usage: Load [-i] ( fail | provider-class-name )*");
-
-        ServiceLoader<FooService> sl = (installedOnly
-                                        ? ServiceLoader.loadInstalled(FooService.class)
-                                        : ServiceLoader.load(FooService.class));
-        out.format("%s%n", sl);
-        Iterator<FooService> sli = sl.iterator();
-        Iterator<String> ei = expected.iterator();
-
-        for (;; ei.remove()) {
-            FooService fp = null;
-            try {
-                if (!sli.hasNext())
-                    break;
-                fp = sli.next();
-            } catch (ServiceConfigurationError x) {
-                if (ei.next().equals("fail")) {
-                    out.format("Failed as expected: %s%n", x);
-                    continue;
-                }
-                throw x;
-            }
-            String ec = ei.next();
-            if (!fp.getClass().getName().equals(ec))
-                throw new
-                    Exception(String.format("Wrong provider %s; expected %s",
-                                            fp.getClass().getName(), ec));
-            out.format("Provider found: %s%n", fp.getClass().getName());
-        }
-
-        if (ei.hasNext())
-            throw new Exception("Missing providers: " + expected);
-
-    }
-
-}
--- a/jdk/test/java/util/ServiceLoader/basic.sh	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-#
-# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# @test
-# @bug 4640520 6354623 7198496
-# @summary Unit test for java.util.ServiceLoader
-#
-# @build Basic Load FooService FooProvider1 FooProvider2 FooProvider3
-# @run shell basic.sh
-
-# Command-line usage: sh basic.sh /path/to/build
-
-if [ -z "$TESTJAVA" ]; then
-  if [ $# -lt 1 ]; then exit 1; fi
-  TESTJAVA="$1"; shift
-  COMPILEJAVA="${TESTJAVA}"
-  TESTSRC="`pwd`"
-  TESTCLASSES="`pwd`"
-fi
-
-JAVA="$TESTJAVA/bin/java"
-JAR="$COMPILEJAVA/bin/jar"
-
-OS=`uname -s`
-case "$OS" in
-    SunOS | Darwin | AIX )
-      FS='/'
-      SEP=':' ;;
-    Linux )
-      FS='/'
-      SEP=':' ;;
-    * )
-      FS='\\'
-      SEP='\;' ;;
-esac
-
-JARD=x.jar
-EXTD=x.ext
-TESTD=x.test
-P3JAR=${EXTD}${FS}p3.jar
-
-if [ \! -d $EXTD ]; then
-    # Initialize
-    echo Initializing...
-    rm -rf $JARD $EXTD $TESTD
-    mkdir -p $JARD $EXTD $TESTD
-
-    for n in 2 3; do
-      rm -rf $JARD/*; mkdir -p $JARD/META-INF/services
-      echo FooProvider$n \
-        >$JARD/META-INF/services/FooService
-      cp $TESTCLASSES/FooProvider$n.class $JARD
-      if [ $n = 3 ]; then
-        cp $TESTCLASSES/FooService.class $JARD
-      fi
-      (cd $JARD; "$JAR" ${TESTTOOLVMOPTS} -cf ../p$n.jar *)
-    done
-
-    mv p3.jar $EXTD
-
-    cp $TESTCLASSES/Load.class $TESTD
-    cp $TESTCLASSES/FooService.class $TESTD
-    cp $TESTCLASSES/FooProvider1.class $TESTD
-    mkdir -p $TESTD/META-INF/services
-    echo FooProvider1 \
-      >$TESTD/META-INF/services/FooService
-
-    # This gives us:
-    #   $TESTD: FooProvider1
-    #   .     : FooProvider2, in p2.jar
-    #   $EXTD:  FooProvider3, in p3.jar
-
-fi
-
-failures=0
-
-go() {
-  echo ''
-  cp="$1"; shift
-  if [ -z "$cp" ]; then cp="$TESTCLASSES"; else cp="$TESTCLASSES$SEP$cp"; fi
-  vmargs="$1"; shift
-  sh -xc "'$JAVA' ${TESTVMOPTS} -cp $cp $vmargs $T $*" 2>&1
-  if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
-}
-
-
-# Java-level tests
-
-T=Basic
-go ".${SEP}$TESTD${SEP}p2.jar" ""
-
-# Success cases
-
-T=Load
-
-go "$TESTD" "" FooProvider1
-
-go ".${SEP}p2.jar" "" FooProvider2
-
-go "${P3JAR}${SEP}p2.jar" "" FooProvider3 FooProvider2
-
-go "$TESTD${SEP}p2.jar" "" FooProvider1 FooProvider2
-
-go "${P3JAR}${SEP}$TESTD" "" FooProvider3 FooProvider1
-
-go "${P3JAR}${SEP}$TESTD${SEP}p2.jar" "" \
-  FooProvider3 FooProvider1 FooProvider2
-
-# Failure cases
-
-mkdir -p x.meta/META-INF/services
-
-# Simple failures
-for p in FooProvider42 'blah blah' 9234 'X!' java.lang.Object; do
-  echo $p >x.meta/META-INF/services/FooService
-  go ".${SEP}x.meta" "" fail
-done
-
-# Failures followed by successes
-echo FooProvider42 >x.meta/META-INF/services/FooService
-go "$TESTD${SEP}x.meta" "" FooProvider1 fail
-go "x.meta${SEP}$TESTD" "" fail FooProvider1
-go "$TESTD${SEP}x.meta${SEP}${SEP}p2.jar" "" \
-  FooProvider1 fail FooProvider2
-
-
-# Summary
-
-echo ''
-if [ $failures -gt 0 ];
-  then echo "$failures case(s) failed";
-  else echo "All cases passed"; fi
-exit $failures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/BarProvider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+public class BarProvider { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/Basic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005, 2012, 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.*;
+import java.util.*;
+
+
+public class Basic {
+
+    private static PrintStream out = System.err;
+
+    private static <T> Set<T> setOf(Iterable<T> it) {
+        Set<T> s = new HashSet<T>();
+        for (T t : it)
+            s.add(t);
+        return s;
+    }
+
+    private static <T> void checkEquals(Set<T> s1, Set<T> s2, boolean eq) {
+        if (s1.equals(s2) != eq)
+            throw new RuntimeException(String.format("%b %s : %s",
+                                                     eq, s1, s2));
+    }
+
+    abstract static class TestLoader {
+        String name;
+
+        TestLoader(String name) { this.name = name; }
+
+        abstract ServiceLoader<FooService> load();
+    }
+
+    static TestLoader tcclLoader = new TestLoader("Thread context class loader") {
+        ServiceLoader<FooService> load() {
+            return ServiceLoader.load(FooService.class);
+        }
+    };
+
+    static TestLoader systemClLoader = new TestLoader("System class loader") {
+        ServiceLoader<FooService> load() {
+            return ServiceLoader.load(FooService.class, ClassLoader.getSystemClassLoader());
+        }
+    };
+
+    static TestLoader nullClLoader = new TestLoader("null (defer to system class loader)") {
+        ServiceLoader<FooService> load() {
+            return ServiceLoader.load(FooService.class, null);
+        }
+    };
+
+    public static void main(String[] args) {
+        for (TestLoader tl : Arrays.asList(tcclLoader, systemClLoader, nullClLoader)) {
+            test(tl);
+        }
+    }
+
+    static void test(TestLoader tl) {
+        ServiceLoader<FooService> sl = tl.load();
+        out.format("%s: %s%n", tl.name, sl);
+
+        // Providers are cached
+        Set<FooService> ps = setOf(sl);
+        checkEquals(ps, setOf(sl), true);
+
+        // The cache can be flushed and reloaded
+        sl.reload();
+        checkEquals(ps, setOf(sl), false);
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/FooProvider1.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2005, 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.
+ */
+
+public class FooProvider1 extends FooService { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/FooProvider2.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2005, 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.
+ */
+
+public class FooProvider2 extends FooService { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/FooProvider3.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2005, 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.
+ */
+
+public class FooProvider3 extends FooService { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/FooService.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2005, 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.
+ */
+
+public abstract class FooService { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/Load.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2005, 2006, 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.*;
+import java.util.*;
+
+
+public class Load {
+
+    private static PrintStream out = System.err;
+
+    public static void main(String[] args) throws Exception {
+
+        boolean installedOnly = false;
+
+        List<String> expected = new ArrayList<String>(Arrays.asList(args));
+        if (!expected.isEmpty() && expected.get(0).equals("-i")) {
+            expected.remove(0);
+            installedOnly = true;
+        }
+        if (expected.isEmpty())
+            throw new Exception("usage: Load [-i] ( fail | provider-class-name )*");
+
+        ServiceLoader<FooService> sl = (installedOnly
+                                        ? ServiceLoader.loadInstalled(FooService.class)
+                                        : ServiceLoader.load(FooService.class));
+        out.format("%s%n", sl);
+        Iterator<FooService> sli = sl.iterator();
+        Iterator<String> ei = expected.iterator();
+
+        for (;; ei.remove()) {
+            FooService fp = null;
+            try {
+                if (!sli.hasNext())
+                    break;
+                fp = sli.next();
+            } catch (ServiceConfigurationError x) {
+                if (ei.next().equals("fail")) {
+                    out.format("Failed as expected: %s%n", x);
+                    continue;
+                }
+                throw x;
+            }
+            String ec = ei.next();
+            if (!fp.getClass().getName().equals(ec))
+                throw new
+                    Exception(String.format("Wrong provider %s; expected %s",
+                                            fp.getClass().getName(), ec));
+            out.format("Provider found: %s%n", fp.getClass().getName());
+        }
+
+        if (ei.hasNext())
+            throw new Exception("Missing providers: " + expected);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/basic/basic.sh	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,153 @@
+#
+# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 4640520 6354623 7198496
+# @summary Unit test for java.util.ServiceLoader
+#
+# @build Basic Load FooService FooProvider1 FooProvider2 FooProvider3 BarProvider
+# @run shell basic.sh
+
+# Command-line usage: sh basic.sh /path/to/build
+
+if [ -z "$TESTJAVA" ]; then
+  if [ $# -lt 1 ]; then exit 1; fi
+  TESTJAVA="$1"; shift
+  COMPILEJAVA="${TESTJAVA}"
+  TESTSRC="`pwd`"
+  TESTCLASSES="`pwd`"
+fi
+
+JAVA="$TESTJAVA/bin/java"
+JAR="$COMPILEJAVA/bin/jar"
+
+OS=`uname -s`
+case "$OS" in
+    SunOS | Darwin | AIX )
+      FS='/'
+      SEP=':' ;;
+    Linux )
+      FS='/'
+      SEP=':' ;;
+    * )
+      FS='\\'
+      SEP='\;' ;;
+esac
+
+JARD=x.jar
+EXTD=x.ext
+TESTD=x.test
+P3JAR=${EXTD}${FS}p3.jar
+
+if [ \! -d $EXTD ]; then
+    # Initialize
+    echo Initializing...
+    rm -rf $JARD $EXTD $TESTD
+    mkdir -p $JARD $EXTD $TESTD
+
+    for n in 2 3; do
+      rm -rf $JARD/*; mkdir -p $JARD/META-INF/services
+      echo FooProvider$n \
+        >$JARD/META-INF/services/FooService
+      cp $TESTCLASSES/FooProvider$n.class $JARD
+      if [ $n = 3 ]; then
+        cp $TESTCLASSES/FooService.class $JARD
+      fi
+      (cd $JARD; "$JAR" ${TESTTOOLVMOPTS} -cf ../p$n.jar *)
+    done
+
+    mv p3.jar $EXTD
+
+    cp $TESTCLASSES/Load.class $TESTD
+    cp $TESTCLASSES/FooService.class $TESTD
+    cp $TESTCLASSES/FooProvider1.class $TESTD
+    mkdir -p $TESTD/META-INF/services
+    echo FooProvider1 \
+      >$TESTD/META-INF/services/FooService
+
+    # This gives us:
+    #   $TESTD: FooProvider1
+    #   .     : FooProvider2, in p2.jar
+    #   $EXTD:  FooProvider3, in p3.jar
+
+fi
+
+failures=0
+
+go() {
+  echo ''
+  cp="$1"; shift
+  if [ -z "$cp" ]; then cp="$TESTCLASSES"; else cp="$TESTCLASSES$SEP$cp"; fi
+  vmargs="$1"; shift
+  sh -xc "'$JAVA' ${TESTVMOPTS} -cp $cp $vmargs $T $*" 2>&1
+  if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
+}
+
+
+# Java-level tests
+
+T=Basic
+go ".${SEP}$TESTD${SEP}p2.jar" ""
+
+# Success cases
+
+T=Load
+
+go "$TESTD" "" FooProvider1
+
+go ".${SEP}p2.jar" "" FooProvider2
+
+go "${P3JAR}${SEP}p2.jar" "" FooProvider3 FooProvider2
+
+go "$TESTD${SEP}p2.jar" "" FooProvider1 FooProvider2
+
+go "${P3JAR}${SEP}$TESTD" "" FooProvider3 FooProvider1
+
+go "${P3JAR}${SEP}$TESTD${SEP}p2.jar" "" \
+  FooProvider3 FooProvider1 FooProvider2
+
+# Failure cases
+
+mkdir -p x.meta/META-INF/services
+
+# Simple failures
+for p in FooProvider42 'blah blah' 9234 'X!' BarProvider; do
+  echo $p >x.meta/META-INF/services/FooService
+  go ".${SEP}x.meta" "" fail
+done
+
+# Failures followed by successes
+echo FooProvider42 >x.meta/META-INF/services/FooService
+go "$TESTD${SEP}x.meta" "" FooProvider1 fail
+go "x.meta${SEP}$TESTD" "" fail FooProvider1
+go "$TESTD${SEP}x.meta${SEP}${SEP}p2.jar" "" \
+  FooProvider1 fail FooProvider2
+
+
+# Summary
+
+echo ''
+if [ $failures -gt 0 ];
+  then echo "$failures case(s) failed";
+  else echo "All cases passed"; fi
+exit $failures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,196 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build CompilerUtils
+ * @run testng/othervm BadProvidersTest
+ * @summary Basic test of ServiceLoader with bad provider and bad provider
+ *          factories deployed on the module path
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.List;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.ServiceLoader.Provider;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.*;
+
+/**
+ * Basic test of `provides S with PF` and `provides S with P` where the provider
+ * factory or provider
+ */
+
+public class BadProvidersTest {
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final Path USER_DIR   = Paths.get(System.getProperty("user.dir"));
+    private static final Path SRC_DIR    = Paths.get(TEST_SRC, "modules");
+
+    private static final Path BADFACTORIES_DIR = Paths.get(TEST_SRC, "badfactories");
+    private static final Path BADPROVIDERS_DIR = Paths.get(TEST_SRC, "badproviders");
+
+    private static final String TEST1_MODULE = "test1";
+    private static final String TEST2_MODULE = "test2";
+
+    private static final String TEST_SERVICE = "p.Service";
+
+    /**
+     * Compiles a module, returning a module path with the compiled module.
+     */
+    private Path compileTest(String moduleName) throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Path output = Files.createDirectory(dir.resolve(moduleName));
+        boolean compiled = CompilerUtils.compile(SRC_DIR.resolve(moduleName), output);
+        assertTrue(compiled);
+        return dir;
+    }
+
+    /**
+     * Resolves a test module and loads it into its own layer. ServiceLoader
+     * is then used to load all providers.
+     */
+    private List<Provider> loadProviders(Path mp, String moduleName) throws Exception {
+        ModuleFinder finder = ModuleFinder.of(mp);
+
+        Layer bootLayer = Layer.boot();
+
+        Configuration cf = bootLayer.configuration()
+                .resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of(moduleName));
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+
+        Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl);
+
+        Class<?> service = layer.findLoader(moduleName).loadClass(TEST_SERVICE);
+
+        return ServiceLoader.load(layer, service)
+                .stream()
+                .collect(Collectors.toList());
+    }
+
+    @Test
+    public void sanityTest1() throws Exception {
+        Path mods = compileTest(TEST1_MODULE);
+        List<Provider> list = loadProviders(mods, TEST1_MODULE);
+        assertTrue(list.size() == 1);
+
+        // the provider is a singleton, enforced by the provider factory
+        Object p1 = list.get(0).get();
+        Object p2 = list.get(0).get();
+        assertTrue(p1 != null);
+        assertTrue(p1 == p2);
+    }
+
+    @Test
+    public void sanityTest2() throws Exception {
+        Path mods = compileTest(TEST2_MODULE);
+        List<Provider> list = loadProviders(mods, TEST2_MODULE);
+        assertTrue(list.size() == 1);
+        Object p = list.get(0).get();
+        assertTrue(p != null);
+    }
+
+
+    @DataProvider(name = "badfactories")
+    public Object[][] createBadFactories() {
+        return new Object[][] {
+                { "classnotpublic",     null },
+                { "methodnotpublic",    null },
+                { "badreturntype",      null },
+                { "returnsnull",        null },
+                { "throwsexception",    null },
+        };
+    }
+
+
+    @Test(dataProvider = "badfactories",
+          expectedExceptions = ServiceConfigurationError.class)
+    public void testBadFactory(String testName, String ignore) throws Exception {
+        Path mods = compileTest(TEST1_MODULE);
+
+        // compile the bad factory
+        Path source = BADFACTORIES_DIR.resolve(testName);
+        Path output = Files.createTempDirectory(USER_DIR, "tmp");
+        boolean compiled = CompilerUtils.compile(source, output);
+        assertTrue(compiled);
+
+        // copy the compiled class into the module
+        Path classFile = Paths.get("p", "ProviderFactory.class");
+        Files.copy(output.resolve(classFile),
+                   mods.resolve(TEST1_MODULE).resolve(classFile),
+                   StandardCopyOption.REPLACE_EXISTING);
+
+        // load providers and instantiate each one
+        loadProviders(mods, TEST1_MODULE).forEach(Provider::get);
+    }
+
+
+    @DataProvider(name = "badproviders")
+    public Object[][] createBadProviders() {
+        return new Object[][] {
+                { "notpublic",          null },
+                { "ctornotpublic",      null },
+                { "notasubtype",        null },
+                { "throwsexception",    null }
+        };
+    }
+
+
+    @Test(dataProvider = "badproviders",
+          expectedExceptions = ServiceConfigurationError.class)
+    public void testBadProvider(String testName, String ignore) throws Exception {
+        Path mods = compileTest(TEST2_MODULE);
+
+        // compile the bad provider
+        Path source = BADPROVIDERS_DIR.resolve(testName);
+        Path output = Files.createTempDirectory(USER_DIR, "tmp");
+        boolean compiled = CompilerUtils.compile(source, output);
+        assertTrue(compiled);
+
+        // copy the compiled class into the module
+        Path classFile = Paths.get("p", "Provider.class");
+        Files.copy(output.resolve(classFile),
+                   mods.resolve(TEST2_MODULE).resolve(classFile),
+                   StandardCopyOption.REPLACE_EXISTING);
+
+        // load providers and instantiate each one
+        loadProviders(mods, TEST2_MODULE).forEach(Provider::get);
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/Basic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,432 @@
+/*
+ * 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
+ * @library modules
+ * @build bananascript/*
+ * @compile src/pearscript/org/pear/PearScriptEngineFactory.java
+ *          src/pearscript/org/pear/PearScript.java
+ * @run testng/othervm Basic
+ * @summary Basic test for ServiceLoader with a provider deployed as a module.
+ */
+
+import java.lang.module.Configuration;
+import java.lang.module.ModuleFinder;
+import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.*;
+import java.util.ServiceLoader.Provider;
+import java.util.stream.Collectors;
+import javax.script.ScriptEngineFactory;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeTest;
+import static org.testng.Assert.*;
+
+/**
+ * Basic test for ServiceLoader. The test make use of two service providers:
+ * 1. BananaScriptEngine - a ScriptEngineFactory deployed as a module on the
+ *    module path. It implementations a singleton via the public static
+ *    provider method.
+ * 2. PearScriptEngine - a ScriptEngineFactory deployed on the class path
+ *    with a service configuration file.
+ */
+
+public class Basic {
+
+    // Copy the services configuration file for "pearscript" into place.
+    @BeforeTest
+    public void setup() throws Exception {
+        Path src = Paths.get(System.getProperty("test.src", ""));
+        Path classes = Paths.get(System.getProperty("test.classes", ""));
+        String st = ScriptEngineFactory.class.getName();
+        Path config = Paths.get("META-INF", "services", st);
+        Path source = src.resolve("src").resolve("pearscript").resolve(config);
+        Path target = classes.resolve(config);
+        Files.createDirectories(target.getParent());
+        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
+    }
+
+    /**
+     * Basic test of iterator() to ensure that providers located as modules
+     * and on the class path are found.
+     */
+    @Test
+    public void testIterator() {
+        ServiceLoader<ScriptEngineFactory> loader
+            = ServiceLoader.load(ScriptEngineFactory.class);
+        Set<String> names = collectAll(loader)
+                .stream()
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertTrue(names.contains("BananaScriptEngine"));
+        assertTrue(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of iterator() to test iteration order. Providers deployed
+     * as named modules should be found before providers deployed on the class
+     * path.
+     */
+    @Test
+    public void testIteratorOrder() {
+        ServiceLoader<ScriptEngineFactory> loader
+            = ServiceLoader.load(ScriptEngineFactory.class);
+        boolean foundUnnamed = false;
+        for (ScriptEngineFactory factory : collectAll(loader)) {
+            if (factory.getClass().getModule().isNamed()) {
+                if (foundUnnamed) {
+                    assertTrue(false, "Named module element after unnamed");
+                }
+            } else {
+                foundUnnamed = true;
+            }
+        }
+    }
+
+    /**
+     * Basic test of Provider::type
+     */
+    @Test
+    public void testProviderType() {
+        Set<String> types = ServiceLoader.load(ScriptEngineFactory.class)
+                .stream()
+                .map(Provider::type)
+                .map(Class::getName)
+                .collect(Collectors.toSet());
+        assertTrue(types.contains("org.banana.BananaScriptEngineFactory"));
+        assertTrue(types.contains("org.pear.PearScriptEngineFactory"));
+    }
+
+    /**
+     * Basic test of Provider::get
+     */
+    @Test
+    public void testProviderGet() {
+        Set<String> names = ServiceLoader.load(ScriptEngineFactory.class)
+                .stream()
+                .map(Provider::get)
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertTrue(names.contains("BananaScriptEngine"));
+        assertTrue(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of the public static provider method. BananaScriptEngine
+     * defines a provider method that returns the same instance.
+     */
+    @Test
+    public void testSingleton() {
+        Optional<Provider<ScriptEngineFactory>> oprovider
+            = ServiceLoader.load(ScriptEngineFactory.class)
+                .stream()
+                .filter(p -> p.type().getName().equals("org.banana.BananaScriptEngineFactory"))
+                .findFirst();
+        assertTrue(oprovider.isPresent());
+        Provider<ScriptEngineFactory> provider = oprovider.get();
+
+        // invoke Provider::get twice
+        ScriptEngineFactory factory1 = provider.get();
+        ScriptEngineFactory factory2 = provider.get();
+        assertTrue(factory1 == factory2);
+    }
+
+    /**
+     * Basic test of stream() to ensure that elements for providers in named
+     * modules come before elements for providers in unnamed modules.
+     */
+    @Test
+    public void testStreamOrder() {
+        List<Class<?>> types = ServiceLoader.load(ScriptEngineFactory.class)
+                .stream()
+                .map(Provider::type)
+                .collect(Collectors.toList());
+
+        boolean foundUnnamed = false;
+        for (Class<?> factoryClass : types) {
+            if (factoryClass.getModule().isNamed()) {
+                if (foundUnnamed) {
+                    assertTrue(false, "Named module element after unnamed");
+                }
+            } else {
+                foundUnnamed = true;
+            }
+        }
+    }
+
+    /**
+     * Basic test of ServiceLoader.findFirst()
+     */
+    @Test
+    public void testFindFirst() {
+        Optional<ScriptEngineFactory> ofactory
+            = ServiceLoader.load(ScriptEngineFactory.class).findFirst();
+        assertTrue(ofactory.isPresent());
+        ScriptEngineFactory factory = ofactory.get();
+        assertTrue(factory.getClass().getModule().isNamed());
+
+        class S { }
+        assertFalse(ServiceLoader.load(S.class).findFirst().isPresent());
+    }
+
+    /**
+     * Basic test ServiceLoader.load specifying the platform class loader.
+     * The providers on the module path and class path should not be located.
+     */
+    @Test
+    public void testWithPlatformClassLoader() {
+        ClassLoader pcl = ClassLoader.getPlatformClassLoader();
+
+        // iterator
+        ServiceLoader<ScriptEngineFactory> loader
+                = ServiceLoader.load(ScriptEngineFactory.class, pcl);
+        Set<String> names = collectAll(loader)
+                .stream()
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertFalse(names.contains("BananaScriptEngine"));
+        assertFalse(names.contains("PearScriptEngine"));
+
+        // stream
+        names = ServiceLoader.load(ScriptEngineFactory.class, pcl)
+                .stream()
+                .map(Provider::get)
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertFalse(names.contains("BananaScriptEngine"));
+        assertFalse(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of ServiceLoader.load, using the class loader for
+     * a module in a custom layer as the context.
+     */
+    @Test
+    public void testWithCustomLayer1() {
+        Layer layer = createCustomLayer("bananascript");
+
+        ClassLoader loader = layer.findLoader("bananascript");
+        List<ScriptEngineFactory> providers
+            = collectAll(ServiceLoader.load(ScriptEngineFactory.class, loader));
+
+        // should have at least 2 x bananascript + pearscript
+        assertTrue(providers.size() >= 3);
+
+        // first element should be the provider in the custom layer
+        ScriptEngineFactory factory = providers.get(0);
+        assertTrue(factory.getClass().getClassLoader() == loader);
+        assertTrue(factory.getClass().getModule().getLayer() == layer);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+
+        // remainder should be the boot layer
+        providers.remove(0);
+        Set<String> names = providers.stream()
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertTrue(names.contains("BananaScriptEngine"));
+        assertTrue(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of ServiceLoader.load using a custom Layer as the context.
+     */
+    @Test
+    public void testWithCustomLayer2() {
+        Layer layer = createCustomLayer("bananascript");
+
+        List<ScriptEngineFactory> factories
+            = collectAll(ServiceLoader.load(layer, ScriptEngineFactory.class));
+
+        // should have at least 2 x bananascript
+        assertTrue(factories.size() >= 2);
+
+        // first element should be the provider in the custom layer
+        ScriptEngineFactory factory = factories.get(0);
+        assertTrue(factory.getClass().getModule().getLayer() == layer);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+
+        // remainder should be the boot layer
+        factories.remove(0);
+        Set<String> names = factories.stream()
+                .map(ScriptEngineFactory::getEngineName)
+                .collect(Collectors.toSet());
+        assertTrue(names.contains("BananaScriptEngine"));
+        assertFalse(names.contains("PearScriptEngine"));
+    }
+
+    /**
+     * Basic test of ServiceLoader.load with a tree of layers.
+     *
+     * Test scenario:
+     * - boot layer contains "bananascript", maybe other script engines
+     * - layer1, with boot layer as parent, contains "bananascript"
+     * - layer2, with boot layer as parent, contains "bananascript"
+     * - layer3, with layer1 ad layer as parents, contains "bananascript"
+     *
+     * ServiceLoader should locate all 4 script engine factories in DFS order.
+     */
+    @Test
+    public void testWithCustomLayer3() {
+        Layer bootLayer = Layer.boot();
+        Configuration cf0 = bootLayer.configuration();
+
+        // boot layer should contain "bananascript"
+        List<ScriptEngineFactory> factories
+            = collectAll(ServiceLoader.load(bootLayer, ScriptEngineFactory.class));
+        int countInBootLayer = factories.size();
+        assertTrue(countInBootLayer >= 1);
+        assertTrue(factories.stream()
+                .map(p -> p.getEngineName())
+                .filter("BananaScriptEngine"::equals)
+                .findAny()
+                .isPresent());
+
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Path dir = Paths.get(System.getProperty("test.classes", "."), "modules");
+        ModuleFinder finder = ModuleFinder.of(dir);
+
+        // layer1
+        Configuration cf1 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of());
+        Layer layer1 = bootLayer.defineModulesWithOneLoader(cf1, scl);
+        assertTrue(layer1.modules().size() == 1);
+
+        // layer2
+        Configuration cf2 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of());
+        Layer layer2 = bootLayer.defineModulesWithOneLoader(cf2, scl);
+        assertTrue(layer2.modules().size() == 1);
+
+        // layer3 with layer1 and layer2 as parents
+        Configuration cf3 = Configuration.resolveRequiresAndUses(finder,
+                List.of(cf1, cf2),
+                ModuleFinder.of(),
+                Set.of());
+        Layer layer3 = Layer.defineModulesWithOneLoader(cf3, List.of(layer1, layer2), scl).layer();
+        assertTrue(layer3.modules().size() == 1);
+
+
+        // class loaders
+        ClassLoader loader1 = layer1.findLoader("bananascript");
+        ClassLoader loader2 = layer2.findLoader("bananascript");
+        ClassLoader loader3 = layer3.findLoader("bananascript");
+        assertTrue(loader1 != loader2);
+        assertTrue(loader1 != loader3);
+        assertTrue(loader2 != loader3);
+
+        // load all factories with layer3 as the context
+        factories = collectAll(ServiceLoader.load(layer3, ScriptEngineFactory.class));
+        int count = factories.size();
+        assertTrue(count == countInBootLayer + 3);
+
+        // the ordering should be layer3, layer1, boot layer, layer2
+
+        ScriptEngineFactory factory = factories.get(0);
+        assertTrue(factory.getClass().getModule().getLayer() == layer3);
+        assertTrue(factory.getClass().getClassLoader() == loader3);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+
+        factory = factories.get(1);
+        assertTrue(factory.getClass().getModule().getLayer() == layer1);
+        assertTrue(factory.getClass().getClassLoader() == loader1);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+
+        // boot layer "bananascript" and maybe other factories
+        int last = count -1;
+        boolean found = false;
+        for (int i=2; i<last; i++) {
+            factory = factories.get(i);
+            assertTrue(factory.getClass().getModule().getLayer() == bootLayer);
+            if (factory.getEngineName().equals("BananaScriptEngine")) {
+                assertFalse(found);
+                found = true;
+            }
+        }
+        assertTrue(found);
+
+        factory = factories.get(last);
+        assertTrue(factory.getClass().getModule().getLayer() == layer2);
+        assertTrue(factory.getClass().getClassLoader() == loader2);
+        assertTrue(factory.getEngineName().equals("BananaScriptEngine"));
+    }
+
+
+    // -- nulls --
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull1() {
+        ServiceLoader.load(null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull2() {
+        ServiceLoader.load((Class<?>) null, ClassLoader.getSystemClassLoader());
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull3() {
+        class S { }
+        ServiceLoader.load((Layer) null, S.class);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull4() {
+        ServiceLoader.load(Layer.empty(), null);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testLoadNull5() {
+        ServiceLoader.loadInstalled(null);
+    }
+
+    /**
+     * Create a custom Layer by resolving the given module names. The modules
+     * are located in the {@code ${test.classes}/modules} directory.
+     */
+    private Layer createCustomLayer(String... modules) {
+        Path dir = Paths.get(System.getProperty("test.classes", "."), "modules");
+        ModuleFinder finder = ModuleFinder.of(dir);
+        Set<String> roots = new HashSet<>();
+        Collections.addAll(roots, modules);
+        Layer bootLayer = Layer.boot();
+        Configuration parent = bootLayer.configuration();
+        Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), roots);
+        ClassLoader scl = ClassLoader.getSystemClassLoader();
+        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
+        assertTrue(layer.modules().size() == 1);
+        return layer;
+    }
+
+    private <E> List<E> collectAll(ServiceLoader<E> loader) {
+        List<E> list = new ArrayList<>();
+        Iterator<E> iterator = loader.iterator();
+        while (iterator.hasNext()) {
+            list.add(iterator.next());
+        }
+        return list;
+    }
+}
+
--- a/jdk/test/java/util/ServiceLoader/modules/MiscTests.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +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.
- *
- * 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.lang.reflect.Layer;
-import java.security.Provider;
-import java.util.ServiceLoader;
-
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
-/*
- * @test
- * @run testng MiscTests
- * @summary Basic test of ServiceLoader with modules
- */
-
-public class MiscTests {
-
-    @Test
-    public void testEmptyLayer() {
-        ServiceLoader<Provider> sl
-            = ServiceLoader.load(Layer.empty(), Provider.class);
-        assertFalse(sl.iterator().hasNext());
-    }
-
-    @Test(expectedExceptions = { NullPointerException.class })
-    public void testNullLayer() {
-        ServiceLoader.load(null, Provider.class);
-    }
-
-    @Test(expectedExceptions = { NullPointerException.class })
-    public void testNullService() {
-        ServiceLoader.load(Layer.empty(), null);
-    }
-
-}
--- a/jdk/test/java/util/ServiceLoader/modules/ServicesTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +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.
- *
- * 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.lang.module.Configuration;
-import java.lang.module.ModuleFinder;
-import java.lang.reflect.Layer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ServiceLoader;
-import java.util.Set;
-import javax.script.ScriptEngineFactory;
-
-import static jdk.testlibrary.ProcessTools.executeTestJava;
-
-import org.testng.annotations.BeforeTest;
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
-/**
- * @test
- * @library /lib/testlibrary
- * @modules java.scripting
- *          jdk.compiler
- * @build ServicesTest CompilerUtils jdk.testlibrary.*
- * @run testng ServicesTest
- * @summary Tests ServiceLoader to locate service providers on the module path
- *          and class path. Also tests ServiceLoader with a custom Layer.
- */
-
-@Test
-public class ServicesTest {
-
-    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 CLASSES_DIR = Paths.get("classes");
-    private static final Path MODS_DIR = Paths.get("mods");
-
-    // modules to compile to the module path
-    private static final String MODULES[] = { "test", "bananascript" };
-
-    // directories of classes to compile to the class path
-    private static final String CLASSES[] = { "pearscript" };
-
-    // resources to copy to the class path
-    private static final String RESOURCES[] = {
-        "pearscript/META-INF/services/javax.script.ScriptEngineFactory"
-    };
-
-
-    /**
-     * Compiles all modules and classes used by the test
-     */
-    @BeforeTest
-    public void setup() throws Exception {
-
-        // modules
-        for (String mn : MODULES ) {
-            Path src = SRC_DIR.resolve(mn);
-            Path mods = MODS_DIR.resolve(mn);
-            assertTrue(CompilerUtils.compile(src, mods));
-        }
-
-        // classes
-        for (String dir : CLASSES) {
-            Path src = SRC_DIR.resolve(dir);
-            assertTrue(CompilerUtils.compile(src, CLASSES_DIR));
-        }
-
-        // copy resources
-        for (String rn : RESOURCES) {
-            Path file = Paths.get(rn.replace('/', File.separatorChar));
-            Path source = SRC_DIR.resolve(file);
-
-            // drop directory to get a target of classes/META-INF/...
-            Path target = CLASSES_DIR.resolve(file.subpath(1, file.getNameCount()));
-
-            Files.createDirectories(target.getParent());
-            Files.copy(source, target);
-        }
-
-    }
-
-
-    /**
-     * Run test with --module-path.
-     *
-     * BananaScriptEngine should be found.
-     */
-    public void runWithModulePath() throws Exception {
-        int exitValue
-            = executeTestJava("--module-path", MODS_DIR.toString(),
-                              "--add-modules", "bananascript",
-                              "-m", "test/test.Main",
-                              "BananaScriptEngine")
-                .outputTo(System.out)
-                .errorTo(System.out)
-                .getExitValue();
-
-        assertTrue(exitValue == 0);
-    }
-
-
-    /**
-     * Run test with --module-path and -classpath.
-     *
-     * Both BananaScriptEngine and PearScriptEngine should be found
-     */
-    public void runWithModulePathAndClassPath() throws Exception {
-        int exitValue
-            = executeTestJava("--module-path", MODS_DIR.toString(),
-                              "-cp", CLASSES_DIR.toString(),
-                              "--add-modules", "bananascript",
-                              "-m", "test/test.Main",
-                              "BananaScriptEngine", "PearScriptEngine")
-                .outputTo(System.out)
-                .errorTo(System.out)
-                .getExitValue();
-
-        assertTrue(exitValue == 0);
-    }
-
-
-    /**
-     * Exercise ServiceLoader.load(Layer, Class).
-     */
-    public void testWithCustomLayer() throws Exception {
-
-        ServiceLoader<ScriptEngineFactory> sl;
-
-        // BananaScriptEngine should not be in the boot Layer
-        sl = ServiceLoader.load(Layer.boot(), ScriptEngineFactory.class);
-        assertTrue(find("BananaScriptEngine", sl) == null);
-
-        // create a custom Layer
-        ModuleFinder finder = ModuleFinder.of(MODS_DIR);
-        Layer bootLayer = Layer.boot();
-        Configuration parent = bootLayer.configuration();
-        Configuration cf
-            = parent.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of());
-        ClassLoader scl = ClassLoader.getSystemClassLoader();
-        Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
-
-        assertTrue(layer.findModule("bananascript").isPresent());
-        ClassLoader loader = layer.findLoader("bananascript");
-
-        sl = ServiceLoader.load(layer, ScriptEngineFactory.class);
-        ScriptEngineFactory factory = find("BananaScriptEngine", sl);
-        assertTrue(factory != null);
-        assertEquals(factory.getClass().getModule().getName(), "bananascript");
-        assertTrue(factory.getClass().getClassLoader() == loader);
-
-    }
-
-    /**
-     * Find the given scripting engine (by name) via the ScriptEngineFactory
-     * that ServiceLoader has found.
-     */
-    static ScriptEngineFactory find(String name,
-                                    ServiceLoader<ScriptEngineFactory> sl) {
-        for (ScriptEngineFactory factory : sl) {
-            if (factory.getEngineName().equals(name))
-                return factory;
-        }
-        return null;
-    }
-
-
-}
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/badreturntype/ProviderFactory.java	Thu Dec 01 21:39:49 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 p;
+
+/**
+ * A provider factory with a provider() method with a return type that is not
+ * p.Service
+ */
+
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    public static Object provider() {
+        throw new RuntimeException("Should not be called");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/ProviderFactory.java	Thu Dec 01 21:39:49 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+/**
+ * Not a provider factory because the class is not public.
+ */
+
+class ProviderFactory {
+    ProviderFactory() { }
+
+    public static Service provider() {
+        throw new RuntimeException("Should not be called");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/classnotpublic/Service.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/ProviderFactory.java	Thu Dec 01 21:39:49 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+/**
+ * Not a provider factory because the static provider() method is not public.
+ */
+
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    static Service provider() {
+        throw new RuntimeException("Should not be called");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/methodnotpublic/Service.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/ProviderFactory.java	Thu Dec 01 21:39:49 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 p;
+
+/**
+ * A provider factory that defines a public static provider method that returns
+ * null.
+ */
+
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    public static Service provider() {
+        return null;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/returnsnull/Service.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/ProviderFactory.java	Thu Dec 01 21:39:49 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package p;
+
+/**
+ * A provider factory that throws an exception.
+ */
+
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    public static Service provider() {
+        throw new RuntimeException();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badfactories/throwsexception/Service.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Provider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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 p;
+
+/**
+ * A provider class with a non-public constructor
+ */
+
+public class Provider implements Service {
+    Provider() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/ctornotpublic/Service.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notasubtype/Provider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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 p;
+
+/**
+ * A provider class that is not a subtype of Service.
+ */
+
+public class Provider {
+    Provider() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Provider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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 p;
+
+/**
+ * Provider class not public.
+ */
+
+class Provider implements Service {
+    public Provider() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/notpublic/Service.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Provider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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 p;
+
+/**
+ * A provider class with a constructor throws an exception.
+ */
+
+public class Provider {
+    public Provider() {
+        throw new RuntimeException();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/badproviders/throwsexception/Service.java	Thu Dec 01 21:39:49 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.
+ */
+
+package p;
+
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * 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 bananascript {
+    requires java.scripting;
+
+    provides javax.script.ScriptEngineFactory
+        with org.banana.BananaScriptEngineFactory;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScript.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, 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 org.banana;
+
+import java.io.Reader;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class BananaScript implements ScriptEngine {
+
+    @Override
+    public Object eval(String script, ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(String script, Bindings n) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object eval(Reader reader , Bindings n) {
+        throw new RuntimeException();
+    }
+    @Override
+    public void put(String key, Object value) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Object get(String key) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings getBindings(int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setBindings(Bindings bindings, int scope) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public Bindings createBindings() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptContext getContext() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public void setContext(ScriptContext context) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngineFactory getFactory() {
+        throw new RuntimeException();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/bananascript/org/banana/BananaScriptEngineFactory.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, 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 org.banana;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+
+public class BananaScriptEngineFactory implements ScriptEngineFactory {
+
+    static final BananaScriptEngineFactory INSTANCE  = new BananaScriptEngineFactory(null);
+
+    public BananaScriptEngineFactory() {
+        throw new RuntimeException("Should not be called");
+    }
+
+    private BananaScriptEngineFactory(Void param) { }
+
+    public static BananaScriptEngineFactory provider() {
+        return INSTANCE;
+    }
+
+    @Override
+    public String getEngineName() {
+        return "BananaScriptEngine";
+    }
+
+    @Override
+    public String getEngineVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public List<String> getExtensions() {
+        return Arrays.asList("banana");
+    }
+
+    @Override
+    public List<String> getMimeTypes() {
+        return Arrays.asList("application/x-bananascript");
+    }
+
+    @Override
+    public List<String> getNames() {
+        return Arrays.asList("BananaScript");
+    }
+
+    @Override
+    public String getLanguageName() {
+        return "BananaScript";
+    }
+
+    @Override
+    public String getLanguageVersion() {
+        return "1.0";
+    }
+
+    @Override
+    public Object getParameter(String key) {
+        return null;
+    }
+
+    @Override
+    public String getMethodCallSyntax(String obj, String m, String... args) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getOutputStatement(String toDisplay) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public String getProgram(String... statements) {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public ScriptEngine getScriptEngine() {
+        return new BananaScript();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,33 @@
+/*
+ * 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 module that provides an implementation of p.Service via a
+ * provider factory class.
+ */
+
+module test1 {
+    exports p;
+    provides p.Service with p.ProviderFactory;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/ProviderFactory.java	Thu Dec 01 21:39:49 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 p;
+
+/**
+ * Provider factory
+ */
+public class ProviderFactory {
+    ProviderFactory() { }
+
+    private static final Service INSTANCE = new Service() { };
+
+    public static Service provider() {
+        return INSTANCE;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test1/p/Service.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * 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 p;
+
+/**
+ * Service type
+ */
+public interface Service { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * 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 module that provides an implementation of p.Service.
+ */
+
+module test2 {
+    exports p;
+    provides p.Service with p.Provider;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Provider.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,32 @@
+/*
+ * 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 p;
+
+/**
+ * Provider type
+ */
+public class Provider implements Service {
+    public Provider() { }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/modules/test2/p/Service.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * 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 p;
+
+/**
+ * Service type
+ */
+public interface Service { }
--- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2014, 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 bananascript {
-    requires java.scripting;
-
-    provides javax.script.ScriptEngineFactory
-      with org.banana.BananaScriptEngineFactory;
-}
-
--- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2014, 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 org.banana;
-
-import java.io.Reader;
-import javax.script.Bindings;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
-
-public class BananaScript implements ScriptEngine {
-
-    @Override
-    public Object eval(String script, ScriptContext context) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(Reader reader , ScriptContext context) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(String script) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(Reader reader) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(String script, Bindings n) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object eval(Reader reader , Bindings n) {
-        throw new RuntimeException();
-    }
-    @Override
-    public void put(String key, Object value) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Object get(String key) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Bindings getBindings(int scope) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public void setBindings(Bindings bindings, int scope) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public Bindings createBindings() {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public ScriptContext getContext() {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public void setContext(ScriptContext context) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public ScriptEngineFactory getFactory() {
-        throw new RuntimeException();
-    }
-}
-
--- a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2014, 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 org.banana;
-
-import java.util.Arrays;
-import java.util.List;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
-
-public class BananaScriptEngineFactory implements ScriptEngineFactory {
-
-    @Override
-    public String getEngineName() {
-        return "BananaScriptEngine";
-    }
-
-    @Override
-    public String getEngineVersion() {
-        return "1.0";
-    }
-
-    @Override
-    public List<String> getExtensions() {
-        return Arrays.asList("banana");
-    }
-
-    @Override
-    public List<String> getMimeTypes() {
-        return Arrays.asList("application/x-bananascript");
-    }
-
-    @Override
-    public List<String> getNames() {
-        return Arrays.asList("BananaScript");
-    }
-
-    @Override
-    public String getLanguageName() {
-        return "BananaScript";
-    }
-
-    @Override
-    public String getLanguageVersion() {
-        return "1.0";
-    }
-
-    @Override
-    public Object getParameter(String key) {
-        return null;
-    }
-
-    @Override
-    public String getMethodCallSyntax(String obj, String m, String... args) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public String getOutputStatement(String toDisplay) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public String getProgram(String... statements) {
-        throw new RuntimeException();
-    }
-
-    @Override
-    public ScriptEngine getScriptEngine() {
-        return new BananaScript();
-    }
-}
--- a/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,6 +30,12 @@
 
 public class PearScriptEngineFactory implements ScriptEngineFactory {
 
+    public PearScriptEngineFactory() { }
+
+    public static PearScriptEngineFactory provider() {
+        throw new RuntimeException("Should not be called");
+    }
+
     @Override
     public String getEngineName() {
         return "PearScriptEngine";
--- a/jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2014, 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 java.scripting;
-
-    uses javax.script.ScriptEngineFactory;
-}
-
--- a/jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- *
- * 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.util.HashSet;
-import java.util.ServiceLoader;
-import java.util.Set;
-import javax.script.ScriptEngineFactory;
-
-public class Main {
-    public static void main(String[] args) {
-        Set<String> engines = new HashSet<>();
-        for (ScriptEngineFactory factory: ServiceLoader.load(ScriptEngineFactory.class)) {
-            System.out.format("loaded: %s%n" , factory.getEngineName());
-            engines.add(factory.getEngineName());
-        }
-
-        for (String engine: args) {
-            if (!engines.contains(engine))
-                throw new RuntimeException(engine + " not found");
-        }
-    }
-}
--- a/jdk/test/java/util/TreeMap/HeadTailTypeError.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/TreeMap/HeadTailTypeError.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,10 +22,10 @@
  */
 
 /*
-   @test
-   @bug 4251519 4251520
-   @summary indexOf and lastIndex of used to let you look outside the
-            valid range in the backing array
+ * @test
+ * @bug 4251519 4251520
+ * @summary indexOf and lastIndex of used to let you look outside the
+ *          valid range in the backing array
  */
 
 import java.util.*;
--- a/jdk/test/java/util/Vector/LastIndexOf.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/Vector/LastIndexOf.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,10 +22,10 @@
  */
 
 /*
-   @test
-   @bug 4271588
-   @summary Vector.lastIndex(Object, int) used to let you look outside the
-            valid range in the backing array
+ * @test
+ * @bug 4271588
+ * @summary Vector.lastIndex(Object, int) used to let you look outside the
+ *          valid range in the backing array
  */
 
 import java.util.*;
--- a/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/ArrayBlockingQueue/IteratorConsistency.java	Thu Dec 01 21:39:49 2016 +0000
@@ -42,23 +42,24 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Queue;
-import java.util.Random;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
 
 /*
  * @test
  * @bug 7014263
+ * @modules java.base/java.util.concurrent:open
  * @summary White box testing of ArrayBlockingQueue iterators.
  */
 
 /**
- * Highly coupled to the implementation of ArrayBlockingQueue.
+ * Tightly coupled to the implementation of ArrayBlockingQueue.
  * Uses reflection to inspect queue and iterator state.
  */
 @SuppressWarnings({"unchecked", "rawtypes"})
 public class IteratorConsistency {
-    final Random rnd = new Random();
+    final ThreadLocalRandom rnd = ThreadLocalRandom.current();
     final int CAPACITY = 20;
     Field itrsField;
     Field itemsField;
@@ -144,6 +145,10 @@
             check(!it.hasNext());
             check(isDetached(it));
         }
+        if (rnd.nextBoolean()) {
+            it.forEachRemaining(e -> { throw new AssertionError(); });
+            checkDetached(it);
+        }
         if (rnd.nextBoolean())
             try { it.next(); fail("should throw"); }
             catch (NoSuchElementException success) {}
--- a/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/BlockingQueue/LastElement.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 6215625 7161229
+ * @modules java.base/java.util.concurrent:open
  * @summary Check correct behavior when last element is removed.
  * @author Martin Buchholz
  */
--- a/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java	Thu Dec 01 21:39:49 2016 +0000
@@ -35,6 +35,8 @@
 /*
  * @test
  * @bug 6236036 6264015
+ * @modules java.base/java.util.concurrent:open
+ *          java.base/java.util.concurrent.locks:open
  * @summary Checks for a memory leak when a sequence of aborted timed
  * waits occur without a signal.  Uses the strategy of detecting
  * changes in the size of the object graph retained by a root object.
--- a/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java	Thu Dec 01 21:39:49 2016 +0000
@@ -34,6 +34,8 @@
 /*
  * @test
  * @bug 8054446 8137184 8137185
+ * @modules java.base/java.util.concurrent:open
+ *          java.base/java.util.concurrent.locks:open
  * @summary Regression test for memory leak in remove(Object)
  */
 
--- a/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/ConcurrentQueues/IteratorWeakConsistency.java	Thu Dec 01 21:39:49 2016 +0000
@@ -44,7 +44,6 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Queue;
-import java.util.Random;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentLinkedDeque;
@@ -52,10 +51,11 @@
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.LinkedTransferQueue;
+import java.util.concurrent.ThreadLocalRandom;
 
 @SuppressWarnings({"unchecked", "rawtypes"})
 public class IteratorWeakConsistency {
-    final Random rnd = new Random();
+    final ThreadLocalRandom rnd = ThreadLocalRandom.current();
 
     void test(String[] args) throws Throwable {
         test(new LinkedBlockingQueue());
@@ -72,6 +72,9 @@
         if (rnd.nextBoolean()) {
             check(!it.hasNext());
         }
+        if (rnd.nextBoolean()) {
+            it.forEachRemaining(e -> { throw new AssertionError(); });
+        }
         if (rnd.nextBoolean())
             try { it.next(); fail("should throw"); }
             catch (NoSuchElementException success) {}
--- a/jdk/test/java/util/concurrent/FutureTask/Throw.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/FutureTask/Throw.java	Thu Dec 01 21:39:49 2016 +0000
@@ -140,8 +140,8 @@
             catch (Throwable t) {
                 if (k.isAssignableFrom(t.getClass())) pass();
                 else unexpected(t);}}
-    @SuppressWarnings("unchecked") static <T extends Throwable>
-        void uncheckedThrow(Throwable t) throws T {
+    @SuppressWarnings("unchecked")
+    static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
         throw (T)t; // rely on vacuous cast
     }
 }
--- a/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/Phaser/PhaseOverflow.java	Thu Dec 01 21:39:49 2016 +0000
@@ -34,6 +34,7 @@
 
 /*
  * @test
+ * @modules java.base/java.util.concurrent:open
  * @summary Test Phaser phase integer overflow behavior
  */
 
--- a/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/ScheduledThreadPoolExecutor/ZeroCoreThreads.java	Thu Dec 01 21:39:49 2016 +0000
@@ -36,6 +36,7 @@
  * @bug 8022642 8065320 8129861
  * @summary Ensure relative sanity when zero core threads
  * @library /lib/testlibrary/
+ * @modules java.base/java.util.concurrent:open
  */
 
 import static java.util.concurrent.TimeUnit.HOURS;
--- a/jdk/test/java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java	Thu Dec 01 21:39:49 2016 +0000
@@ -247,7 +247,13 @@
                tg.activeCount() > 0)
             Thread.sleep(4);
         equal(tg.activeCount(), 0);
-        check(System.nanoTime() - t0 >= tpe.getKeepAliveTime(NANOSECONDS));
+
+        // The following assertion is almost always true, but may
+        // exceptionally not be during a transition from core count
+        // too high to allowCoreThreadTimeOut.  Users will never
+        // notice, and we accept the small loss of testability.
+        //
+        // check(System.nanoTime() - t0 >= tpe.getKeepAliveTime(NANOSECONDS));
 
         //report("idle", tpe);
 
--- a/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/ThreadPoolExecutor/ThrowingTasks.java	Thu Dec 01 21:39:49 2016 +0000
@@ -290,8 +290,8 @@
         try {realMain(args);} catch (Throwable t) {unexpected(t);}
         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
         if (failed > 0) throw new AssertionError("Some tests failed");}
-    @SuppressWarnings("unchecked") static <T extends Throwable>
-        void uncheckedThrow(Throwable t) throws T {
+    @SuppressWarnings("unchecked")
+    static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
         throw (T)t; // rely on vacuous cast
     }
 }
--- a/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/atomic/VMSupportsCS8.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 4992443 4994819
+ * @modules java.base/java.util.concurrent.atomic:open
  * @run main VMSupportsCS8
  * @summary Checks that the value of VMSupportsCS8 matches system properties.
  */
--- a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java	Thu Dec 01 21:39:49 2016 +0000
@@ -35,6 +35,7 @@
 /*
  * @test
  * @bug 8004138
+ * @modules java.base/java.util.concurrent:open
  * @summary Checks that ForkJoinTask thrown exceptions are not leaked.
  * This whitebox test is sensitive to forkjoin implementation details.
  */
--- a/jdk/test/java/util/concurrent/locks/Lock/FlakyMutex.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/locks/Lock/FlakyMutex.java	Thu Dec 01 21:39:49 2016 +0000
@@ -148,8 +148,8 @@
         try {realMain(args);} catch (Throwable t) {unexpected(t);}
         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
         if (failed > 0) throw new AssertionError("Some tests failed");}
-    @SuppressWarnings("unchecked") static <T extends Throwable>
-        void uncheckedThrow(Throwable t) throws T {
+    @SuppressWarnings("unchecked")
+    static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
         throw (T)t; // rely on vacuous cast
     }
 }
--- a/jdk/test/java/util/concurrent/tck/ArrayBlockingQueueTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ArrayBlockingQueueTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -38,6 +38,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Queue;
@@ -46,45 +47,78 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 
 public class ArrayBlockingQueueTest extends JSR166TestCase {
 
-    public static class Fair extends BlockingQueueTest {
-        protected BlockingQueue emptyCollection() {
-            return new ArrayBlockingQueue(SIZE, true);
-        }
-    }
-
-    public static class NonFair extends BlockingQueueTest {
-        protected BlockingQueue emptyCollection() {
-            return new ArrayBlockingQueue(SIZE, false);
-        }
-    }
-
     public static void main(String[] args) {
         main(suite(), args);
     }
 
     public static Test suite() {
-        return newTestSuite(ArrayBlockingQueueTest.class,
-                            new Fair().testSuite(),
-                            new NonFair().testSuite());
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ArrayBlockingQueue.class; }
+            public Collection emptyCollection() {
+                boolean fair = ThreadLocalRandom.current().nextBoolean();
+                return populatedQueue(0, SIZE, 2 * SIZE, fair);
+            }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
+
+        return newTestSuite(
+            ArrayBlockingQueueTest.class,
+            new Fair().testSuite(),
+            new NonFair().testSuite(),
+            CollectionTest.testSuite(new Implementation()));
+    }
+
+    public static class Fair extends BlockingQueueTest {
+        protected BlockingQueue emptyCollection() {
+            return populatedQueue(0, SIZE, 2 * SIZE, true);
+        }
+    }
+
+    public static class NonFair extends BlockingQueueTest {
+        protected BlockingQueue emptyCollection() {
+            return populatedQueue(0, SIZE, 2 * SIZE, false);
+        }
     }
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
-    private ArrayBlockingQueue<Integer> populatedQueue(int n) {
-        ArrayBlockingQueue<Integer> q = new ArrayBlockingQueue<Integer>(n);
+    static ArrayBlockingQueue<Integer> populatedQueue(int n) {
+        return populatedQueue(n, n, n, false);
+    }
+
+    /**
+     * Returns a new queue of given size containing consecutive
+     * Integers 0 ... n - 1, with given capacity range and fairness.
+     */
+    static ArrayBlockingQueue<Integer> populatedQueue(
+        int size, int minCapacity, int maxCapacity, boolean fair) {
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        int capacity = rnd.nextInt(minCapacity, maxCapacity + 1);
+        ArrayBlockingQueue<Integer> q = new ArrayBlockingQueue<>(capacity);
         assertTrue(q.isEmpty());
-        for (int i = 0; i < n; i++)
-            assertTrue(q.offer(new Integer(i)));
-        assertFalse(q.isEmpty());
-        assertEquals(0, q.remainingCapacity());
-        assertEquals(n, q.size());
+        // shuffle circular array elements so they wrap
+        {
+            int n = rnd.nextInt(capacity);
+            for (int i = 0; i < n; i++) q.add(42);
+            for (int i = 0; i < n; i++) q.remove();
+        }
+        for (int i = 0; i < size; i++)
+            assertTrue(q.offer((Integer) i));
+        assertEquals(size == 0, q.isEmpty());
+        assertEquals(capacity - size, q.remainingCapacity());
+        assertEquals(size, q.size());
+        if (size > 0)
+            assertEquals((Integer) 0, q.peek());
         return q;
     }
 
@@ -98,17 +132,25 @@
     /**
      * Constructor throws IAE if capacity argument nonpositive
      */
-    public void testConstructor2() {
-        try {
-            new ArrayBlockingQueue(0);
-            shouldThrow();
-        } catch (IllegalArgumentException success) {}
+    public void testConstructor_nonPositiveCapacity() {
+        for (int i : new int[] { 0, -1, Integer.MIN_VALUE }) {
+            try {
+                new ArrayBlockingQueue(i);
+                shouldThrow();
+            } catch (IllegalArgumentException success) {}
+            for (boolean fair : new boolean[] { true, false }) {
+                try {
+                    new ArrayBlockingQueue(i, fair);
+                    shouldThrow();
+                } catch (IllegalArgumentException success) {}
+            }
+        }
     }
 
     /**
      * Initializing from null Collection throws NPE
      */
-    public void testConstructor3() {
+    public void testConstructor_nullCollection() {
         try {
             new ArrayBlockingQueue(1, true, null);
             shouldThrow();
@@ -143,13 +185,13 @@
     /**
      * Initializing from too large collection throws IAE
      */
-    public void testConstructor6() {
-        Integer[] ints = new Integer[SIZE];
-        for (int i = 0; i < SIZE; ++i)
-            ints[i] = i;
-        Collection<Integer> elements = Arrays.asList(ints);
+    public void testConstructor_collectionTooLarge() {
+        // just barely fits - succeeds
+        new ArrayBlockingQueue(SIZE, false,
+                               Collections.nCopies(SIZE, ""));
         try {
-            new ArrayBlockingQueue(SIZE - 1, false, elements);
+            new ArrayBlockingQueue(SIZE - 1, false,
+                                   Collections.nCopies(SIZE, ""));
             shouldThrow();
         } catch (IllegalArgumentException success) {}
     }
@@ -171,12 +213,12 @@
      * Queue transitions from empty to full when elements added
      */
     public void testEmptyFull() {
-        ArrayBlockingQueue q = new ArrayBlockingQueue(2);
+        BlockingQueue q = populatedQueue(0, 2, 2, false);
         assertTrue(q.isEmpty());
         assertEquals(2, q.remainingCapacity());
         q.add(one);
         assertFalse(q.isEmpty());
-        q.add(two);
+        assertTrue(q.offer(two));
         assertFalse(q.isEmpty());
         assertEquals(0, q.remainingCapacity());
         assertFalse(q.offer(three));
@@ -186,15 +228,18 @@
      * remainingCapacity decreases on add, increases on remove
      */
     public void testRemainingCapacity() {
-        BlockingQueue q = populatedQueue(SIZE);
-        for (int i = 0; i < SIZE; ++i) {
-            assertEquals(i, q.remainingCapacity());
-            assertEquals(SIZE, q.size() + q.remainingCapacity());
+        int size = ThreadLocalRandom.current().nextInt(1, SIZE);
+        BlockingQueue q = populatedQueue(size, size, 2 * size, false);
+        int spare = q.remainingCapacity();
+        int capacity = spare + size;
+        for (int i = 0; i < size; i++) {
+            assertEquals(spare + i, q.remainingCapacity());
+            assertEquals(capacity, q.size() + q.remainingCapacity());
             assertEquals(i, q.remove());
         }
-        for (int i = 0; i < SIZE; ++i) {
-            assertEquals(SIZE - i, q.remainingCapacity());
-            assertEquals(SIZE, q.size() + q.remainingCapacity());
+        for (int i = 0; i < size; i++) {
+            assertEquals(capacity - i, q.remainingCapacity());
+            assertEquals(capacity, q.size() + q.remainingCapacity());
             assertTrue(q.add(i));
         }
     }
@@ -213,12 +258,10 @@
      */
     public void testAdd() {
         ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
-        for (int i = 0; i < SIZE; ++i) {
-            assertTrue(q.add(new Integer(i)));
-        }
+        for (int i = 0; i < SIZE; i++) assertTrue(q.add((Integer) i));
         assertEquals(0, q.remainingCapacity());
         try {
-            q.add(new Integer(SIZE));
+            q.add((Integer) SIZE);
             shouldThrow();
         } catch (IllegalStateException success) {}
     }
@@ -252,13 +295,17 @@
     /**
      * addAll throws ISE if not enough room
      */
-    public void testAddAll4() {
-        ArrayBlockingQueue q = new ArrayBlockingQueue(1);
-        Integer[] ints = new Integer[SIZE];
-        for (int i = 0; i < SIZE; ++i)
-            ints[i] = new Integer(i);
+    public void testAddAll_insufficientSpace() {
+        int size = ThreadLocalRandom.current().nextInt(1, SIZE);
+        ArrayBlockingQueue q = populatedQueue(0, size, size, false);
+        // Just fits:
+        q.addAll(populatedQueue(size, size, 2 * size, false));
+        assertEquals(0, q.remainingCapacity());
+        assertEquals(size, q.size());
+        assertEquals(0, q.peek());
         try {
-            q.addAll(Arrays.asList(ints));
+            q = populatedQueue(0, size, size, false);
+            q.addAll(Collections.nCopies(size + 1, 42));
             shouldThrow();
         } catch (IllegalStateException success) {}
     }
@@ -545,8 +592,10 @@
      * contains(x) reports true when elements added but not yet removed
      */
     public void testContains() {
-        ArrayBlockingQueue q = populatedQueue(SIZE);
-        for (int i = 0; i < SIZE; ++i) {
+        int size = ThreadLocalRandom.current().nextInt(1, SIZE);
+        ArrayBlockingQueue q = populatedQueue(size, size, 2 * size, false);
+        assertFalse(q.contains(null));
+        for (int i = 0; i < size; ++i) {
             assertTrue(q.contains(new Integer(i)));
             assertEquals(i, q.poll());
             assertFalse(q.contains(new Integer(i)));
@@ -557,11 +606,13 @@
      * clear removes all elements
      */
     public void testClear() {
-        ArrayBlockingQueue q = populatedQueue(SIZE);
+        int size = ThreadLocalRandom.current().nextInt(1, 5);
+        ArrayBlockingQueue q = populatedQueue(size, size, 2 * size, false);
+        int capacity = size + q.remainingCapacity();
         q.clear();
         assertTrue(q.isEmpty());
         assertEquals(0, q.size());
-        assertEquals(SIZE, q.remainingCapacity());
+        assertEquals(capacity, q.remainingCapacity());
         q.add(one);
         assertFalse(q.isEmpty());
         assertTrue(q.contains(one));
@@ -618,103 +669,75 @@
         }
     }
 
-    void checkToArray(ArrayBlockingQueue q) {
+    void checkToArray(ArrayBlockingQueue<Integer> q) {
         int size = q.size();
-        Object[] o = q.toArray();
-        assertEquals(size, o.length);
+        Object[] a1 = q.toArray();
+        assertEquals(size, a1.length);
+        Integer[] a2 = q.toArray(new Integer[0]);
+        assertEquals(size, a2.length);
+        Integer[] a3 = q.toArray(new Integer[Math.max(0, size - 1)]);
+        assertEquals(size, a3.length);
+        Integer[] a4 = new Integer[size];
+        assertSame(a4, q.toArray(a4));
+        Integer[] a5 = new Integer[size + 1];
+        Arrays.fill(a5, 42);
+        assertSame(a5, q.toArray(a5));
+        Integer[] a6 = new Integer[size + 2];
+        Arrays.fill(a6, 42);
+        assertSame(a6, q.toArray(a6));
+        Object[][] as = { a1, a2, a3, a4, a5, a6 };
+        for (Object[] a : as) {
+            if (a.length > size) assertNull(a[size]);
+            if (a.length > size + 1) assertEquals(42, a[size + 1]);
+        }
         Iterator it = q.iterator();
+        Integer s = q.peek();
         for (int i = 0; i < size; i++) {
             Integer x = (Integer) it.next();
-            assertEquals((Integer)o[0] + i, (int) x);
-            assertSame(o[i], x);
+            assertEquals(s + i, (int) x);
+            for (Object[] a : as)
+                assertSame(a1[i], x);
         }
     }
 
     /**
-     * toArray() contains all elements in FIFO order
+     * toArray() and toArray(a) contain all elements in FIFO order
      */
     public void testToArray() {
-        ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
-        for (int i = 0; i < SIZE; i++) {
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        final int size = rnd.nextInt(6);
+        final int capacity = Math.max(1, size + rnd.nextInt(size + 1));
+        ArrayBlockingQueue<Integer> q = new ArrayBlockingQueue<>(capacity);
+        for (int i = 0; i < size; i++) {
             checkToArray(q);
             q.add(i);
         }
         // Provoke wraparound
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray(q);
-            assertEquals(i, q.poll());
+        int added = size * 2;
+        for (int i = 0; i < added; i++) {
             checkToArray(q);
-            q.add(SIZE + i);
-        }
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray(q);
-            assertEquals(SIZE + i, q.poll());
+            assertEquals((Integer) i, q.poll());
+            q.add(size + i);
         }
-    }
-
-    void checkToArray2(ArrayBlockingQueue q) {
-        int size = q.size();
-        Integer[] a1 = (size == 0) ? null : new Integer[size - 1];
-        Integer[] a2 = new Integer[size];
-        Integer[] a3 = new Integer[size + 2];
-        if (size > 0) Arrays.fill(a1, 42);
-        Arrays.fill(a2, 42);
-        Arrays.fill(a3, 42);
-        Integer[] b1 = (size == 0) ? null : (Integer[]) q.toArray(a1);
-        Integer[] b2 = (Integer[]) q.toArray(a2);
-        Integer[] b3 = (Integer[]) q.toArray(a3);
-        assertSame(a2, b2);
-        assertSame(a3, b3);
-        Iterator it = q.iterator();
         for (int i = 0; i < size; i++) {
-            Integer x = (Integer) it.next();
-            assertSame(b1[i], x);
-            assertEquals(b1[0] + i, (int) x);
-            assertSame(b2[i], x);
-            assertSame(b3[i], x);
-        }
-        assertNull(a3[size]);
-        assertEquals(42, (int) a3[size + 1]);
-        if (size > 0) {
-            assertNotSame(a1, b1);
-            assertEquals(size, b1.length);
-            for (int i = 0; i < a1.length; i++) {
-                assertEquals(42, (int) a1[i]);
-            }
-        }
-    }
-
-    /**
-     * toArray(a) contains all elements in FIFO order
-     */
-    public void testToArray2() {
-        ArrayBlockingQueue q = new ArrayBlockingQueue(SIZE);
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            q.add(i);
-        }
-        // Provoke wraparound
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            assertEquals(i, q.poll());
-            checkToArray2(q);
-            q.add(SIZE + i);
-        }
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            assertEquals(SIZE + i, q.poll());
+            checkToArray(q);
+            assertEquals((Integer) (added + i), q.poll());
         }
     }
 
     /**
      * toArray(incompatible array type) throws ArrayStoreException
      */
-    public void testToArray1_BadArg() {
+    public void testToArray_incompatibleArrayType() {
         ArrayBlockingQueue q = populatedQueue(SIZE);
         try {
             q.toArray(new String[10]);
             shouldThrow();
         } catch (ArrayStoreException success) {}
+        try {
+            q.toArray(new String[0]);
+            shouldThrow();
+        } catch (ArrayStoreException success) {}
     }
 
     /**
@@ -943,8 +966,8 @@
      */
     public void testNeverContainsNull() {
         Collection<?>[] qs = {
-            new ArrayBlockingQueue<Object>(10),
-            populatedQueue(2),
+            populatedQueue(0, 1, 10, false),
+            populatedQueue(2, 2, 10, true),
         };
 
         for (Collection<?> q : qs) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/ArrayDeque8Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Spliterator;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class ArrayDeque8Test extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+
+    public static Test suite() {
+        return newTestSuite(ArrayDeque8Test.class);
+    }
+
+    /**
+     * Spliterator.getComparator always throws IllegalStateException
+     */
+    public void testSpliterator_getComparator() {
+        assertThrows(IllegalStateException.class,
+                     () -> new ArrayDeque().spliterator().getComparator());
+    }
+
+    /**
+     * Spliterator characteristics are as advertised
+     */
+    public void testSpliterator_characteristics() {
+        ArrayDeque q = new ArrayDeque();
+        Spliterator s = q.spliterator();
+        int characteristics = s.characteristics();
+        int required = Spliterator.NONNULL
+            | Spliterator.ORDERED
+            | Spliterator.SIZED
+            | Spliterator.SUBSIZED;
+        assertEquals(required, characteristics & required);
+        assertTrue(s.hasCharacteristics(required));
+        assertEquals(0, characteristics
+                     & (Spliterator.CONCURRENT
+                        | Spliterator.DISTINCT
+                        | Spliterator.IMMUTABLE
+                        | Spliterator.SORTED));
+    }
+
+    /**
+     * Handle capacities near Integer.MAX_VALUE.
+     * ant -Dvmoptions='-Xms28g -Xmx28g' -Djsr166.expensiveTests=true -Djsr166.tckTestClass=ArrayDeque8Test -Djsr166.methodFilter=testHugeCapacity tck
+     */
+    public void testHugeCapacity() {
+        if (! (testImplementationDetails
+               && expensiveTests
+               && Runtime.getRuntime().maxMemory() > 24L * (1 << 30)))
+            return;
+
+        final Integer e = 42;
+        final int maxArraySize = Integer.MAX_VALUE - 8;
+
+        assertThrows(OutOfMemoryError.class,
+                     () -> new ArrayDeque(Integer.MAX_VALUE));
+
+        {
+            ArrayDeque q = new ArrayDeque(maxArraySize - 1);
+            assertEquals(0, q.size());
+            assertTrue(q.isEmpty());
+            q = null;
+        }
+
+        {
+            ArrayDeque q = new ArrayDeque();
+            assertTrue(q.addAll(Collections.nCopies(maxArraySize - 3, e)));
+            assertEquals(e, q.peekFirst());
+            assertEquals(e, q.peekLast());
+            assertEquals(maxArraySize - 3, q.size());
+            q.addFirst((Integer) 0);
+            q.addLast((Integer) 1);
+            assertEquals((Integer) 0, q.peekFirst());
+            assertEquals((Integer) 1, q.peekLast());
+            assertEquals(maxArraySize - 1, q.size());
+
+            ArrayDeque qq = q;
+            ArrayDeque smallish = new ArrayDeque(
+                Collections.nCopies(Integer.MAX_VALUE - q.size() + 1, e));
+            assertThrows(
+                IllegalStateException.class,
+                () -> qq.addAll(qq),
+                () -> qq.addAll(smallish),
+                () -> smallish.addAll(qq));
+        }
+    }
+
+}
--- a/jdk/test/java/util/concurrent/tck/ArrayDequeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ArrayDequeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,19 +26,22 @@
  * However, the following notice accompanied the original version of this
  * file:
  *
- * Written by Doug Lea with assistance from members of JCP JSR-166
- * Expert Group and released to the public domain, as explained at
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 import java.util.ArrayDeque;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Queue;
 import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -49,20 +52,60 @@
     }
 
     public static Test suite() {
-        return new TestSuite(ArrayDequeTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ArrayDeque.class; }
+            public Collection emptyCollection() { return populatedDeque(0); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return false; }
+        }
+        return newTestSuite(ArrayDequeTest.class,
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new deque of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
-    private ArrayDeque<Integer> populatedDeque(int n) {
-        ArrayDeque<Integer> q = new ArrayDeque<Integer>();
+    private static ArrayDeque<Integer> populatedDeque(int n) {
+        // Randomize various aspects of memory layout, including
+        // capacity slop and wraparound.
+        final ArrayDeque<Integer> q;
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        switch (rnd.nextInt(6)) {
+        case 0: q = new ArrayDeque<Integer>();      break;
+        case 1: q = new ArrayDeque<Integer>(0);     break;
+        case 2: q = new ArrayDeque<Integer>(1);     break;
+        case 3: q = new ArrayDeque<Integer>(Math.max(0, n - 1)); break;
+        case 4: q = new ArrayDeque<Integer>(n);     break;
+        case 5: q = new ArrayDeque<Integer>(n + 1); break;
+        default: throw new AssertionError();
+        }
+        switch (rnd.nextInt(3)) {
+        case 0:
+            q.addFirst(42);
+            assertEquals((Integer) 42, q.removeLast());
+            break;
+        case 1:
+            q.addLast(42);
+            assertEquals((Integer) 42, q.removeFirst());
+            break;
+        case 2: /* do nothing */ break;
+        default: throw new AssertionError();
+        }
         assertTrue(q.isEmpty());
-        for (int i = 0; i < n; ++i)
-            assertTrue(q.offerLast(new Integer(i)));
-        assertFalse(q.isEmpty());
+        if (rnd.nextBoolean())
+            for (int i = 0; i < n; i++)
+                assertTrue(q.offerLast((Integer) i));
+        else
+            for (int i = n; --i >= 0; )
+                q.addFirst((Integer) i);
         assertEquals(n, q.size());
+        if (n > 0) {
+            assertFalse(q.isEmpty());
+            assertEquals((Integer) 0, q.peekFirst());
+            assertEquals((Integer) (n - 1), q.peekLast());
+        }
         return q;
     }
 
@@ -556,30 +599,48 @@
      * removeFirstOccurrence(x) removes x and returns true if present
      */
     public void testRemoveFirstOccurrence() {
-        ArrayDeque q = populatedDeque(SIZE);
+        Deque<Integer> q = populatedDeque(SIZE);
+        assertFalse(q.removeFirstOccurrence(null));
         for (int i = 1; i < SIZE; i += 2) {
-            assertTrue(q.removeFirstOccurrence(new Integer(i)));
+            assertTrue(q.removeFirstOccurrence(i));
+            assertFalse(q.contains(i));
         }
         for (int i = 0; i < SIZE; i += 2) {
-            assertTrue(q.removeFirstOccurrence(new Integer(i)));
-            assertFalse(q.removeFirstOccurrence(new Integer(i + 1)));
+            assertTrue(q.removeFirstOccurrence(i));
+            assertFalse(q.removeFirstOccurrence(i + 1));
+            assertFalse(q.contains(i));
+            assertFalse(q.contains(i + 1));
         }
         assertTrue(q.isEmpty());
+        assertFalse(q.removeFirstOccurrence(null));
+        assertFalse(q.removeFirstOccurrence(42));
+        q = new ArrayDeque();
+        assertFalse(q.removeFirstOccurrence(null));
+        assertFalse(q.removeFirstOccurrence(42));
     }
 
     /**
      * removeLastOccurrence(x) removes x and returns true if present
      */
     public void testRemoveLastOccurrence() {
-        ArrayDeque q = populatedDeque(SIZE);
+        Deque<Integer> q = populatedDeque(SIZE);
+        assertFalse(q.removeLastOccurrence(null));
         for (int i = 1; i < SIZE; i += 2) {
-            assertTrue(q.removeLastOccurrence(new Integer(i)));
+            assertTrue(q.removeLastOccurrence(i));
+            assertFalse(q.contains(i));
         }
         for (int i = 0; i < SIZE; i += 2) {
-            assertTrue(q.removeLastOccurrence(new Integer(i)));
-            assertFalse(q.removeLastOccurrence(new Integer(i + 1)));
+            assertTrue(q.removeLastOccurrence(i));
+            assertFalse(q.removeLastOccurrence(i + 1));
+            assertFalse(q.contains(i));
+            assertFalse(q.contains(i + 1));
         }
         assertTrue(q.isEmpty());
+        assertFalse(q.removeLastOccurrence(null));
+        assertFalse(q.removeLastOccurrence(42));
+        q = new ArrayDeque();
+        assertFalse(q.removeLastOccurrence(null));
+        assertFalse(q.removeLastOccurrence(42));
     }
 
     /**
@@ -652,89 +713,57 @@
         }
     }
 
-    void checkToArray(ArrayDeque q) {
+    void checkToArray(ArrayDeque<Integer> q) {
         int size = q.size();
-        Object[] o = q.toArray();
-        assertEquals(size, o.length);
+        Object[] a1 = q.toArray();
+        assertEquals(size, a1.length);
+        Integer[] a2 = q.toArray(new Integer[0]);
+        assertEquals(size, a2.length);
+        Integer[] a3 = q.toArray(new Integer[Math.max(0, size - 1)]);
+        assertEquals(size, a3.length);
+        Integer[] a4 = new Integer[size];
+        assertSame(a4, q.toArray(a4));
+        Integer[] a5 = new Integer[size + 1];
+        Arrays.fill(a5, 42);
+        assertSame(a5, q.toArray(a5));
+        Integer[] a6 = new Integer[size + 2];
+        Arrays.fill(a6, 42);
+        assertSame(a6, q.toArray(a6));
+        Object[][] as = { a1, a2, a3, a4, a5, a6 };
+        for (Object[] a : as) {
+            if (a.length > size) assertNull(a[size]);
+            if (a.length > size + 1) assertEquals(42, a[size + 1]);
+        }
         Iterator it = q.iterator();
+        Integer s = q.peekFirst();
         for (int i = 0; i < size; i++) {
             Integer x = (Integer) it.next();
-            assertEquals((Integer)o[0] + i, (int) x);
-            assertSame(o[i], x);
+            assertEquals(s + i, (int) x);
+            for (Object[] a : as)
+                assertSame(a1[i], x);
         }
     }
 
     /**
-     * toArray() contains all elements in FIFO order
+     * toArray() and toArray(a) contain all elements in FIFO order
      */
     public void testToArray() {
-        ArrayDeque q = new ArrayDeque();
-        for (int i = 0; i < SIZE; i++) {
+        final int size = ThreadLocalRandom.current().nextInt(10);
+        ArrayDeque<Integer> q = new ArrayDeque<>(size);
+        for (int i = 0; i < size; i++) {
             checkToArray(q);
             q.addLast(i);
         }
         // Provoke wraparound
-        for (int i = 0; i < SIZE; i++) {
+        int added = size * 2;
+        for (int i = 0; i < added; i++) {
             checkToArray(q);
-            assertEquals(i, q.poll());
-            q.addLast(SIZE + i);
-        }
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray(q);
-            assertEquals(SIZE + i, q.poll());
+            assertEquals((Integer) i, q.poll());
+            q.addLast(size + i);
         }
-    }
-
-    void checkToArray2(ArrayDeque q) {
-        int size = q.size();
-        Integer[] a1 = (size == 0) ? null : new Integer[size - 1];
-        Integer[] a2 = new Integer[size];
-        Integer[] a3 = new Integer[size + 2];
-        if (size > 0) Arrays.fill(a1, 42);
-        Arrays.fill(a2, 42);
-        Arrays.fill(a3, 42);
-        Integer[] b1 = (size == 0) ? null : (Integer[]) q.toArray(a1);
-        Integer[] b2 = (Integer[]) q.toArray(a2);
-        Integer[] b3 = (Integer[]) q.toArray(a3);
-        assertSame(a2, b2);
-        assertSame(a3, b3);
-        Iterator it = q.iterator();
         for (int i = 0; i < size; i++) {
-            Integer x = (Integer) it.next();
-            assertSame(b1[i], x);
-            assertEquals(b1[0] + i, (int) x);
-            assertSame(b2[i], x);
-            assertSame(b3[i], x);
-        }
-        assertNull(a3[size]);
-        assertEquals(42, (int) a3[size + 1]);
-        if (size > 0) {
-            assertNotSame(a1, b1);
-            assertEquals(size, b1.length);
-            for (int i = 0; i < a1.length; i++) {
-                assertEquals(42, (int) a1[i]);
-            }
-        }
-    }
-
-    /**
-     * toArray(a) contains all elements in FIFO order
-     */
-    public void testToArray2() {
-        ArrayDeque q = new ArrayDeque();
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            q.addLast(i);
-        }
-        // Provoke wraparound
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            assertEquals(i, q.poll());
-            q.addLast(SIZE + i);
-        }
-        for (int i = 0; i < SIZE; i++) {
-            checkToArray2(q);
-            assertEquals(SIZE + i, q.poll());
+            checkToArray(q);
+            assertEquals((Integer) (added + i), q.poll());
         }
     }
 
@@ -753,13 +782,17 @@
     /**
      * toArray(incompatible array type) throws ArrayStoreException
      */
-    public void testToArray1_BadArg() {
+    public void testToArray_incompatibleArrayType() {
         ArrayDeque l = new ArrayDeque();
         l.add(new Integer(5));
         try {
             l.toArray(new String[10]);
             shouldThrow();
         } catch (ArrayStoreException success) {}
+        try {
+            l.toArray(new String[0]);
+            shouldThrow();
+        } catch (ArrayStoreException success) {}
     }
 
     /**
@@ -917,6 +950,25 @@
         assertNotSame(y, x);
         assertEquals(x.size(), y.size());
         assertEquals(x.toString(), y.toString());
+        assertEquals(Arrays.toString(x.toArray()), Arrays.toString(y.toArray()));
+        assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+        while (!x.isEmpty()) {
+            assertFalse(y.isEmpty());
+            assertEquals(x.remove(), y.remove());
+        }
+        assertTrue(y.isEmpty());
+    }
+
+    /**
+     * A cloned deque has same elements in same order
+     */
+    public void testClone() throws Exception {
+        ArrayDeque<Integer> x = populatedDeque(SIZE);
+        ArrayDeque<Integer> y = x.clone();
+
+        assertNotSame(y, x);
+        assertEquals(x.size(), y.size());
+        assertEquals(x.toString(), y.toString());
         assertTrue(Arrays.equals(x.toArray(), y.toArray()));
         while (!x.isEmpty()) {
             assertFalse(y.isEmpty());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/ArrayListTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class ArrayListTest extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+
+    public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ArrayList.class; }
+            public List emptyCollection() { return new ArrayList(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return true; }
+        }
+        class SubListImplementation extends Implementation {
+            public List emptyCollection() {
+                return super.emptyCollection().subList(0, 0);
+            }
+        }
+        return newTestSuite(
+                // ArrayListTest.class,
+                CollectionTest.testSuite(new Implementation()),
+                CollectionTest.testSuite(new SubListImplementation()));
+    }
+
+}
--- a/jdk/test/java/util/concurrent/tck/Atomic8Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/Atomic8Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -45,6 +45,9 @@
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
+/**
+ * Tests of atomic class methods accepting lambdas introduced in JDK8.
+ */
 public class Atomic8Test extends JSR166TestCase {
 
     public static void main(String[] args) {
@@ -54,30 +57,25 @@
         return new TestSuite(Atomic8Test.class);
     }
 
-    /*
-     * Tests of atomic class methods accepting lambdas
-     * introduced in JDK8.
-     */
-
     static long addLong17(long x) { return x + 17; }
     static int addInt17(int x) { return x + 17; }
     static Integer addInteger17(Integer x) {
-        return new Integer(x.intValue() + 17);
+        return x.intValue() + 17;
     }
     static Integer sumInteger(Integer x, Integer y) {
-        return new Integer(x.intValue() + y.intValue());
+        return x.intValue() + y.intValue();
     }
 
     volatile long aLongField;
     volatile int anIntField;
     volatile Integer anIntegerField;
 
-    AtomicLongFieldUpdater aLongFieldUpdater() {
+    AtomicLongFieldUpdater<Atomic8Test> aLongFieldUpdater() {
         return AtomicLongFieldUpdater.newUpdater
             (Atomic8Test.class, "aLongField");
     }
 
-    AtomicIntegerFieldUpdater anIntFieldUpdater() {
+    AtomicIntegerFieldUpdater<Atomic8Test> anIntFieldUpdater() {
         return AtomicIntegerFieldUpdater.newUpdater
             (Atomic8Test.class, "anIntField");
     }
@@ -180,9 +178,9 @@
      */
     public void testReferenceGetAndUpdate() {
         AtomicReference<Integer> a = new AtomicReference<>(one);
-        assertEquals(new Integer(1), a.getAndUpdate(Atomic8Test::addInteger17));
-        assertEquals(new Integer(18), a.getAndUpdate(Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get());
+        assertEquals((Integer) 1, a.getAndUpdate(Atomic8Test::addInteger17));
+        assertEquals((Integer) 18, a.getAndUpdate(Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get());
     }
 
     /**
@@ -191,9 +189,9 @@
      */
     public void testReferenceUpdateAndGet() {
         AtomicReference<Integer> a = new AtomicReference<>(one);
-        assertEquals(new Integer(18), a.updateAndGet(Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.updateAndGet(Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get());
+        assertEquals((Integer) 18, a.updateAndGet(Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.updateAndGet(Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get());
     }
 
     /**
@@ -202,9 +200,9 @@
      */
     public void testReferenceGetAndAccumulate() {
         AtomicReference<Integer> a = new AtomicReference<>(one);
-        assertEquals(new Integer(1), a.getAndAccumulate(2, Atomic8Test::sumInteger));
-        assertEquals(new Integer(3), a.getAndAccumulate(3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(6), a.get());
+        assertEquals((Integer) 1, a.getAndAccumulate(2, Atomic8Test::sumInteger));
+        assertEquals((Integer) 3, a.getAndAccumulate(3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 6, a.get());
     }
 
     /**
@@ -213,9 +211,9 @@
      */
     public void testReferenceAccumulateAndGet() {
         AtomicReference<Integer> a = new AtomicReference<>(one);
-        assertEquals(new Integer(7), a.accumulateAndGet(6, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.accumulateAndGet(3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.get());
+        assertEquals((Integer) 7, a.accumulateAndGet(6, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.accumulateAndGet(3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.get());
     }
 
     /**
@@ -320,9 +318,9 @@
     public void testReferenceArrayGetAndUpdate() {
         AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
         a.set(0, one);
-        assertEquals(new Integer(1), a.getAndUpdate(0, Atomic8Test::addInteger17));
-        assertEquals(new Integer(18), a.getAndUpdate(0, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get(0));
+        assertEquals((Integer) 1, a.getAndUpdate(0, Atomic8Test::addInteger17));
+        assertEquals((Integer) 18, a.getAndUpdate(0, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get(0));
     }
 
     /**
@@ -332,8 +330,8 @@
     public void testReferenceArrayUpdateAndGet() {
         AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
         a.set(0, one);
-        assertEquals(new Integer(18), a.updateAndGet(0, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.updateAndGet(0, Atomic8Test::addInteger17));
+        assertEquals((Integer) 18, a.updateAndGet(0, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.updateAndGet(0, Atomic8Test::addInteger17));
     }
 
     /**
@@ -343,9 +341,9 @@
     public void testReferenceArrayGetAndAccumulate() {
         AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
         a.set(0, one);
-        assertEquals(new Integer(1), a.getAndAccumulate(0, 2, Atomic8Test::sumInteger));
-        assertEquals(new Integer(3), a.getAndAccumulate(0, 3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(6), a.get(0));
+        assertEquals((Integer) 1, a.getAndAccumulate(0, 2, Atomic8Test::sumInteger));
+        assertEquals((Integer) 3, a.getAndAccumulate(0, 3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 6, a.get(0));
     }
 
     /**
@@ -355,8 +353,8 @@
     public void testReferenceArrayAccumulateAndGet() {
         AtomicReferenceArray<Integer> a = new AtomicReferenceArray<Integer>(1);
         a.set(0, one);
-        assertEquals(new Integer(7), a.accumulateAndGet(0, 6, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.accumulateAndGet(0, 3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 7, a.accumulateAndGet(0, 6, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.accumulateAndGet(0, 3, Atomic8Test::sumInteger));
     }
 
     /**
@@ -470,10 +468,10 @@
     public void testReferenceFieldUpdaterGetAndUpdate() {
         AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
         a.set(this, one);
-        assertEquals(new Integer(1), a.getAndUpdate(this, Atomic8Test::addInteger17));
-        assertEquals(new Integer(18), a.getAndUpdate(this, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get(this));
-        assertEquals(new Integer(35), anIntegerField);
+        assertEquals((Integer) 1, a.getAndUpdate(this, Atomic8Test::addInteger17));
+        assertEquals((Integer) 18, a.getAndUpdate(this, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get(this));
+        assertEquals((Integer) 35, anIntegerField);
     }
 
     /**
@@ -483,10 +481,10 @@
     public void testReferenceFieldUpdaterUpdateAndGet() {
         AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
         a.set(this, one);
-        assertEquals(new Integer(18), a.updateAndGet(this, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.updateAndGet(this, Atomic8Test::addInteger17));
-        assertEquals(new Integer(35), a.get(this));
-        assertEquals(new Integer(35), anIntegerField);
+        assertEquals((Integer) 18, a.updateAndGet(this, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.updateAndGet(this, Atomic8Test::addInteger17));
+        assertEquals((Integer) 35, a.get(this));
+        assertEquals((Integer) 35, anIntegerField);
     }
 
     /**
@@ -496,10 +494,10 @@
     public void testReferenceFieldUpdaterGetAndAccumulate() {
         AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
         a.set(this, one);
-        assertEquals(new Integer(1), a.getAndAccumulate(this, 2, Atomic8Test::sumInteger));
-        assertEquals(new Integer(3), a.getAndAccumulate(this, 3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(6), a.get(this));
-        assertEquals(new Integer(6), anIntegerField);
+        assertEquals((Integer) 1, a.getAndAccumulate(this, 2, Atomic8Test::sumInteger));
+        assertEquals((Integer) 3, a.getAndAccumulate(this, 3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 6, a.get(this));
+        assertEquals((Integer) 6, anIntegerField);
     }
 
     /**
@@ -509,10 +507,10 @@
     public void testReferenceFieldUpdaterAccumulateAndGet() {
         AtomicReferenceFieldUpdater<Atomic8Test,Integer> a = anIntegerFieldUpdater();
         a.set(this, one);
-        assertEquals(new Integer(7), a.accumulateAndGet(this, 6, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.accumulateAndGet(this, 3, Atomic8Test::sumInteger));
-        assertEquals(new Integer(10), a.get(this));
-        assertEquals(new Integer(10), anIntegerField);
+        assertEquals((Integer) 7, a.accumulateAndGet(this, 6, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.accumulateAndGet(this, 3, Atomic8Test::sumInteger));
+        assertEquals((Integer) 10, a.get(this));
+        assertEquals((Integer) 10, anIntegerField);
     }
 
     /**
@@ -530,9 +528,6 @@
             () -> aLongFieldUpdater().getAndUpdate(this, null),
             () -> anIntFieldUpdater().getAndUpdate(this, null),
             () -> anIntegerFieldUpdater().getAndUpdate(this, null),
-            ////() -> aLongFieldUpdater().getAndUpdate(null, Atomic8Test::addLong17),
-            ////() -> anIntFieldUpdater().getAndUpdate(null, Atomic8Test::addInt17),
-            ////() -> anIntegerFieldUpdater().getAndUpdate(null, Atomic8Test::addInteger17),
         };
         assertThrows(NullPointerException.class, throwingActions);
     }
@@ -593,4 +588,40 @@
         assertThrows(NullPointerException.class, throwingActions);
     }
 
+    /**
+     * Object arguments for parameters of type T that are not
+     * instances of the class passed to the newUpdater call will
+     * result in a ClassCastException being thrown.
+     */
+    public void testFieldUpdaters_ClassCastException() {
+        // Use raw types to allow passing wrong object type, provoking CCE
+        final AtomicLongFieldUpdater longUpdater = aLongFieldUpdater();
+        final AtomicIntegerFieldUpdater intUpdater = anIntFieldUpdater();
+        final AtomicReferenceFieldUpdater refUpdater = anIntegerFieldUpdater();
+        final Object obj = new Object();
+        for (Object x : new Object[]{ new Object(), null }) {
+            Runnable[] throwingActions = {
+                () -> longUpdater.get(x),
+                () -> intUpdater.get(x),
+                () -> refUpdater.get(x),
+
+                () -> longUpdater.set(x, 17L),
+                () -> intUpdater.set(x, 17),
+                () -> refUpdater.set(x, (Integer) 17),
+
+                () -> longUpdater.addAndGet(x, 17L),
+                () -> intUpdater.addAndGet(x, 17),
+
+                () -> longUpdater.getAndUpdate(x, y -> y),
+                () -> intUpdater.getAndUpdate(x, y -> y),
+                () -> refUpdater.getAndUpdate(x, y -> y),
+
+                () -> longUpdater.compareAndSet(x, 17L, 42L),
+                () -> intUpdater.compareAndSet(x, 17, 42),
+                () -> refUpdater.compareAndSet(x, (Integer) 17, (Integer) 42),
+            };
+            assertThrows(ClassCastException.class, throwingActions);
+        }
+    }
+
 }
--- a/jdk/test/java/util/concurrent/tck/Collection8Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/Collection8Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -32,18 +32,35 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.concurrent.BlockingDeque;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
+import java.util.concurrent.Phaser;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 import junit.framework.Test;
 
@@ -66,16 +83,422 @@
                                       impl);
     }
 
+    Object bomb() {
+        return new Object() {
+                public boolean equals(Object x) { throw new AssertionError(); }
+                public int hashCode() { throw new AssertionError(); }
+            };
+    }
+
+    /** Checks properties of empty collections. */
+    public void testEmptyMeansEmpty() throws Throwable {
+        Collection c = impl.emptyCollection();
+        emptyMeansEmpty(c);
+
+        if (c instanceof java.io.Serializable) {
+            try {
+                emptyMeansEmpty(serialClonePossiblyFailing(c));
+            } catch (java.io.NotSerializableException ex) {
+                // excusable when we have a serializable wrapper around
+                // a non-serializable collection, as can happen with:
+                // Vector.subList() => wrapped AbstractList$RandomAccessSubList
+                if (testImplementationDetails
+                    && (! c.getClass().getName().matches(
+                                "java.util.Collections.*")))
+                    throw ex;
+            }
+        }
+
+        Collection clone = cloneableClone(c);
+        if (clone != null)
+            emptyMeansEmpty(clone);
+    }
+
+    void emptyMeansEmpty(Collection c) throws InterruptedException {
+        assertTrue(c.isEmpty());
+        assertEquals(0, c.size());
+        assertEquals("[]", c.toString());
+        {
+            Object[] a = c.toArray();
+            assertEquals(0, a.length);
+            assertSame(Object[].class, a.getClass());
+        }
+        {
+            Object[] a = new Object[0];
+            assertSame(a, c.toArray(a));
+        }
+        {
+            Integer[] a = new Integer[0];
+            assertSame(a, c.toArray(a));
+        }
+        {
+            Integer[] a = { 1, 2, 3};
+            assertSame(a, c.toArray(a));
+            assertNull(a[0]);
+            assertSame(2, a[1]);
+            assertSame(3, a[2]);
+        }
+        assertIteratorExhausted(c.iterator());
+        Consumer alwaysThrows = e -> { throw new AssertionError(); };
+        c.forEach(alwaysThrows);
+        c.iterator().forEachRemaining(alwaysThrows);
+        c.spliterator().forEachRemaining(alwaysThrows);
+        assertFalse(c.spliterator().tryAdvance(alwaysThrows));
+        if (c.spliterator().hasCharacteristics(Spliterator.SIZED))
+            assertEquals(0, c.spliterator().estimateSize());
+        assertFalse(c.contains(bomb()));
+        assertFalse(c.remove(bomb()));
+        if (c instanceof Queue) {
+            Queue q = (Queue) c;
+            assertNull(q.peek());
+            assertNull(q.poll());
+        }
+        if (c instanceof Deque) {
+            Deque d = (Deque) c;
+            assertNull(d.peekFirst());
+            assertNull(d.peekLast());
+            assertNull(d.pollFirst());
+            assertNull(d.pollLast());
+            assertIteratorExhausted(d.descendingIterator());
+            d.descendingIterator().forEachRemaining(alwaysThrows);
+            assertFalse(d.removeFirstOccurrence(bomb()));
+            assertFalse(d.removeLastOccurrence(bomb()));
+        }
+        if (c instanceof BlockingQueue) {
+            BlockingQueue q = (BlockingQueue) c;
+            assertNull(q.poll(0L, MILLISECONDS));
+        }
+        if (c instanceof BlockingDeque) {
+            BlockingDeque q = (BlockingDeque) c;
+            assertNull(q.pollFirst(0L, MILLISECONDS));
+            assertNull(q.pollLast(0L, MILLISECONDS));
+        }
+    }
+
+    public void testNullPointerExceptions() throws InterruptedException {
+        Collection c = impl.emptyCollection();
+        assertThrows(
+            NullPointerException.class,
+            () -> c.addAll(null),
+            () -> c.containsAll(null),
+            () -> c.retainAll(null),
+            () -> c.removeAll(null),
+            () -> c.removeIf(null),
+            () -> c.forEach(null),
+            () -> c.iterator().forEachRemaining(null),
+            () -> c.spliterator().forEachRemaining(null),
+            () -> c.spliterator().tryAdvance(null),
+            () -> c.toArray(null));
+
+        if (!impl.permitsNulls()) {
+            assertThrows(
+                NullPointerException.class,
+                () -> c.add(null));
+        }
+        if (!impl.permitsNulls() && c instanceof Queue) {
+            Queue q = (Queue) c;
+            assertThrows(
+                NullPointerException.class,
+                () -> q.offer(null));
+        }
+        if (!impl.permitsNulls() && c instanceof Deque) {
+            Deque d = (Deque) c;
+            assertThrows(
+                NullPointerException.class,
+                () -> d.addFirst(null),
+                () -> d.addLast(null),
+                () -> d.offerFirst(null),
+                () -> d.offerLast(null),
+                () -> d.push(null),
+                () -> d.descendingIterator().forEachRemaining(null));
+        }
+        if (c instanceof BlockingQueue) {
+            BlockingQueue q = (BlockingQueue) c;
+            assertThrows(
+                NullPointerException.class,
+                () -> {
+                    try { q.offer(null, 1L, HOURS); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }},
+                () -> {
+                    try { q.put(null); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }});
+        }
+        if (c instanceof BlockingDeque) {
+            BlockingDeque q = (BlockingDeque) c;
+            assertThrows(
+                NullPointerException.class,
+                () -> {
+                    try { q.offerFirst(null, 1L, HOURS); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }},
+                () -> {
+                    try { q.offerLast(null, 1L, HOURS); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }},
+                () -> {
+                    try { q.putFirst(null); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }},
+                () -> {
+                    try { q.putLast(null); }
+                    catch (InterruptedException ex) {
+                        throw new AssertionError(ex);
+                    }});
+        }
+    }
+
+    public void testNoSuchElementExceptions() {
+        Collection c = impl.emptyCollection();
+        assertThrows(
+            NoSuchElementException.class,
+            () -> c.iterator().next());
+
+        if (c instanceof Queue) {
+            Queue q = (Queue) c;
+            assertThrows(
+                NoSuchElementException.class,
+                () -> q.element(),
+                () -> q.remove());
+        }
+        if (c instanceof Deque) {
+            Deque d = (Deque) c;
+            assertThrows(
+                NoSuchElementException.class,
+                () -> d.getFirst(),
+                () -> d.getLast(),
+                () -> d.removeFirst(),
+                () -> d.removeLast(),
+                () -> d.pop(),
+                () -> d.descendingIterator().next());
+        }
+    }
+
+    public void testRemoveIf() {
+        Collection c = impl.emptyCollection();
+        boolean ordered =
+            c.spliterator().hasCharacteristics(Spliterator.ORDERED);
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        int n = rnd.nextInt(6);
+        for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
+        AtomicReference threwAt = new AtomicReference(null);
+        List orig = rnd.nextBoolean()
+            ? new ArrayList(c)
+            : Arrays.asList(c.toArray());
+
+        // Merely creating an iterator can change ArrayBlockingQueue behavior
+        Iterator it = rnd.nextBoolean() ? c.iterator() : null;
+
+        ArrayList survivors = new ArrayList();
+        ArrayList accepts = new ArrayList();
+        ArrayList rejects = new ArrayList();
+
+        Predicate randomPredicate = e -> {
+            assertNull(threwAt.get());
+            switch (rnd.nextInt(3)) {
+            case 0: accepts.add(e); return true;
+            case 1: rejects.add(e); return false;
+            case 2: threwAt.set(e); throw new ArithmeticException();
+            default: throw new AssertionError();
+            }
+        };
+        try {
+            try {
+                boolean modified = c.removeIf(randomPredicate);
+                assertNull(threwAt.get());
+                assertEquals(modified, accepts.size() > 0);
+                assertEquals(modified, rejects.size() != n);
+                assertEquals(accepts.size() + rejects.size(), n);
+                if (ordered) {
+                    assertEquals(rejects,
+                                 Arrays.asList(c.toArray()));
+                } else {
+                    assertEquals(new HashSet(rejects),
+                                 new HashSet(Arrays.asList(c.toArray())));
+                }
+            } catch (ArithmeticException ok) {
+                assertNotNull(threwAt.get());
+                assertTrue(c.contains(threwAt.get()));
+            }
+            if (it != null && impl.isConcurrent())
+                // check for weakly consistent iterator
+                while (it.hasNext()) assertTrue(orig.contains(it.next()));
+            switch (rnd.nextInt(4)) {
+            case 0: survivors.addAll(c); break;
+            case 1: survivors.addAll(Arrays.asList(c.toArray())); break;
+            case 2: c.forEach(survivors::add); break;
+            case 3: for (Object e : c) survivors.add(e); break;
+            }
+            assertTrue(orig.containsAll(accepts));
+            assertTrue(orig.containsAll(rejects));
+            assertTrue(orig.containsAll(survivors));
+            assertTrue(orig.containsAll(c));
+            assertTrue(c.containsAll(rejects));
+            assertTrue(c.containsAll(survivors));
+            assertTrue(survivors.containsAll(rejects));
+            if (threwAt.get() == null) {
+                assertEquals(n - accepts.size(), c.size());
+                for (Object x : accepts) assertFalse(c.contains(x));
+            } else {
+                // Two acceptable behaviors: entire removeIf call is one
+                // transaction, or each element processed is one transaction.
+                assertTrue(n == c.size() || n == c.size() + accepts.size());
+                int k = 0;
+                for (Object x : accepts) if (c.contains(x)) k++;
+                assertTrue(k == accepts.size() || k == 0);
+            }
+        } catch (Throwable ex) {
+            System.err.println(impl.klazz());
+            // c is at risk of corruption if we got here, so be lenient
+            try { System.err.printf("c=%s%n", c); }
+            catch (Throwable t) { t.printStackTrace(); }
+            System.err.printf("n=%d%n", n);
+            System.err.printf("orig=%s%n", orig);
+            System.err.printf("accepts=%s%n", accepts);
+            System.err.printf("rejects=%s%n", rejects);
+            System.err.printf("survivors=%s%n", survivors);
+            System.err.printf("threwAt=%s%n", threwAt.get());
+            throw ex;
+        }
+    }
+
+    /**
+     * Various ways of traversing a collection yield same elements
+     */
+    public void testIteratorEquivalence() {
+        Collection c = impl.emptyCollection();
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        int n = rnd.nextInt(6);
+        for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
+        ArrayList iterated = new ArrayList();
+        ArrayList iteratedForEachRemaining = new ArrayList();
+        ArrayList tryAdvanced = new ArrayList();
+        ArrayList spliterated = new ArrayList();
+        ArrayList splitonced = new ArrayList();
+        ArrayList forEached = new ArrayList();
+        ArrayList streamForEached = new ArrayList();
+        ConcurrentLinkedQueue parallelStreamForEached = new ConcurrentLinkedQueue();
+        ArrayList removeIfed = new ArrayList();
+        for (Object x : c) iterated.add(x);
+        c.iterator().forEachRemaining(iteratedForEachRemaining::add);
+        for (Spliterator s = c.spliterator();
+             s.tryAdvance(tryAdvanced::add); ) {}
+        c.spliterator().forEachRemaining(spliterated::add);
+        {                       // trySplit returns "strict prefix"
+            Spliterator s1 = c.spliterator(), s2 = s1.trySplit();
+            if (s2 != null) s2.forEachRemaining(splitonced::add);
+            s1.forEachRemaining(splitonced::add);
+        }
+        c.forEach(forEached::add);
+        c.stream().forEach(streamForEached::add);
+        c.parallelStream().forEach(parallelStreamForEached::add);
+        c.removeIf(e -> { removeIfed.add(e); return false; });
+        boolean ordered =
+            c.spliterator().hasCharacteristics(Spliterator.ORDERED);
+        if (c instanceof List || c instanceof Deque)
+            assertTrue(ordered);
+        HashSet cset = new HashSet(c);
+        assertEquals(cset, new HashSet(parallelStreamForEached));
+        if (ordered) {
+            assertEquals(iterated, iteratedForEachRemaining);
+            assertEquals(iterated, tryAdvanced);
+            assertEquals(iterated, spliterated);
+            assertEquals(iterated, splitonced);
+            assertEquals(iterated, forEached);
+            assertEquals(iterated, streamForEached);
+            assertEquals(iterated, removeIfed);
+        } else {
+            assertEquals(cset, new HashSet(iterated));
+            assertEquals(cset, new HashSet(iteratedForEachRemaining));
+            assertEquals(cset, new HashSet(tryAdvanced));
+            assertEquals(cset, new HashSet(spliterated));
+            assertEquals(cset, new HashSet(splitonced));
+            assertEquals(cset, new HashSet(forEached));
+            assertEquals(cset, new HashSet(streamForEached));
+            assertEquals(cset, new HashSet(removeIfed));
+        }
+        if (c instanceof Deque) {
+            Deque d = (Deque) c;
+            ArrayList descending = new ArrayList();
+            ArrayList descendingForEachRemaining = new ArrayList();
+            for (Iterator it = d.descendingIterator(); it.hasNext(); )
+                descending.add(it.next());
+            d.descendingIterator().forEachRemaining(
+                e -> descendingForEachRemaining.add(e));
+            Collections.reverse(descending);
+            Collections.reverse(descendingForEachRemaining);
+            assertEquals(iterated, descending);
+            assertEquals(iterated, descendingForEachRemaining);
+        }
+    }
+
+    /**
+     * Calling Iterator#remove() after Iterator#forEachRemaining
+     * should (maybe) remove last element
+     */
+    public void testRemoveAfterForEachRemaining() {
+        Collection c = impl.emptyCollection();
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        testCollection: {
+            int n = 3 + rnd.nextInt(2);
+            for (int i = 0; i < n; i++) c.add(impl.makeElement(i));
+            Iterator it = c.iterator();
+            assertTrue(it.hasNext());
+            assertEquals(impl.makeElement(0), it.next());
+            assertTrue(it.hasNext());
+            assertEquals(impl.makeElement(1), it.next());
+            it.forEachRemaining(e -> assertTrue(c.contains(e)));
+            if (testImplementationDetails) {
+                if (c instanceof java.util.concurrent.ArrayBlockingQueue) {
+                    assertIteratorExhausted(it);
+                } else {
+                    try { it.remove(); }
+                    catch (UnsupportedOperationException ok) {
+                        break testCollection;
+                    }
+                    assertEquals(n - 1, c.size());
+                    for (int i = 0; i < n - 1; i++)
+                        assertTrue(c.contains(impl.makeElement(i)));
+                    assertFalse(c.contains(impl.makeElement(n - 1)));
+                }
+            }
+        }
+        if (c instanceof Deque) {
+            Deque d = (Deque) impl.emptyCollection();
+            int n = 3 + rnd.nextInt(2);
+            for (int i = 0; i < n; i++) d.add(impl.makeElement(i));
+            Iterator it = d.descendingIterator();
+            assertTrue(it.hasNext());
+            assertEquals(impl.makeElement(n - 1), it.next());
+            assertTrue(it.hasNext());
+            assertEquals(impl.makeElement(n - 2), it.next());
+            it.forEachRemaining(e -> assertTrue(c.contains(e)));
+            if (testImplementationDetails) {
+                it.remove();
+                assertEquals(n - 1, d.size());
+                for (int i = 1; i < n; i++)
+                    assertTrue(d.contains(impl.makeElement(i)));
+                assertFalse(d.contains(impl.makeElement(0)));
+            }
+        }
+    }
+
     /**
      * stream().forEach returns elements in the collection
      */
-    public void testForEach() throws Throwable {
+    public void testStreamForEach() throws Throwable {
         final Collection c = impl.emptyCollection();
         final AtomicLong count = new AtomicLong(0L);
         final Object x = impl.makeElement(1);
         final Object y = impl.makeElement(2);
         final ArrayList found = new ArrayList();
-        Consumer<Object> spy = (o) -> { found.add(o); };
+        Consumer<Object> spy = o -> found.add(o);
         c.stream().forEach(spy);
         assertTrue(found.isEmpty());
 
@@ -96,7 +519,7 @@
         assertTrue(found.isEmpty());
     }
 
-    public void testForEachConcurrentStressTest() throws Throwable {
+    public void testStreamForEachConcurrentStressTest() throws Throwable {
         if (!impl.isConcurrent()) return;
         final Collection c = impl.emptyCollection();
         final long testDurationMillis = timeoutMillis();
@@ -109,7 +532,7 @@
             Runnable checkElt = () -> {
                 threadsStarted.countDown();
                 while (!done.get())
-                    c.stream().forEach((x) -> { assertSame(x, elt); }); };
+                    c.stream().forEach(x -> assertSame(x, elt)); };
             Runnable addRemove = () -> {
                 threadsStarted.countDown();
                 while (!done.get()) {
@@ -124,5 +547,144 @@
         assertNull(f2.get(0L, MILLISECONDS));
     }
 
-    // public void testCollection8DebugFail() { fail(); }
+    /**
+     * collection.forEach returns elements in the collection
+     */
+    public void testForEach() throws Throwable {
+        final Collection c = impl.emptyCollection();
+        final AtomicLong count = new AtomicLong(0L);
+        final Object x = impl.makeElement(1);
+        final Object y = impl.makeElement(2);
+        final ArrayList found = new ArrayList();
+        Consumer<Object> spy = o -> found.add(o);
+        c.forEach(spy);
+        assertTrue(found.isEmpty());
+
+        assertTrue(c.add(x));
+        c.forEach(spy);
+        assertEquals(Collections.singletonList(x), found);
+        found.clear();
+
+        assertTrue(c.add(y));
+        c.forEach(spy);
+        assertEquals(2, found.size());
+        assertTrue(found.contains(x));
+        assertTrue(found.contains(y));
+        found.clear();
+
+        c.clear();
+        c.forEach(spy);
+        assertTrue(found.isEmpty());
+    }
+
+    /**
+     * Motley crew of threads concurrently randomly hammer the collection.
+     */
+    public void testDetectRaces() throws Throwable {
+        if (!impl.isConcurrent()) return;
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        final Collection c = impl.emptyCollection();
+        final long testDurationMillis
+            = expensiveTests ? LONG_DELAY_MS : timeoutMillis();
+        final AtomicBoolean done = new AtomicBoolean(false);
+        final Object one = impl.makeElement(1);
+        final Object two = impl.makeElement(2);
+        final Consumer checkSanity = x -> assertTrue(x == one || x == two);
+        final Consumer<Object[]> checkArraySanity = array -> {
+            // assertTrue(array.length <= 2); // duplicates are permitted
+            for (Object x : array) assertTrue(x == one || x == two);
+        };
+        final Object[] emptyArray =
+            (Object[]) java.lang.reflect.Array.newInstance(one.getClass(), 0);
+        final List<Future<?>> futures;
+        final Phaser threadsStarted = new Phaser(1); // register this thread
+        final Runnable[] frobbers = {
+            () -> c.forEach(checkSanity),
+            () -> c.stream().forEach(checkSanity),
+            () -> c.parallelStream().forEach(checkSanity),
+            () -> c.spliterator().trySplit(),
+            () -> {
+                Spliterator s = c.spliterator();
+                s.tryAdvance(checkSanity);
+                s.trySplit();
+            },
+            () -> {
+                Spliterator s = c.spliterator();
+                do {} while (s.tryAdvance(checkSanity));
+            },
+            () -> { for (Object x : c) checkSanity.accept(x); },
+            () -> checkArraySanity.accept(c.toArray()),
+            () -> checkArraySanity.accept(c.toArray(emptyArray)),
+            () -> {
+                assertTrue(c.add(one));
+                assertTrue(c.contains(one));
+                assertTrue(c.remove(one));
+                assertFalse(c.contains(one));
+            },
+            () -> {
+                assertTrue(c.add(two));
+                assertTrue(c.contains(two));
+                assertTrue(c.remove(two));
+                assertFalse(c.contains(two));
+            },
+        };
+        final List<Runnable> tasks =
+            Arrays.stream(frobbers)
+            .filter(task -> rnd.nextBoolean()) // random subset
+            .map(task -> (Runnable) () -> {
+                     threadsStarted.arriveAndAwaitAdvance();
+                     while (!done.get())
+                         task.run();
+                 })
+            .collect(Collectors.toList());
+        final ExecutorService pool = Executors.newCachedThreadPool();
+        try (PoolCleaner cleaner = cleaner(pool, done)) {
+            threadsStarted.bulkRegister(tasks.size());
+            futures = tasks.stream()
+                .map(pool::submit)
+                .collect(Collectors.toList());
+            threadsStarted.arriveAndDeregister();
+            Thread.sleep(testDurationMillis);
+        }
+        for (Future future : futures)
+            assertNull(future.get(0L, MILLISECONDS));
+    }
+
+    /**
+     * Spliterators are either IMMUTABLE or truly late-binding or, if
+     * concurrent, use the same "late-binding style" of returning
+     * elements added between creation and first use.
+     */
+    public void testLateBindingStyle() {
+        if (!testImplementationDetails) return;
+        if (impl.klazz() == ArrayList.class) return; // for jdk8
+        // Immutable (snapshot) spliterators are exempt
+        if (impl.emptyCollection().spliterator()
+            .hasCharacteristics(Spliterator.IMMUTABLE))
+            return;
+        final Object one = impl.makeElement(1);
+        {
+            final Collection c = impl.emptyCollection();
+            final Spliterator split = c.spliterator();
+            c.add(one);
+            assertTrue(split.tryAdvance(e -> { assertSame(e, one); }));
+            assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
+            assertTrue(c.contains(one));
+        }
+        {
+            final AtomicLong count = new AtomicLong(0);
+            final Collection c = impl.emptyCollection();
+            final Spliterator split = c.spliterator();
+            c.add(one);
+            split.forEachRemaining(
+                e -> { assertSame(e, one); count.getAndIncrement(); });
+            assertEquals(1L, count.get());
+            assertFalse(split.tryAdvance(e -> { throw new AssertionError(); }));
+            assertTrue(c.contains(one));
+        }
+    }
+
+//     public void testCollection8DebugFail() {
+//         fail(impl.klazz().getSimpleName());
+//     }
 }
--- a/jdk/test/java/util/concurrent/tck/CollectionTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/CollectionTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -32,8 +32,6 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-import java.util.Collection;
-
 import junit.framework.Test;
 
 /**
@@ -58,11 +56,7 @@
                                         impl));
     }
 
-    /** A test of the CollectionImplementation implementation ! */
-    public void testEmptyMeansEmpty() {
-        assertTrue(impl.emptyCollection().isEmpty());
-        assertEquals(0, impl.emptyCollection().size());
-    }
-
-    // public void testCollectionDebugFail() { fail(); }
+//     public void testCollectionDebugFail() {
+//         fail(impl.klazz().getSimpleName());
+//     }
 }
--- a/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -174,26 +174,26 @@
 
     void checkCompletedWithWrappedCFException(CompletableFuture<?> f) {
         checkCompletedExceptionally(f, true,
-            (t) -> assertTrue(t instanceof CFException));
+            t -> assertTrue(t instanceof CFException));
     }
 
     void checkCompletedWithWrappedCancellationException(CompletableFuture<?> f) {
         checkCompletedExceptionally(f, true,
-            (t) -> assertTrue(t instanceof CancellationException));
+            t -> assertTrue(t instanceof CancellationException));
     }
 
     void checkCompletedWithTimeoutException(CompletableFuture<?> f) {
         checkCompletedExceptionally(f, false,
-            (t) -> assertTrue(t instanceof TimeoutException));
+            t -> assertTrue(t instanceof TimeoutException));
     }
 
     void checkCompletedWithWrappedException(CompletableFuture<?> f,
                                             Throwable ex) {
-        checkCompletedExceptionally(f, true, (t) -> assertSame(t, ex));
+        checkCompletedExceptionally(f, true, t -> assertSame(t, ex));
     }
 
     void checkCompletedExceptionally(CompletableFuture<?> f, Throwable ex) {
-        checkCompletedExceptionally(f, false, (t) -> assertSame(t, ex));
+        checkCompletedExceptionally(f, false, t -> assertSame(t, ex));
     }
 
     void checkCancelled(CompletableFuture<?> f) {
@@ -3284,12 +3284,12 @@
 
             () -> f.thenApply(null),
             () -> f.thenApplyAsync(null),
-            () -> f.thenApplyAsync((x) -> x, null),
+            () -> f.thenApplyAsync(x -> x, null),
             () -> f.thenApplyAsync(null, exec),
 
             () -> f.thenAccept(null),
             () -> f.thenAcceptAsync(null),
-            () -> f.thenAcceptAsync((x) -> {} , null),
+            () -> f.thenAcceptAsync(x -> {} , null),
             () -> f.thenAcceptAsync(null, exec),
 
             () -> f.thenRun(null),
@@ -3324,18 +3324,18 @@
             () -> f.applyToEither(g, null),
             () -> f.applyToEitherAsync(g, null),
             () -> f.applyToEitherAsync(g, null, exec),
-            () -> f.applyToEither(nullFuture, (x) -> x),
-            () -> f.applyToEitherAsync(nullFuture, (x) -> x),
-            () -> f.applyToEitherAsync(nullFuture, (x) -> x, exec),
-            () -> f.applyToEitherAsync(g, (x) -> x, null),
+            () -> f.applyToEither(nullFuture, x -> x),
+            () -> f.applyToEitherAsync(nullFuture, x -> x),
+            () -> f.applyToEitherAsync(nullFuture, x -> x, exec),
+            () -> f.applyToEitherAsync(g, x -> x, null),
 
             () -> f.acceptEither(g, null),
             () -> f.acceptEitherAsync(g, null),
             () -> f.acceptEitherAsync(g, null, exec),
-            () -> f.acceptEither(nullFuture, (x) -> {}),
-            () -> f.acceptEitherAsync(nullFuture, (x) -> {}),
-            () -> f.acceptEitherAsync(nullFuture, (x) -> {}, exec),
-            () -> f.acceptEitherAsync(g, (x) -> {}, null),
+            () -> f.acceptEither(nullFuture, x -> {}),
+            () -> f.acceptEitherAsync(nullFuture, x -> {}),
+            () -> f.acceptEitherAsync(nullFuture, x -> {}, exec),
+            () -> f.acceptEitherAsync(g, x -> {}, null),
 
             () -> f.runAfterEither(g, null),
             () -> f.runAfterEitherAsync(g, null),
@@ -3401,18 +3401,18 @@
         for (CompletableFuture<Integer> src : srcs) {
             List<CompletableFuture<?>> fs = new ArrayList<>();
             fs.add(src.thenRunAsync(() -> {}, e));
-            fs.add(src.thenAcceptAsync((z) -> {}, e));
-            fs.add(src.thenApplyAsync((z) -> z, e));
+            fs.add(src.thenAcceptAsync(z -> {}, e));
+            fs.add(src.thenApplyAsync(z -> z, e));
 
             fs.add(src.thenCombineAsync(src, (x, y) -> x, e));
             fs.add(src.thenAcceptBothAsync(src, (x, y) -> {}, e));
             fs.add(src.runAfterBothAsync(src, () -> {}, e));
 
-            fs.add(src.applyToEitherAsync(src, (z) -> z, e));
-            fs.add(src.acceptEitherAsync(src, (z) -> {}, e));
+            fs.add(src.applyToEitherAsync(src, z -> z, e));
+            fs.add(src.acceptEitherAsync(src, z -> {}, e));
             fs.add(src.runAfterEitherAsync(src, () -> {}, e));
 
-            fs.add(src.thenComposeAsync((z) -> null, e));
+            fs.add(src.thenComposeAsync(z -> null, e));
             fs.add(src.whenCompleteAsync((z, t) -> {}, e));
             fs.add(src.handleAsync((z, t) -> null, e));
 
@@ -3445,11 +3445,11 @@
         {
             List<CompletableFuture<?>> fs = new ArrayList<>();
 
-            fs.add(complete.applyToEitherAsync(incomplete, (z) -> z, e));
-            fs.add(incomplete.applyToEitherAsync(complete, (z) -> z, e));
-
-            fs.add(complete.acceptEitherAsync(incomplete, (z) -> {}, e));
-            fs.add(incomplete.acceptEitherAsync(complete, (z) -> {}, e));
+            fs.add(complete.applyToEitherAsync(incomplete, z -> z, e));
+            fs.add(incomplete.applyToEitherAsync(complete, z -> z, e));
+
+            fs.add(complete.acceptEitherAsync(incomplete, z -> {}, e));
+            fs.add(incomplete.acceptEitherAsync(complete, z -> {}, e));
 
             fs.add(complete.runAfterEitherAsync(incomplete, () -> {}, e));
             fs.add(incomplete.runAfterEitherAsync(complete, () -> {}, e));
@@ -3488,18 +3488,18 @@
 
         List<CompletableFuture<?>> fs = new ArrayList<>();
         fs.add(incomplete.thenRunAsync(() -> {}, e));
-        fs.add(incomplete.thenAcceptAsync((z) -> {}, e));
-        fs.add(incomplete.thenApplyAsync((z) -> z, e));
+        fs.add(incomplete.thenAcceptAsync(z -> {}, e));
+        fs.add(incomplete.thenApplyAsync(z -> z, e));
 
         fs.add(incomplete.thenCombineAsync(incomplete, (x, y) -> x, e));
         fs.add(incomplete.thenAcceptBothAsync(incomplete, (x, y) -> {}, e));
         fs.add(incomplete.runAfterBothAsync(incomplete, () -> {}, e));
 
-        fs.add(incomplete.applyToEitherAsync(incomplete, (z) -> z, e));
-        fs.add(incomplete.acceptEitherAsync(incomplete, (z) -> {}, e));
+        fs.add(incomplete.applyToEitherAsync(incomplete, z -> z, e));
+        fs.add(incomplete.acceptEitherAsync(incomplete, z -> {}, e));
         fs.add(incomplete.runAfterEitherAsync(incomplete, () -> {}, e));
 
-        fs.add(incomplete.thenComposeAsync((z) -> null, e));
+        fs.add(incomplete.thenComposeAsync(z -> null, e));
         fs.add(incomplete.whenCompleteAsync((z, t) -> {}, e));
         fs.add(incomplete.handleAsync((z, t) -> null, e));
 
@@ -3720,7 +3720,7 @@
     public void testCompleteAsync2() {
         CompletableFuture<Integer> f = new CompletableFuture<>();
         CFException ex = new CFException();
-        f.completeAsync(() -> {if (true) throw ex; return 1;});
+        f.completeAsync(() -> { throw ex; });
         try {
             f.join();
             shouldThrow();
@@ -3750,7 +3750,7 @@
         CompletableFuture<Integer> f = new CompletableFuture<>();
         CFException ex = new CFException();
         ThreadExecutor executor = new ThreadExecutor();
-        f.completeAsync(() -> {if (true) throw ex; return 1;}, executor);
+        f.completeAsync(() -> { throw ex; }, executor);
         try {
             f.join();
             shouldThrow();
@@ -3909,31 +3909,31 @@
         List<Function<CompletableFuture<Integer>, CompletableFuture<?>>> funs
             = new ArrayList<>();
 
-        funs.add((y) -> m.thenRun(y, noopRunnable));
-        funs.add((y) -> m.thenAccept(y, noopConsumer));
-        funs.add((y) -> m.thenApply(y, incFunction));
-
-        funs.add((y) -> m.runAfterEither(y, incomplete, noopRunnable));
-        funs.add((y) -> m.acceptEither(y, incomplete, noopConsumer));
-        funs.add((y) -> m.applyToEither(y, incomplete, incFunction));
-
-        funs.add((y) -> m.runAfterBoth(y, v42, noopRunnable));
-        funs.add((y) -> m.runAfterBoth(v42, y, noopRunnable));
-        funs.add((y) -> m.thenAcceptBoth(y, v42, new SubtractAction(m)));
-        funs.add((y) -> m.thenAcceptBoth(v42, y, new SubtractAction(m)));
-        funs.add((y) -> m.thenCombine(y, v42, new SubtractFunction(m)));
-        funs.add((y) -> m.thenCombine(v42, y, new SubtractFunction(m)));
-
-        funs.add((y) -> m.whenComplete(y, (Integer r, Throwable t) -> {}));
-
-        funs.add((y) -> m.thenCompose(y, new CompletableFutureInc(m)));
-
-        funs.add((y) -> CompletableFuture.allOf(y));
-        funs.add((y) -> CompletableFuture.allOf(y, v42));
-        funs.add((y) -> CompletableFuture.allOf(v42, y));
-        funs.add((y) -> CompletableFuture.anyOf(y));
-        funs.add((y) -> CompletableFuture.anyOf(y, incomplete));
-        funs.add((y) -> CompletableFuture.anyOf(incomplete, y));
+        funs.add(y -> m.thenRun(y, noopRunnable));
+        funs.add(y -> m.thenAccept(y, noopConsumer));
+        funs.add(y -> m.thenApply(y, incFunction));
+
+        funs.add(y -> m.runAfterEither(y, incomplete, noopRunnable));
+        funs.add(y -> m.acceptEither(y, incomplete, noopConsumer));
+        funs.add(y -> m.applyToEither(y, incomplete, incFunction));
+
+        funs.add(y -> m.runAfterBoth(y, v42, noopRunnable));
+        funs.add(y -> m.runAfterBoth(v42, y, noopRunnable));
+        funs.add(y -> m.thenAcceptBoth(y, v42, new SubtractAction(m)));
+        funs.add(y -> m.thenAcceptBoth(v42, y, new SubtractAction(m)));
+        funs.add(y -> m.thenCombine(y, v42, new SubtractFunction(m)));
+        funs.add(y -> m.thenCombine(v42, y, new SubtractFunction(m)));
+
+        funs.add(y -> m.whenComplete(y, (Integer r, Throwable t) -> {}));
+
+        funs.add(y -> m.thenCompose(y, new CompletableFutureInc(m)));
+
+        funs.add(y -> CompletableFuture.allOf(y));
+        funs.add(y -> CompletableFuture.allOf(y, v42));
+        funs.add(y -> CompletableFuture.allOf(v42, y));
+        funs.add(y -> CompletableFuture.anyOf(y));
+        funs.add(y -> CompletableFuture.anyOf(y, incomplete));
+        funs.add(y -> CompletableFuture.anyOf(incomplete, y));
 
         for (Function<CompletableFuture<Integer>, CompletableFuture<?>>
                  fun : funs) {
@@ -3990,12 +3990,12 @@
     public void testMinimalCompletionStage_minimality() {
         if (!testImplementationDetails) return;
         Function<Method, String> toSignature =
-            (method) -> method.getName() + Arrays.toString(method.getParameterTypes());
+            method -> method.getName() + Arrays.toString(method.getParameterTypes());
         Predicate<Method> isNotStatic =
-            (method) -> (method.getModifiers() & Modifier.STATIC) == 0;
+            method -> (method.getModifiers() & Modifier.STATIC) == 0;
         List<Method> minimalMethods =
             Stream.of(Object.class, CompletionStage.class)
-            .flatMap((klazz) -> Stream.of(klazz.getMethods()))
+            .flatMap(klazz -> Stream.of(klazz.getMethods()))
             .filter(isNotStatic)
             .collect(Collectors.toList());
         // Methods from CompletableFuture permitted NOT to throw UOE
@@ -4011,7 +4011,7 @@
             .collect(Collectors.toSet());
         List<Method> allMethods = Stream.of(CompletableFuture.class.getMethods())
             .filter(isNotStatic)
-            .filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method)))
+            .filter(method -> !permittedMethodSignatures.contains(toSignature.apply(method)))
             .collect(Collectors.toList());
 
         List<CompletionStage<Integer>> stages = new ArrayList<>();
@@ -4171,7 +4171,7 @@
         CompletionStage<Integer> minimal = f.minimalCompletionStage();
         CompletableFuture<Integer> g = new CompletableFuture<>();
         if (!createIncomplete) assertTrue(f.complete(v1));
-        minimal.thenAccept((x) -> g.complete(x));
+        minimal.thenAccept(x -> g.complete(x));
         if (createIncomplete) assertTrue(f.complete(v1));
         g.join();
         checkCompletedNormally(g, v1);
@@ -4195,7 +4195,7 @@
         static <T,U,V> Function<T, CompletableFuture<V>> compose
             (Function<T, CompletableFuture<U>> f,
              Function<U, CompletableFuture<V>> g) {
-            return (x) -> f.apply(x).thenCompose(g);
+            return x -> f.apply(x).thenCompose(g);
         }
 
         static void assertZero(CompletableFuture<?> f) {
@@ -4275,9 +4275,9 @@
 
         // Some mutually non-commutative functions
         Function<Long, CompletableFuture<Long>> triple
-            = (x) -> Monad.unit(3 * x);
+            = x -> Monad.unit(3 * x);
         Function<Long, CompletableFuture<Long>> inc
-            = (x) -> Monad.unit(x + 1);
+            = x -> Monad.unit(x + 1);
 
         // unit is a right identity: m >>= unit === m
         Monad.assertFutureEquals(inc.apply(5L).thenCompose(unit),
@@ -4289,7 +4289,7 @@
         // associativity: (m >>= f) >>= g === m >>= ( \x -> (f x >>= g) )
         Monad.assertFutureEquals(
             unit.apply(5L).thenCompose(inc).thenCompose(triple),
-            unit.apply(5L).thenCompose((x) -> inc.apply(x).thenCompose(triple)));
+            unit.apply(5L).thenCompose(x -> inc.apply(x).thenCompose(triple)));
 
         // The case for CompletableFuture as an additive monad is weaker...
 
@@ -4299,7 +4299,7 @@
         // left zero: zero >>= f === zero
         Monad.assertZero(zero.thenCompose(inc));
         // right zero: f >>= (\x -> zero) === zero
-        Monad.assertZero(inc.apply(5L).thenCompose((x) -> zero));
+        Monad.assertZero(inc.apply(5L).thenCompose(x -> zero));
 
         // f plus zero === f
         Monad.assertFutureEquals(Monad.unit(5L),
@@ -4357,8 +4357,8 @@
         final AtomicInteger count = new AtomicInteger(0);
         for (int i = 0; i < n; i++) {
             head.thenRun(() -> count.getAndIncrement());
-            head.thenAccept((x) -> count.getAndIncrement());
-            head.thenApply((x) -> count.getAndIncrement());
+            head.thenAccept(x -> count.getAndIncrement());
+            head.thenApply(x -> count.getAndIncrement());
 
             head.runAfterBoth(complete, () -> count.getAndIncrement());
             head.thenAcceptBoth(complete, (x, y) -> count.getAndIncrement());
@@ -4368,11 +4368,11 @@
             complete.thenCombine(head, (x, y) -> count.getAndIncrement());
 
             head.runAfterEither(new CompletableFuture<Void>(), () -> count.getAndIncrement());
-            head.acceptEither(new CompletableFuture<Void>(), (x) -> count.getAndIncrement());
-            head.applyToEither(new CompletableFuture<Void>(), (x) -> count.getAndIncrement());
+            head.acceptEither(new CompletableFuture<Void>(), x -> count.getAndIncrement());
+            head.applyToEither(new CompletableFuture<Void>(), x -> count.getAndIncrement());
             new CompletableFuture<Void>().runAfterEither(head, () -> count.getAndIncrement());
-            new CompletableFuture<Void>().acceptEither(head, (x) -> count.getAndIncrement());
-            new CompletableFuture<Void>().applyToEither(head, (x) -> count.getAndIncrement());
+            new CompletableFuture<Void>().acceptEither(head, x -> count.getAndIncrement());
+            new CompletableFuture<Void>().applyToEither(head, x -> count.getAndIncrement());
         }
         head.complete(null);
         assertEquals(5 * 3 * n, count.get());
@@ -4389,11 +4389,11 @@
             f.complete(null);
 
             f = new CompletableFuture<>();
-            f.acceptEither(incomplete, (x) -> {});
+            f.acceptEither(incomplete, x -> {});
             f.complete(null);
 
             f = new CompletableFuture<>();
-            f.applyToEither(incomplete, (x) -> x);
+            f.applyToEither(incomplete, x -> x);
             f.complete(null);
 
             f = new CompletableFuture<>();
@@ -4407,11 +4407,11 @@
             f.complete(null);
 
             f = new CompletableFuture<>();
-            incomplete.acceptEither(f, (x) -> {});
+            incomplete.acceptEither(f, x -> {});
             f.complete(null);
 
             f = new CompletableFuture<>();
-            incomplete.applyToEither(f, (x) -> x);
+            incomplete.applyToEither(f, x -> x);
             f.complete(null);
 
             f = new CompletableFuture<>();
--- a/jdk/test/java/util/concurrent/tck/ConcurrentHashMap8Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentHashMap8Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -43,6 +43,8 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.Spliterator;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.LongAdder;
 import java.util.function.BiFunction;
@@ -88,7 +90,7 @@
      */
     public void testComputeIfAbsent() {
         ConcurrentHashMap map = map5();
-        map.computeIfAbsent(six, (x) -> "Z");
+        map.computeIfAbsent(six, x -> "Z");
         assertTrue(map.containsKey(six));
     }
 
@@ -97,7 +99,7 @@
      */
     public void testComputeIfAbsent2() {
         ConcurrentHashMap map = map5();
-        assertEquals("A", map.computeIfAbsent(one, (x) -> "Z"));
+        assertEquals("A", map.computeIfAbsent(one, x -> "Z"));
     }
 
     /**
@@ -105,7 +107,7 @@
      */
     public void testComputeIfAbsent3() {
         ConcurrentHashMap map = map5();
-        map.computeIfAbsent(six, (x) -> null);
+        map.computeIfAbsent(six, x -> null);
         assertFalse(map.containsKey(six));
     }
 
@@ -1114,4 +1116,30 @@
         assertNull(r);
     }
 
+    /**
+     * Tests performance of computeIfAbsent when the element is present.
+     * See JDK-8161372
+     * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testcomputeIfAbsent_performance -Djsr166.expensiveTests=true tck
+     */
+    public void testcomputeIfAbsent_performance() {
+        final int mapSize = 20;
+        final int iterations = expensiveTests ? (1 << 23) : mapSize * 2;
+        final int threads = expensiveTests ? 10 : 2;
+        final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
+        for (int i = 0; i < mapSize; i++)
+            map.put(i, i);
+        final ExecutorService pool = Executors.newFixedThreadPool(2);
+        try (PoolCleaner cleaner = cleaner(pool)) {
+            Runnable r = new CheckedRunnable() {
+                public void realRun() {
+                    int result = 0;
+                    for (int i = 0; i < iterations; i++)
+                        result += map.computeIfAbsent(i % mapSize, k -> k + k);
+                    if (result == -42) throw new Error();
+                }};
+            for (int i = 0; i < threads; i++)
+                pool.execute(r);
+        }
+    }
+
 }
--- a/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -864,30 +864,4 @@
         assertEquals(mapSize, map.size());
     }
 
-    /**
-     * Tests performance of computeIfAbsent when the element is present.
-     * See JDK-8161372
-     * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testcomputeIfAbsent_performance -Djsr166.expensiveTests=true tck
-     */
-    public void testcomputeIfAbsent_performance() {
-        final int mapSize = 20;
-        final int iterations = expensiveTests ? (1 << 23) : mapSize * 2;
-        final int threads = expensiveTests ? 10 : 2;
-        final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
-        for (int i = 0; i < mapSize; i++)
-            map.put(i, i);
-        final ExecutorService pool = Executors.newFixedThreadPool(2);
-        try (PoolCleaner cleaner = cleaner(pool)) {
-            Runnable r = new CheckedRunnable() {
-                public void realRun() {
-                    int result = 0;
-                    for (int i = 0; i < iterations; i++)
-                        result += map.computeIfAbsent(i % mapSize, (k) -> k + k);
-                    if (result == -42) throw new Error();
-                }};
-            for (int i = 0; i < threads; i++)
-                pool.execute(r);
-        }
-    }
-
 }
--- a/jdk/test/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -52,12 +52,20 @@
     }
 
     public static Test suite() {
-        return new TestSuite(ConcurrentLinkedDequeTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ConcurrentLinkedDeque.class; }
+            public Collection emptyCollection() { return new ConcurrentLinkedDeque(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
+        return newTestSuite(ConcurrentLinkedDequeTest.class,
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new deque of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private ConcurrentLinkedDeque<Integer> populatedDeque(int n) {
         ConcurrentLinkedDeque<Integer> q = new ConcurrentLinkedDeque<Integer>();
@@ -66,6 +74,8 @@
             assertTrue(q.offer(new Integer(i)));
         assertFalse(q.isEmpty());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peekFirst());
+        assertEquals((Integer) (n - 1), q.peekLast());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentLinkedQueueTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -50,12 +50,20 @@
     }
 
     public static Test suite() {
-        return new TestSuite(ConcurrentLinkedQueueTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ConcurrentLinkedQueue.class; }
+            public Collection emptyCollection() { return new ConcurrentLinkedQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
+        return newTestSuite(ConcurrentLinkedQueueTest.class,
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private ConcurrentLinkedQueue<Integer> populatedQueue(int n) {
         ConcurrentLinkedQueue<Integer> q = new ConcurrentLinkedQueue<Integer>();
@@ -64,6 +72,7 @@
             assertTrue(q.offer(new Integer(i)));
         assertFalse(q.isEmpty());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSetTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -62,7 +62,7 @@
 
     /**
      * Returns a new set of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private ConcurrentSkipListSet<Integer> populatedSet(int n) {
         ConcurrentSkipListSet<Integer> q =
--- a/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubSetTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentSkipListSubSetTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -57,7 +57,7 @@
 
     /**
      * Returns a new set of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private NavigableSet<Integer> populatedSet(int n) {
         ConcurrentSkipListSet<Integer> q =
--- a/jdk/test/java/util/concurrent/tck/CopyOnWriteArrayListTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/CopyOnWriteArrayListTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -53,7 +53,22 @@
     }
 
     public static Test suite() {
-        return new TestSuite(CopyOnWriteArrayListTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return ArrayList.class; }
+            public List emptyCollection() { return new CopyOnWriteArrayList(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return true; }
+        }
+        class SubListImplementation extends Implementation {
+            public List emptyCollection() {
+                return super.emptyCollection().subList(0, 0);
+            }
+        }
+        return newTestSuite(
+                CopyOnWriteArrayListTest.class,
+                CollectionTest.testSuite(new Implementation()),
+                CollectionTest.testSuite(new SubListImplementation()));
     }
 
     static CopyOnWriteArrayList<Integer> populatedArray(int n) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/CountedCompleter8Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class CountedCompleter8Test extends JSR166TestCase {
+
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+
+    public static Test suite() {
+        return new TestSuite(CountedCompleter8Test.class);
+    }
+
+    /** CountedCompleter class javadoc code sample, version 1. */
+    public static <E> void forEach1(E[] array, Consumer<E> action) {
+        class Task extends CountedCompleter<Void> {
+            final int lo, hi;
+            Task(Task parent, int lo, int hi) {
+                super(parent); this.lo = lo; this.hi = hi;
+            }
+
+            public void compute() {
+                if (hi - lo >= 2) {
+                    int mid = (lo + hi) >>> 1;
+                    // must set pending count before fork
+                    setPendingCount(2);
+                    new Task(this, mid, hi).fork(); // right child
+                    new Task(this, lo, mid).fork(); // left child
+                }
+                else if (hi > lo)
+                    action.accept(array[lo]);
+                tryComplete();
+            }
+        }
+        new Task(null, 0, array.length).invoke();
+    }
+
+    /** CountedCompleter class javadoc code sample, version 2. */
+    public static <E> void forEach2(E[] array, Consumer<E> action) {
+        class Task extends CountedCompleter<Void> {
+            final int lo, hi;
+            Task(Task parent, int lo, int hi) {
+                super(parent); this.lo = lo; this.hi = hi;
+            }
+
+            public void compute() {
+                if (hi - lo >= 2) {
+                    int mid = (lo + hi) >>> 1;
+                    setPendingCount(1); // looks off by one, but correct!
+                    new Task(this, mid, hi).fork(); // right child
+                    new Task(this, lo, mid).compute(); // direct invoke
+                } else {
+                    if (hi > lo)
+                        action.accept(array[lo]);
+                    tryComplete();
+                }
+            }
+        }
+        new Task(null, 0, array.length).invoke();
+    }
+
+    /** CountedCompleter class javadoc code sample, version 3. */
+    public static <E> void forEach3(E[] array, Consumer<E> action) {
+        class Task extends CountedCompleter<Void> {
+            final int lo, hi;
+            Task(Task parent, int lo, int hi) {
+                super(parent); this.lo = lo; this.hi = hi;
+            }
+
+            public void compute() {
+                int n = hi - lo;
+                for (; n >= 2; n /= 2) {
+                    addToPendingCount(1);
+                    new Task(this, lo + n/2, lo + n).fork();
+                }
+                if (n > 0)
+                    action.accept(array[lo]);
+                propagateCompletion();
+            }
+        }
+        new Task(null, 0, array.length).invoke();
+    }
+
+    /** CountedCompleter class javadoc code sample, version 4. */
+    public static <E> void forEach4(E[] array, Consumer<E> action) {
+        class Task extends CountedCompleter<Void> {
+            final int lo, hi;
+            Task(Task parent, int lo, int hi) {
+                super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
+                this.lo = lo; this.hi = hi;
+            }
+
+            public void compute() {
+                for (int n = hi - lo; n >= 2; n /= 2)
+                    new Task(this, lo + n/2, lo + n).fork();
+                action.accept(array[lo]);
+                propagateCompletion();
+            }
+        }
+        if (array.length > 0)
+            new Task(null, 0, array.length).invoke();
+    }
+
+    void testRecursiveDecomposition(
+        BiConsumer<Integer[], Consumer<Integer>> action) {
+        int n = ThreadLocalRandom.current().nextInt(8);
+        Integer[] a = new Integer[n];
+        for (int i = 0; i < n; i++) a[i] = i + 1;
+        AtomicInteger ai = new AtomicInteger(0);
+        action.accept(a, ai::addAndGet);
+        assertEquals(n * (n + 1) / 2, ai.get());
+    }
+
+    /**
+     * Variants of divide-by-two recursive decomposition into leaf tasks,
+     * as described in the CountedCompleter class javadoc code samples
+     */
+    public void testRecursiveDecomposition() {
+        testRecursiveDecomposition(CountedCompleter8Test::forEach1);
+        testRecursiveDecomposition(CountedCompleter8Test::forEach2);
+        testRecursiveDecomposition(CountedCompleter8Test::forEach3);
+        testRecursiveDecomposition(CountedCompleter8Test::forEach4);
+    }
+
+}
--- a/jdk/test/java/util/concurrent/tck/CountedCompleterTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/CountedCompleterTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -44,8 +44,6 @@
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -1872,115 +1870,4 @@
         testInvokeOnPool(singletonPool(), a);
     }
 
-    /** CountedCompleter class javadoc code sample, version 1. */
-    public static <E> void forEach1(E[] array, Consumer<E> action) {
-        class Task extends CountedCompleter<Void> {
-            final int lo, hi;
-            Task(Task parent, int lo, int hi) {
-                super(parent); this.lo = lo; this.hi = hi;
-            }
-
-            public void compute() {
-                if (hi - lo >= 2) {
-                    int mid = (lo + hi) >>> 1;
-                    // must set pending count before fork
-                    setPendingCount(2);
-                    new Task(this, mid, hi).fork(); // right child
-                    new Task(this, lo, mid).fork(); // left child
-                }
-                else if (hi > lo)
-                    action.accept(array[lo]);
-                tryComplete();
-            }
-        }
-        new Task(null, 0, array.length).invoke();
-    }
-
-    /** CountedCompleter class javadoc code sample, version 2. */
-    public static <E> void forEach2(E[] array, Consumer<E> action) {
-        class Task extends CountedCompleter<Void> {
-            final int lo, hi;
-            Task(Task parent, int lo, int hi) {
-                super(parent); this.lo = lo; this.hi = hi;
-            }
-
-            public void compute() {
-                if (hi - lo >= 2) {
-                    int mid = (lo + hi) >>> 1;
-                    setPendingCount(1); // looks off by one, but correct!
-                    new Task(this, mid, hi).fork(); // right child
-                    new Task(this, lo, mid).compute(); // direct invoke
-                } else {
-                    if (hi > lo)
-                        action.accept(array[lo]);
-                    tryComplete();
-                }
-            }
-        }
-        new Task(null, 0, array.length).invoke();
-    }
-
-    /** CountedCompleter class javadoc code sample, version 3. */
-    public static <E> void forEach3(E[] array, Consumer<E> action) {
-        class Task extends CountedCompleter<Void> {
-            final int lo, hi;
-            Task(Task parent, int lo, int hi) {
-                super(parent); this.lo = lo; this.hi = hi;
-            }
-
-            public void compute() {
-                int n = hi - lo;
-                for (; n >= 2; n /= 2) {
-                    addToPendingCount(1);
-                    new Task(this, lo + n/2, lo + n).fork();
-                }
-                if (n > 0)
-                    action.accept(array[lo]);
-                propagateCompletion();
-            }
-        }
-        new Task(null, 0, array.length).invoke();
-    }
-
-    /** CountedCompleter class javadoc code sample, version 4. */
-    public static <E> void forEach4(E[] array, Consumer<E> action) {
-        class Task extends CountedCompleter<Void> {
-            final int lo, hi;
-            Task(Task parent, int lo, int hi) {
-                super(parent, 31 - Integer.numberOfLeadingZeros(hi - lo));
-                this.lo = lo; this.hi = hi;
-            }
-
-            public void compute() {
-                for (int n = hi - lo; n >= 2; n /= 2)
-                    new Task(this, lo + n/2, lo + n).fork();
-                action.accept(array[lo]);
-                propagateCompletion();
-            }
-        }
-        if (array.length > 0)
-            new Task(null, 0, array.length).invoke();
-    }
-
-    void testRecursiveDecomposition(
-        BiConsumer<Integer[], Consumer<Integer>> action) {
-        int n = ThreadLocalRandom.current().nextInt(8);
-        Integer[] a = new Integer[n];
-        for (int i = 0; i < n; i++) a[i] = i + 1;
-        AtomicInteger ai = new AtomicInteger(0);
-        action.accept(a, (x) -> ai.addAndGet(x));
-        assertEquals(n * (n + 1) / 2, ai.get());
-    }
-
-    /**
-     * Variants of divide-by-two recursive decomposition into leaf tasks,
-     * as described in the CountedCompleter class javadoc code samples
-     */
-    public void testRecursiveDecomposition() {
-        testRecursiveDecomposition(CountedCompleterTest::forEach1);
-        testRecursiveDecomposition(CountedCompleterTest::forEach2);
-        testRecursiveDecomposition(CountedCompleterTest::forEach3);
-        testRecursiveDecomposition(CountedCompleterTest::forEach4);
-    }
-
 }
--- a/jdk/test/java/util/concurrent/tck/DelayQueueTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/DelayQueueTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -66,8 +66,16 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return DelayQueue.class; }
+            public Collection emptyCollection() { return new DelayQueue(); }
+            public Object makeElement(int i) { return new PDelay(i); }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(DelayQueueTest.class,
-                            new Generic().testSuite());
+                            new Generic().testSuite(),
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
@@ -144,7 +152,7 @@
 
     /**
      * Returns a new queue of given size containing consecutive
-     * PDelays 0 ... n.
+     * PDelays 0 ... n - 1.
      */
     private DelayQueue<PDelay> populatedQueue(int n) {
         DelayQueue<PDelay> q = new DelayQueue<PDelay>();
@@ -156,6 +164,7 @@
         assertFalse(q.isEmpty());
         assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
         assertEquals(n, q.size());
+        assertEquals(new PDelay(0), q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/ExecutorCompletionService9Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ExecutorCompletionService9Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -34,6 +34,7 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
 import java.util.HashSet;
@@ -77,7 +78,7 @@
         List<Future<Integer>> futures = new ArrayList<>(n);
         Integer result = null;
         try {
-            solvers.forEach((solver) -> futures.add(cs.submit(solver)));
+            solvers.forEach(solver -> futures.add(cs.submit(solver)));
             for (int i = n; i > 0; i--) {
                 try {
                     Integer r = cs.take().get();
@@ -88,17 +89,17 @@
                 } catch (ExecutionException ignore) {}
             }
         } finally {
-            futures.forEach((future) -> future.cancel(true));
+            futures.forEach(future -> future.cancel(true));
         }
 
         if (result != null)
             use(result);
     }
 
-    HashSet<Integer> results;
+    ArrayList<Integer> results;
 
     void use(Integer x) {
-        if (results == null) results = new HashSet<Integer>();
+        if (results == null) results = new ArrayList<Integer>();
         results.add(x);
     }
 
@@ -107,6 +108,7 @@
      */
     public void testSolveAll()
         throws InterruptedException, ExecutionException {
+        results = null;
         Set<Callable<Integer>> solvers = Set.of(
             () -> null,
             () -> 1,
@@ -114,7 +116,8 @@
             () -> 3,
             () -> null);
         solveAll(cachedThreadPool, solvers);
-        assertEquals(Set.of(1, 2, 3), results);
+        results.sort(Comparator.naturalOrder());
+        assertEquals(List.of(1, 2, 3), results);
     }
 
     /**
@@ -122,6 +125,7 @@
      */
     public void testSolveAny()
         throws InterruptedException {
+        results = null;
         Set<Callable<Integer>> solvers = Set.of(
             () -> { throw new ArithmeticException(); },
             () -> null,
@@ -129,7 +133,7 @@
             () -> 2);
         solveAny(cachedThreadPool, solvers);
         assertEquals(1, results.size());
-        Integer elt = results.iterator().next();
+        Integer elt = results.get(0);
         assertTrue(elt.equals(1) || elt.equals(2));
     }
 
--- a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java	Thu Dec 01 21:39:49 2016 +0000
@@ -36,7 +36,8 @@
 /*
  * @test
  * @summary JSR-166 tck tests
- * @modules java.management
+ * @modules java.base/java.util.concurrent:open
+ *          java.management
  * @build *
  * @run junit/othervm/timeout=1000 -Djsr166.testImplementationDetails=true JSR166TestCase
  * @run junit/othervm/timeout=1000 -Djava.util.concurrent.ForkJoinPool.common.parallelism=0 -Djsr166.testImplementationDetails=true JSR166TestCase
@@ -68,6 +69,7 @@
 import java.security.SecurityPermission;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
@@ -474,6 +476,7 @@
             AbstractQueuedLongSynchronizerTest.suite(),
             ArrayBlockingQueueTest.suite(),
             ArrayDequeTest.suite(),
+            ArrayListTest.suite(),
             AtomicBooleanTest.suite(),
             AtomicIntegerArrayTest.suite(),
             AtomicIntegerFieldUpdaterTest.suite(),
@@ -496,6 +499,7 @@
             CopyOnWriteArrayListTest.suite(),
             CopyOnWriteArraySetTest.suite(),
             CountDownLatchTest.suite(),
+            CountedCompleterTest.suite(),
             CyclicBarrierTest.suite(),
             DelayQueueTest.suite(),
             EntryTest.suite(),
@@ -524,15 +528,17 @@
             TreeMapTest.suite(),
             TreeSetTest.suite(),
             TreeSubMapTest.suite(),
-            TreeSubSetTest.suite());
+            TreeSubSetTest.suite(),
+            VectorTest.suite());
 
         // Java8+ test classes
         if (atLeastJava8()) {
             String[] java8TestClassNames = {
+                "ArrayDeque8Test",
                 "Atomic8Test",
                 "CompletableFutureTest",
                 "ConcurrentHashMap8Test",
-                "CountedCompleterTest",
+                "CountedCompleter8Test",
                 "DoubleAccumulatorTest",
                 "DoubleAdderTest",
                 "ForkJoinPool8Test",
@@ -1850,12 +1856,22 @@
         }
     }
 
+    void assertImmutable(final Object o) {
+        if (o instanceof Collection) {
+            assertThrows(
+                UnsupportedOperationException.class,
+                new Runnable() { public void run() {
+                        ((Collection) o).add(null);}});
+        }
+    }
+
     @SuppressWarnings("unchecked")
     <T> T serialClone(T o) {
         try {
             ObjectInputStream ois = new ObjectInputStream
                 (new ByteArrayInputStream(serialBytes(o)));
             T clone = (T) ois.readObject();
+            if (o == clone) assertImmutable(o);
             assertSame(o.getClass(), clone.getClass());
             return clone;
         } catch (Throwable fail) {
@@ -1864,6 +1880,46 @@
         }
     }
 
+    /**
+     * A version of serialClone that leaves error handling (for
+     * e.g. NotSerializableException) up to the caller.
+     */
+    @SuppressWarnings("unchecked")
+    <T> T serialClonePossiblyFailing(T o)
+        throws ReflectiveOperationException, java.io.IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(o);
+        oos.flush();
+        oos.close();
+        ObjectInputStream ois = new ObjectInputStream
+            (new ByteArrayInputStream(bos.toByteArray()));
+        T clone = (T) ois.readObject();
+        if (o == clone) assertImmutable(o);
+        assertSame(o.getClass(), clone.getClass());
+        return clone;
+    }
+
+    /**
+     * If o implements Cloneable and has a public clone method,
+     * returns a clone of o, else null.
+     */
+    @SuppressWarnings("unchecked")
+    <T> T cloneableClone(T o) {
+        if (!(o instanceof Cloneable)) return null;
+        final T clone;
+        try {
+            clone = (T) o.getClass().getMethod("clone").invoke(o);
+        } catch (NoSuchMethodException ok) {
+            return null;
+        } catch (ReflectiveOperationException unexpected) {
+            throw new Error(unexpected);
+        }
+        assertNotSame(o, clone); // not 100% guaranteed by spec
+        assertSame(o.getClass(), clone.getClass());
+        return clone;
+    }
+
     public void assertThrows(Class<? extends Throwable> expectedExceptionClass,
                              Runnable... throwingActions) {
         for (Runnable throwingAction : throwingActions) {
--- a/jdk/test/java/util/concurrent/tck/LinkedBlockingDequeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/LinkedBlockingDequeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -68,14 +68,22 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return LinkedBlockingDeque.class; }
+            public Collection emptyCollection() { return new LinkedBlockingDeque(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(LinkedBlockingDequeTest.class,
                             new Unbounded().testSuite(),
-                            new Bounded().testSuite());
+                            new Bounded().testSuite(),
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new deque of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private LinkedBlockingDeque<Integer> populatedDeque(int n) {
         LinkedBlockingDeque<Integer> q =
@@ -86,6 +94,8 @@
         assertFalse(q.isEmpty());
         assertEquals(0, q.remainingCapacity());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peekFirst());
+        assertEquals((Integer) (n - 1), q.peekLast());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/LinkedBlockingQueueTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/LinkedBlockingQueueTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -68,14 +68,22 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return LinkedBlockingQueue.class; }
+            public Collection emptyCollection() { return new LinkedBlockingQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(LinkedBlockingQueueTest.class,
                             new Unbounded().testSuite(),
-                            new Bounded().testSuite());
+                            new Bounded().testSuite(),
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private LinkedBlockingQueue<Integer> populatedQueue(int n) {
         LinkedBlockingQueue<Integer> q =
@@ -86,6 +94,7 @@
         assertFalse(q.isEmpty());
         assertEquals(0, q.remainingCapacity());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/LinkedListTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/LinkedListTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -48,12 +48,27 @@
     }
 
     public static Test suite() {
-        return new TestSuite(LinkedListTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return LinkedList.class; }
+            public Collection emptyCollection() { return new LinkedList(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return true; }
+        }
+        class SubListImplementation extends Implementation {
+            public Collection emptyCollection() {
+                return new LinkedList().subList(0, 0);
+            }
+        }
+        return newTestSuite(
+                LinkedListTest.class,
+                CollectionTest.testSuite(new Implementation()),
+                CollectionTest.testSuite(new SubListImplementation()));
     }
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private LinkedList<Integer> populatedQueue(int n) {
         LinkedList<Integer> q = new LinkedList<Integer>();
@@ -62,6 +77,8 @@
             assertTrue(q.offer(new Integer(i)));
         assertFalse(q.isEmpty());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peekFirst());
+        assertEquals((Integer) (n - 1), q.peekLast());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/LinkedTransferQueueTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/LinkedTransferQueueTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -51,14 +51,6 @@
 
 @SuppressWarnings({"unchecked", "rawtypes"})
 public class LinkedTransferQueueTest extends JSR166TestCase {
-    static class Implementation implements CollectionImplementation {
-        public Class<?> klazz() { return LinkedTransferQueue.class; }
-        public Collection emptyCollection() { return new LinkedTransferQueue(); }
-        public Object makeElement(int i) { return i; }
-        public boolean isConcurrent() { return true; }
-        public boolean permitsNulls() { return false; }
-    }
-
     public static class Generic extends BlockingQueueTest {
         protected BlockingQueue emptyCollection() {
             return new LinkedTransferQueue();
@@ -70,6 +62,13 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return LinkedTransferQueue.class; }
+            public Collection emptyCollection() { return new LinkedTransferQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(LinkedTransferQueueTest.class,
                             new Generic().testSuite(),
                             CollectionTest.testSuite(new Implementation()));
--- a/jdk/test/java/util/concurrent/tck/PriorityBlockingQueueTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/PriorityBlockingQueueTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -69,9 +69,17 @@
     }
 
     public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return PriorityBlockingQueue.class; }
+            public Collection emptyCollection() { return new PriorityBlockingQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return false; }
+        }
         return newTestSuite(PriorityBlockingQueueTest.class,
                             new Generic().testSuite(),
-                            new InitialCapacity().testSuite());
+                            new InitialCapacity().testSuite(),
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     /** Sample Comparator */
@@ -83,7 +91,7 @@
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private PriorityBlockingQueue<Integer> populatedQueue(int n) {
         PriorityBlockingQueue<Integer> q =
@@ -96,6 +104,7 @@
         assertFalse(q.isEmpty());
         assertEquals(Integer.MAX_VALUE, q.remainingCapacity());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/PriorityQueueTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/PriorityQueueTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -49,7 +49,15 @@
         main(suite(), args);
     }
     public static Test suite() {
-        return new TestSuite(PriorityQueueTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return PriorityQueue.class; }
+            public Collection emptyCollection() { return new PriorityQueue(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return false; }
+        }
+        return newTestSuite(PriorityQueueTest.class,
+                            CollectionTest.testSuite(new Implementation()));
     }
 
     static class MyReverseComparator implements Comparator {
@@ -60,7 +68,7 @@
 
     /**
      * Returns a new queue of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private PriorityQueue<Integer> populatedQueue(int n) {
         PriorityQueue<Integer> q = new PriorityQueue<Integer>(n);
@@ -71,6 +79,7 @@
             assertTrue(q.offer(new Integer(i)));
         assertFalse(q.isEmpty());
         assertEquals(n, q.size());
+        assertEquals((Integer) 0, q.peek());
         return q;
     }
 
--- a/jdk/test/java/util/concurrent/tck/StampedLockTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/StampedLockTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -110,12 +110,12 @@
 
     List<Function<StampedLock, Long>> readLockers() {
         List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
-        readLockers.add((sl) -> sl.readLock());
-        readLockers.add((sl) -> sl.tryReadLock());
-        readLockers.add((sl) -> readLockInterruptiblyUninterrupted(sl));
-        readLockers.add((sl) -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
-        readLockers.add((sl) -> tryReadLockUninterrupted(sl, 0L, DAYS));
-        readLockers.add((sl) -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
+        readLockers.add(sl -> sl.readLock());
+        readLockers.add(sl -> sl.tryReadLock());
+        readLockers.add(sl -> readLockInterruptiblyUninterrupted(sl));
+        readLockers.add(sl -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+        readLockers.add(sl -> tryReadLockUninterrupted(sl, 0L, DAYS));
+        readLockers.add(sl -> sl.tryConvertToReadLock(sl.tryOptimisticRead()));
         return readLockers;
     }
 
@@ -131,12 +131,12 @@
 
     List<Function<StampedLock, Long>> writeLockers() {
         List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
-        writeLockers.add((sl) -> sl.writeLock());
-        writeLockers.add((sl) -> sl.tryWriteLock());
-        writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
-        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
-        writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0L, DAYS));
-        writeLockers.add((sl) -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
+        writeLockers.add(sl -> sl.writeLock());
+        writeLockers.add(sl -> sl.tryWriteLock());
+        writeLockers.add(sl -> writeLockInterruptiblyUninterrupted(sl));
+        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+        writeLockers.add(sl -> tryWriteLockUninterrupted(sl, 0L, DAYS));
+        writeLockers.add(sl -> sl.tryConvertToWriteLock(sl.tryOptimisticRead()));
         return writeLockers;
     }
 
--- a/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/SubmissionPublisherTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -963,7 +963,7 @@
         AtomicInteger sum = new AtomicInteger();
         SubmissionPublisher<Integer> p = basicPublisher();
         CompletableFuture<Void> f =
-            p.consume((Integer x) -> { sum.getAndAdd(x.intValue()); });
+            p.consume((Integer x) -> sum.getAndAdd(x.intValue()));
         int n = 20;
         for (int i = 1; i <= n; ++i)
             p.submit(i);
--- a/jdk/test/java/util/concurrent/tck/ThreadLocalRandom8Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ThreadLocalRandom8Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -259,4 +259,20 @@
         assertEquals(size, counter.sum());
     }
 
+    /**
+     * A deserialized ThreadLocalRandom is always identical to
+     * ThreadLocalRandom.current()
+     */
+    public void testSerialization() {
+        assertSame(
+            ThreadLocalRandom.current(),
+            serialClone(ThreadLocalRandom.current()));
+        // In the current implementation, there is exactly one shared instance
+        if (testImplementationDetails)
+            assertSame(
+                ThreadLocalRandom.current(),
+                java.util.concurrent.CompletableFuture.supplyAsync(
+                    () -> serialClone(ThreadLocalRandom.current())).join());
+    }
+
 }
--- a/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/ThreadLocalRandomTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -79,6 +79,41 @@
     }
 
     /**
+     * Repeated calls to next (only accessible via reflection) produce
+     * at least two distinct results, and repeated calls produce all
+     * possible values.
+     */
+    public void testNext() throws ReflectiveOperationException {
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        try {
+            java.lang.reflect.Method m
+                = ThreadLocalRandom.class.getDeclaredMethod(
+                    "next", new Class[] { int.class });
+            m.setAccessible(true);
+
+            int i;
+            {
+                int val = new java.util.Random().nextInt(4);
+                for (i = 0; i < NCALLS; i++) {
+                    int q = (int) m.invoke(rnd, new Object[] { 2 });
+                    if (val == q) break;
+                }
+                assertTrue(i < NCALLS);
+            }
+
+            {
+                int r = (int) m.invoke(rnd, new Object[] { 3 });
+                for (i = 0; i < NCALLS; i++) {
+                    int q = (int) m.invoke(rnd, new Object[] { 3 });
+                    assertTrue(q < (1<<3));
+                    if (r != q) break;
+                }
+                assertTrue(i < NCALLS);
+            }
+        } catch (SecurityException acceptable) {}
+    }
+
+    /**
      * Repeated calls to nextInt produce at least two distinct results
      */
     public void testNextInt() {
--- a/jdk/test/java/util/concurrent/tck/TreeSetTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/TreeSetTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -67,7 +67,7 @@
 
     /**
      * Returns a new set of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private TreeSet<Integer> populatedSet(int n) {
         TreeSet<Integer> q = new TreeSet<Integer>();
--- a/jdk/test/java/util/concurrent/tck/TreeSubSetTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/concurrent/tck/TreeSubSetTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -58,7 +58,7 @@
 
     /**
      * Returns a new set of given size containing consecutive
-     * Integers 0 ... n.
+     * Integers 0 ... n - 1.
      */
     private NavigableSet<Integer> populatedSet(int n) {
         TreeSet<Integer> q = new TreeSet<Integer>();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/tck/VectorTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from
+ * members of JCP JSR-166 Expert Group and released to the public
+ * domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+import java.util.Vector;
+import java.util.Collection;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class VectorTest extends JSR166TestCase {
+    public static void main(String[] args) {
+        main(suite(), args);
+    }
+
+    public static Test suite() {
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return Vector.class; }
+            public List emptyCollection() { return new Vector(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return false; }
+            public boolean permitsNulls() { return true; }
+        }
+        class SubListImplementation extends Implementation {
+            public List emptyCollection() {
+                return super.emptyCollection().subList(0, 0);
+            }
+        }
+        return newTestSuite(
+                // VectorTest.class,
+                CollectionTest.testSuite(new Implementation()),
+                CollectionTest.testSuite(new SubListImplementation()));
+    }
+
+}
--- a/jdk/test/java/util/logging/FileHandlerLongLimit.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/logging/FileHandlerLongLimit.java	Thu Dec 01 21:39:49 2016 +0000
@@ -52,6 +52,7 @@
  * @test
  * @bug 8059767
  * @summary tests that FileHandler can accept a long limit.
+ * @modules java.logging/java.util.logging:open
  * @run main/othervm FileHandlerLongLimit UNSECURE
  * @run main/othervm FileHandlerLongLimit SECURE
  * @author danielfuchs
--- a/jdk/test/java/util/logging/HandlersConfigTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/logging/HandlersConfigTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,6 +28,7 @@
  *          configured correctly from defaults and/or LogManager properties
  *          as specified in javadoc and that no special
  *          logging permission is required for instantiating them.
+ * @modules java.logging/java.util.logging:open
  * @run main/othervm HandlersConfigTest default
  * @run main/othervm HandlersConfigTest configured
  */
--- a/jdk/test/java/util/logging/LocalizedLevelName.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/logging/LocalizedLevelName.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
  * @test
  * @bug 8016127 8024131
  * @summary test logging.properties localized
+ * @modules java.logging/sun.util.logging.resources:open
  * @run main/othervm LocalizedLevelName
  */
 
--- a/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -61,6 +61,7 @@
  * @test
  * @bug 8033661
  * @summary tests LogManager.updateConfiguration(bin)
+ * @modules java.logging/java.util.logging:open
  * @run main/othervm UpdateConfigurationTest UNSECURE
  * @run main/othervm UpdateConfigurationTest SECURE
  * @author danielfuchs
--- a/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -136,10 +136,6 @@
         // class resource bundle in another named module m1.
         failToLoadResourceBundle("mylogger.g", "p1.resource.ClassResource",
                 true, NAMED_NEGATIVE_CLASSBUNDLE_MSG);
-        // in named module m2, try to create a logger with
-        // class resource bundle in an unnamed module.
-        failToLoadResourceBundle("mylogger.h", "p3.resource.ClassResource",
-                true, NAMED_NEGATIVE_CLASSBUNDLE_MSG);
     }
 
     static void failToLoadPropertyRBs() {
@@ -153,10 +149,6 @@
         // property resource bundle in another named module m1.
         failToLoadResourceBundle("mylogger.k", "p1.resource.p",
                 true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG);
-        // in named module m2, try to create a logger with
-        // property resource bundle in an unnamed module.
-        failToLoadResourceBundle("mylogger.l", "p3.resource.p",
-                true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG);
     }
 
     static void failToLoadResourceBundle(String loggerName, String rbName,
--- a/jdk/test/javax/management/ObjectName/CompressedStorageTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/management/ObjectName/CompressedStorageTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,7 +27,7 @@
  * @summary Tests the limits imposed on the domain name part of an
  *          ObjectName instance
  * @author Jaroslav Bachorik
- * @modules java.management
+ * @modules java.management/javax.management:open
  * @run main CompressedStorageTest
  */
 
--- a/jdk/test/javax/management/loading/MLetInternalsTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/management/loading/MLetInternalsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -36,7 +36,7 @@
  * @bug 8058089
  * @summary Tests various internal functions provided by MLet for correctness
  * @author Jaroslav Bachorik
- * @modules java.management
+ * @modules java.management/javax.management.loading:open
  * @run testng MLetInternalsTest
  */
 public class MLetInternalsTest {
--- a/jdk/test/javax/management/openmbean/TabularDataOrderTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/management/openmbean/TabularDataOrderTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,7 +26,7 @@
  * @bug 6334663
  * @summary Test that TabularDataSupport preserves the order elements were added
  * @author Eamonn McManus
- * @modules java.management
+ * @modules java.management/javax.management.openmbean:open
  */
 
 import java.io.ByteArrayInputStream;
--- a/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connection/ObjectInputStreamWithLoaderNullCheckTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,7 +29,7 @@
  *          thrown when constructor is invoked with null class loader as
  *          an argument.
  * @author Amit Sapre
- * @modules java.management
+ * @modules java.management/javax.management.remote.rmi:open
  * @run clean ObjectInputStreamWithLoaderNullCheckTest
  * @run build ObjectInputStreamWithLoaderNullCheckTest
  * @run main ObjectInputStreamWithLoaderNullCheckTest
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectionIdTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectionIdTest.java	Thu Dec 01 21:39:49 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
@@ -24,7 +24,7 @@
 /*
  * @test
  * @bug 4901808 7183800
- * @summary Check that RMI connection ids include client host name
+ * @summary Check that RMI connection ids include IP address of a client network interface
  * @author Eamonn McManus
  * @modules java.management
  * @run clean RMIConnectionIdTest
@@ -39,7 +39,7 @@
 public class RMIConnectionIdTest {
     public static void main(String[] args) throws Exception {
         System.out.println("Testing that RMI connection id includes " +
-                           "client host name");
+                           "IP address of a client network interface");
         MBeanServer mbs = MBeanServerFactory.createMBeanServer();
         JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
         JMXConnectorServer cs =
@@ -61,11 +61,9 @@
         }
         String clientAddr = rest.substring(0, spaceIndex);
         InetAddress clientInetAddr = InetAddress.getByName(clientAddr);
-        InetAddress localAddr = clientInetAddr.isLoopbackAddress() ? InetAddress.getLoopbackAddress() : InetAddress.getLocalHost();
-        System.out.println("InetAddresses: local=" + localAddr + "; " +
-                           "connectionId=" + clientInetAddr);
-        if (!localAddr.equals(clientInetAddr)) {
-            System.out.println("TEST FAILS: addresses differ");
+        NetworkInterface ni = NetworkInterface.getByInetAddress(clientInetAddr);
+        if (ni == null) {
+            System.out.println("TEST FAILS: address not found");
             System.exit(1);
         }
         cc.close();
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -42,7 +42,7 @@
  * @bug 6566891
  * @summary Check no memory leak on RMIConnector's rmbscMap
  * @author Shanliang JIANG
- * @modules java.management
+ * @modules java.management/javax.management.remote.rmi:open
  * @run clean RMIConnectorInternalMapTest
  * @run build RMIConnectorInternalMapTest
  * @run main RMIConnectorInternalMapTest
--- a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -38,7 +38,7 @@
  * @bug 6566891
  * @summary Check no memory leak on RMIConnector's nullSubjectConn
  * @author Shanliang JIANG
- * @modules java.management
+ * @modules java.management/javax.management.remote.rmi:open
  * @run clean RMIConnectorNullSubjectConnTest
  * @run build RMIConnectorNullSubjectConnTest
  * @run main RMIConnectorNullSubjectConnTest
--- a/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/management/remote/mandatory/notif/DeadListenerTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,8 @@
  * @test
  * @bug 6957378
  * @summary Test that a listener can be removed remotely from an MBean that no longer exists.
- * @modules java.management/com.sun.jmx.remote.internal
+ * @modules java.management/javax.management.remote.rmi:open
+ *          java.management/com.sun.jmx.remote.internal:+open
  * @author Eamonn McManus
  * @run main/othervm -XX:+UsePerfData DeadListenerTest
  */
--- a/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSBufferOverflowUnderflowTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,8 +30,8 @@
  * @modules java.security.jgss
  *          jdk.security.auth
  *          java.base/sun.security.util
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
  *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
--- a/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSDataExchangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSEnginesClosureTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSHandshakeWithReplicatedPacketsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSIncorrectAppDataTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSMFLNTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSNotEnabledRC4Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,10 +27,10 @@
  * @summary Testing DTLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS DTLSNotEnabledRC4Test
--- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithCipherChangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSRehandshakeWithDataExTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSSequenceNumberTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS
--- a/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSUnsupportedCiphersTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,10 +28,10 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLS DTLSUnsupportedCiphersTest
--- a/jdk/test/javax/net/ssl/DTLS/TEST.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -1,7 +1,7 @@
 modules = \
-    java.security.jgss/sun.security.krb5 \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.security.jgss/sun.security.krb5.internal.ktab \
     java.base/sun.security.util
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10BufferOverflowUnderflowTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10DataExchangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10EnginesClosureTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10HandshakeWithReplicatedPacketsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon /javax/net/ssl/DTLS
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10IncorrectAppDataTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon /javax/net/ssl/DTLS
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10MFLNTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10NotEnabledRC4Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,10 +27,10 @@
  * @summary Testing DTLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0 DTLSv10NotEnabledRC4Test
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithCipherChangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10RehandshakeWithDataExTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10SequenceNumberTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon /javax/net/ssl/DTLS
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/DTLSv10UnsupportedCiphersTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,10 +28,10 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=DTLSv1.0
--- a/jdk/test/javax/net/ssl/DTLSv10/TEST.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/DTLSv10/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -1,7 +1,7 @@
 modules = \
-    java.security.jgss/sun.security.krb5 \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.security.jgss/sun.security.krb5.internal.ktab \
     java.base/sun.security.util
--- a/jdk/test/javax/net/ssl/TLS/TEST.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -1,8 +1,8 @@
 modules = \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ktab \
-    java.security.jgss/sun.security.krb5 \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.base/sun.security.util \
     jdk.crypto.ec/sun.security.ec
--- a/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSClientPropertyTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,11 +28,11 @@
  * @summary javax/net/ssl/TLS/TLSClientPropertyTest.java needs to be
  *     updated for JDK-8061210
  * @modules java.security.jgss
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm TLSClientPropertyTest NoProperty
  * @run main/othervm TLSClientPropertyTest SSLv3
--- a/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSDataExchangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,11 +29,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSDataExchangeTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSDataExchangeTest
--- a/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,11 +29,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSEnginesClosureTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSEnginesClosureTest
--- a/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSHandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,11 +29,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSHandshakeTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSHandshakeTest
--- a/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSMFLNTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,11 +30,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSMFLNTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSMFLNTest
--- a/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,11 +27,11 @@
  * @summary Testing TLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS TLSNotEnabledRC4Test
  */
--- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,11 +29,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSRehandshakeTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSRehandshakeTest
--- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,11 +29,11 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS TLSRehandshakeWithCipherChangeTest
  */
--- a/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,11 +30,11 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSRehandshakeWithDataExTest
  * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSRehandshakeWithDataExTest
--- a/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,11 +28,11 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLS TLSUnsupportedCiphersTest
  */
--- a/jdk/test/javax/net/ssl/TLSv1/TEST.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -1,7 +1,7 @@
 modules = \
-    java.security.jgss/sun.security.krb5 \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.security.jgss/sun.security.krb5.internal.ktab \
     java.base/sun.security.util
--- a/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSDataExchangeTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSEnginesClosureTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSHandshakeTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSMFLNTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSMFLNTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,10 +27,10 @@
  * @summary Testing TLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 TLSNotEnabledRC4Test
--- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSRehandshakeTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 TLSRehandshakeWithCipherChangeTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSRehandshakeWithDataExTest
--- a/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,10 +28,10 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1 TLSUnsupportedCiphersTest
--- a/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/EmptyCertificateAuthorities.java	Thu Dec 01 21:39:49 2016 +0000
@@ -34,10 +34,10 @@
  * @summary Support TLS 1.1
  * @run main/othervm EmptyCertificateAuthorities
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @author Xuelei Fan
--- a/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java	Thu Dec 01 21:39:49 2016 +0000
@@ -34,10 +34,10 @@
  * @summary Support TLS 1.1
  * @run main/othervm ExportableBlockCipher
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @author Xuelei Fan
--- a/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java	Thu Dec 01 21:39:49 2016 +0000
@@ -33,10 +33,10 @@
  * @bug 4873188
  * @summary Support TLS 1.1
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm ExportableStreamCipher
--- a/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/GenericBlockCipher.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,10 +28,10 @@
  * @bug 4873188
  * @summary Support TLS 1.1
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm GenericBlockCipher
--- a/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/GenericStreamCipher.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,10 +28,10 @@
  * @bug 4873188
  * @summary Support TLS 1.1
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm GenericStreamCipher
--- a/jdk/test/javax/net/ssl/TLSv11/TEST.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -1,7 +1,7 @@
 modules = \
-    java.security.jgss/sun.security.krb5 \
+    java.security.jgss/sun.security.krb5:+open \
     java.security.jgss/sun.security.krb5.internal.crypto \
     java.security.jgss/sun.security.krb5.internal.ccache \
-    java.security.jgss/sun.security.krb5.internal \
+    java.security.jgss/sun.security.krb5.internal:+open \
     java.security.jgss/sun.security.krb5.internal.ktab \
     java.base/sun.security.util
--- a/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSDataExchangeTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSEnginesClosureTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSHandshakeTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSMFLNTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSMFLNTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,10 +27,10 @@
  * @summary Testing TLS engines do not enable RC4 ciphers by default.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSNotEnabledRC4Test
--- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSRehandshakeTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,10 +29,10 @@
  * @key randomness
  * @library /sun/security/krb5/auto /lib/testlibrary /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSRehandshakeWithCipherChangeTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,10 +30,10 @@
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
  *          jdk.security.auth
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSRehandshakeWithDataExTest
--- a/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,10 +28,10 @@
  *          causes IllegalArgumentException.
  * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
  * @modules java.security.jgss
- *          java.security.jgss/sun.security.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.ccache
- *          java.security.jgss/sun.security.krb5.internal
  *          java.security.jgss/sun.security.krb5.internal.ktab
  *          java.base/sun.security.util
  * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSUnsupportedCiphersTest
--- a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/ImplicitOpenClose.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,7 +23,7 @@
 
 /* @test
    @summary Test SoftSynthesizer implicit open/close using getReceiver.
-   @modules java.desktop/com.sun.media.sound
+   @modules java.desktop/com.sun.media.sound:+open
 */
 
 import java.lang.reflect.Field;
--- a/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/sound/midi/Gervill/SoftSynthesizer/Open.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,7 +23,7 @@
 
 /* @test
    @summary Test SoftSynthesizer open method
-   @modules java.desktop/com.sun.media.sound
+   @modules java.desktop/com.sun.media.sound:+open
 */
 
 import java.lang.reflect.Field;
--- a/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/JFileChooser/6688203/bug6688203.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,6 +25,7 @@
    @bug 6688203
    @summary Memory leak and performance problems in the method getFileSystemView of FileSystemView
    @author Pavel Porvatov
+   @modules java.desktop/javax.swing.filechooser:open
    @run main bug6688203
 */
 
--- a/jdk/test/javax/swing/JLabel/7004134/bug7004134.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/JLabel/7004134/bug7004134.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,6 +28,7 @@
  * @summary JLabel containing a ToolTipText does no longer show ToolTip after browser refresh
  * @author Pavel Porvatov
  * @modules java.desktop/sun.awt
+ * @modules java.desktop/javax.swing:open
  */
 
 import sun.awt.SunToolkit;
--- a/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/JPopupMenu/6495920/bug6495920.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,6 +30,7 @@
  * @author Sergey Malenkov
  * @library ../..
  * @modules java.desktop/sun.awt
+ * @modules java.desktop/javax.swing.plaf.basic:open
  */
 
 import sun.awt.AppContext;
--- a/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/JPopupMenu/6800513/bug6800513.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,6 +28,7 @@
  * @bug 6800513
  * @summary GTK-LaF renders menus incompletely
  * @author Mario Torre
+ * @modules java.desktop/javax.swing:open
  * @library ../../regtesthelpers/
  * @build Util
  * @run main bug6800513
--- a/jdk/test/javax/swing/JSlider/6794836/bug6794836.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/JSlider/6794836/bug6794836.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,6 +27,7 @@
  * @bug 6794836
  * @summary BasicSliderUI throws NullPointerExc when JSlider maximum is Integer.MAX_VALUE
  * @author Pavel Porvatov
+ * @modules java.desktop/javax.swing.plaf.basic:open
  * @run main bug6794836
  */
 
--- a/jdk/test/javax/swing/JSlider/6848475/bug6848475.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/JSlider/6848475/bug6848475.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,6 +27,7 @@
  * @bug 6848475
  * @summary JSlider does not display the correct value of its BoundedRangeModel
  * @author Pavel Porvatov
+ * @modules java.desktop/javax.swing.plaf.basic:open
  * @run main bug6848475
  */
 
--- a/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/JTabbedPane/7010561/bug7010561.java	Thu Dec 01 21:39:49 2016 +0000
@@ -29,6 +29,7 @@
 /* @test
    @bug 7010561
    @summary Tab text position with Synth based LaF is different to Java 5/6
+   @modules java.desktop/javax.swing.plaf.basic:open
    @author Pavel Porvatov
 */
 public class bug7010561 {
--- a/jdk/test/javax/swing/JTree/6263446/bug6263446.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/JTree/6263446/bug6263446.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,6 +27,7 @@
  * @bug 6263446
  * @summary Tests that double-clicking to edit a cell doesn't select the content.
  * @author Shannon Hickey
+ * @modules java.desktop/javax.swing.tree:open
  * @run main bug6263446
  */
 import java.awt.*;
--- a/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,6 +24,7 @@
 /* @test
    @bug 7013453
    @summary BufferStrategyPaintManager.dispose will cause IllegalMonitorStateException in event thread
+   @modules java.desktop/javax.swing:open
    @author Pavel Porvatov
 */
 
--- a/jdk/test/javax/swing/Security/6938813/bug6938813.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/Security/6938813/bug6938813.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,7 @@
  * @bug 6938813
  * @summary Swing mutable statics
  * @author Pavel Porvatov
+ * @modules java.desktop/javax.swing.text.html.parser:open
  * @modules java.desktop/sun.awt
  */
 
--- a/jdk/test/javax/swing/border/Test7149090.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/border/Test7149090.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,6 +24,7 @@
 /* @test
    @bug 7149090
    @summary Nimbus:BorderFactory.createTitledBorder() the DEFAULT position of a title is not the same as the TOP
+   @modules java.desktop/javax.swing.border:open
    @author Pavel Porvatov
 */
 
--- a/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/plaf/synth/7143614/bug7143614.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,7 @@
  * @bug 7143614
  * @summary Issues with Synth Look&Feel
  * @author Pavel Porvatov
+ * @modules java.desktop/javax.swing.plaf.synth:open
  * @modules java.desktop/sun.awt
  */
 
--- a/jdk/test/javax/swing/text/View/8014863/bug8014863.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/swing/text/View/8014863/bug8014863.java	Thu Dec 01 21:39:49 2016 +0000
@@ -28,6 +28,7 @@
  * @bug 8024395
  * @summary  Tests the calculation of the line breaks when a text is inserted
  * @author Dmitry Markov
+ * @modules java.desktop/javax.swing.text:open
  * @library ../../../regtesthelpers
  * @build Util
  * @run main bug8014863
--- a/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java	Thu Dec 01 21:39:49 2016 +0000
@@ -30,7 +30,7 @@
  *      correctly maps them to their preferred mime names.
  *      Also checks that the Encodings.properties resource file
  *      is consistent.
- * @modules java.xml/com.sun.org.apache.xml.internal.serializer
+ * @modules java.xml/com.sun.org.apache.xml.internal.serializer:+open
  * @compile -XDignore.symbol.file CheckEncodingPropertiesFile.java
  * @run main CheckEncodingPropertiesFile
  * @author Daniel Fuchs
--- a/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/javax/xml/jaxp/PrecisionDecimalDV/XPrecisionDecimalToString.java	Thu Dec 01 21:39:49 2016 +0000
@@ -31,7 +31,7 @@
  *   in com.sun.org.apache.xerces.internal.impl.dv.xs.PrecisionDecimalDV$XPrecisionDecimal.
  *   Since that method is private the test unfortunately needs to use reflection
  *   to invoke the method.
- * @modules java.xml/com.sun.org.apache.xerces.internal.impl.dv.xs
+ * @modules java.xml/com.sun.org.apache.xerces.internal.impl.dv.xs:open
  * @run main XPrecisionDecimalToString
  * @author Daniel Fuchs
  */
--- a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,7 @@
  * @test
  * @bug 8080679 8131913
  * @modules jdk.internal.le/jdk.internal.jline
- *          jdk.internal.le/jdk.internal.jline.console
+ *          jdk.internal.le/jdk.internal.jline.console:+open
  * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly.
  */
 
--- a/jdk/test/jdk/internal/jrtfs/remote/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/jdk/internal/jrtfs/remote/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -68,7 +68,7 @@
     }
 
     private static FileSystem createFsWithURLClassloader(String javaHome) throws IOException{
-        URL url = Paths.get(javaHome, "jrt-fs.jar").toUri().toURL();
+        URL url = Paths.get(javaHome, "lib", "jrt-fs.jar").toUri().toURL();
         URLClassLoader loader = new URLClassLoader(new URL[] { url });
         return FileSystems.newFileSystem(URI.create("jrt:/"),
                                                     Collections.emptyMap(),
--- a/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/jdk/internal/jrtfs/remote/RemoteRuntimeImageTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -64,7 +64,7 @@
         String java = jdk8Path.resolve("bin/java").toAbsolutePath().toString();
         String javac = jdk8Path.resolve("bin/javac").toAbsolutePath().toString();
         Files.createDirectories(Paths.get(".", CLASSES_DIR));
-        String jrtJar = Paths.get(TEST_JAVAHOME, JRTFS_JAR).toAbsolutePath().toString();
+        String jrtJar = Paths.get(TEST_JAVAHOME, "lib", JRTFS_JAR).toAbsolutePath().toString();
 
         // Compose command-lines for compiling and executing tests
         List<List<String>> cmds = Arrays.asList(
--- a/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,7 +22,6 @@
  */
 
 import jdk.internal.misc.Unsafe;
-import java.lang.reflect.Field;
 
 /**
  * Helper class to support testing of Unsafe.copyMemory and Unsafe.copySwapMemory
@@ -37,17 +36,7 @@
     static final int SMALL_COPY_SIZE = 32;
     static final int BASE_ALIGNMENT = 16;
 
-    protected static final Unsafe UNSAFE;
-
-    static {
-        try {
-            Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe");
-            f.setAccessible(true);
-            UNSAFE = (jdk.internal.misc.Unsafe) f.get(null);
-        } catch (Exception e) {
-            throw new RuntimeException("Unable to get Unsafe instance.", e);
-        }
-    }
+    protected static final Unsafe UNSAFE = Unsafe.getUnsafe();
 
     static long alignDown(long value, long alignment) {
         return value & ~(alignment - 1);
--- a/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java	Thu Dec 01 21:39:49 2016 +0000
@@ -152,6 +152,9 @@
         try {
             ClassFileReader reader = ClassFileReader.newInstance(path);
             for (ClassFile cf : reader.getClassFiles()) {
+                if (cf.access_flags.is(AccessFlags.ACC_MODULE))
+                    continue;
+
                 String classFileName = cf.getName();
                 // for each ClassFile
                 //    parse constant pool to find matching method refs
--- a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java	Thu Dec 01 21:39:49 2016 +0000
@@ -50,15 +50,15 @@
     private static final String JAVA_COMPACT2 = "java.compact2";
 
     private static final ModuleDescriptor BASE
-        = new ModuleDescriptor.Builder(JAVA_BASE).build();
+        = ModuleDescriptor.module(JAVA_BASE).build();
 
     private static final ModuleDescriptor COMPACT2
-        = new ModuleDescriptor.Builder(JAVA_COMPACT2)
+        = ModuleDescriptor.module(JAVA_COMPACT2)
             .requires(Set.of(MANDATED), JAVA_BASE)
-            .requires(Set.of(PUBLIC), JAVA_COMPACT1)
-            .requires(Set.of(PUBLIC), "java.rmi")
-            .requires(Set.of(PUBLIC), "java.sql")
-            .requires(Set.of(PUBLIC), "java.xml")
+            .requires(Set.of(TRANSITIVE), JAVA_COMPACT1)
+            .requires(Set.of(TRANSITIVE), "java.rmi")
+            .requires(Set.of(TRANSITIVE), "java.sql")
+            .requires(Set.of(TRANSITIVE), "java.xml")
             .build();
 
     private static final Set<ModuleDescriptor> MREFS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/Basic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,317 @@
+/*
+ * 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
+ * @library modules
+ * @build m1/* m2/*
+ * @run testng/othervm --add-modules=m1,m2 Basic
+ * @summary Basic test of open modules and open packages
+ */
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InaccessibleObjectException;
+import java.lang.reflect.Module;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeTest;
+import static org.testng.Assert.*;
+
+/**
+ * open module m1 {
+ *     exports p;
+ *     // contains p.internal
+ * }
+ *
+ * module m2 {
+ *     exports q;
+ *     exports q;
+ *     // contains q.internal
+ * }
+ *
+ * Each package in m1 and m2 contains a public type a non-public type.
+ */
+
+public class Basic {
+
+    @BeforeTest
+    public void checkSetup() throws Exception {
+        Module m1 = Class.forName("p.PublicType").getModule();
+        assertTrue(m1.isNamed());
+        assertTrue(m1.getDescriptor().isOpen());
+        assertTrue(m1.getDescriptor().packages().size() == 2);
+        assertTrue(m1.getDescriptor().packages().contains("p"));
+        assertTrue(m1.getDescriptor().packages().contains("p.internal"));
+        assertTrue(m1.getDescriptor().exports().size() == 1);
+        ModuleDescriptor.Exports e = m1.getDescriptor().exports().iterator().next();
+        assertTrue(e.source().equals("p"));
+        assertTrue(m1.isOpen("p"));
+        assertTrue(m1.isOpen("p.internal"));
+
+        Module m2 = Class.forName("q.PublicType").getModule();
+        assertTrue(m2.isNamed());
+        assertFalse(m2.getDescriptor().isOpen());
+        assertTrue(m2.getDescriptor().packages().size() == 2);
+        assertTrue(m2.getDescriptor().packages().contains("q"));
+        assertTrue(m2.getDescriptor().packages().contains("q.internal"));
+        assertTrue(m2.getDescriptor().exports().size() == 1);
+        e = m2.getDescriptor().exports().iterator().next();
+        assertTrue(e.source().equals("q"));
+        assertTrue(m2.isOpen("q"));
+        assertFalse(m2.isOpen("p.internal"));
+    }
+
+    @Test
+    public void testPublicTypeInExportedPackage() throws Throwable {
+        // invokespecial
+        new p.PublicType();
+
+        Class<?> clazz = p.PublicType.class;
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        ctor.newInstance();
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testNotPublicTypeInExportedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("p.NotPublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testPublicTypeInNonExportedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("p.internal.PublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        ctor.newInstance(); // should succeed
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testNotPublicTypeInNonExportedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("p.internal.NotPublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testPublicTypeInOpenPackage() throws Throwable {
+        // invokespecial
+        // new q.PublicType();   TBD
+
+        // core reflection
+        Class<?> clazz = q.PublicType.class;
+        clazz.getConstructor().newInstance();
+
+        // method handles
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+
+    }
+
+    @Test
+    public void testNotPublicTypeInOpenPackage() throws Throwable {
+        Class<?> clazz = Class.forName("q.NotPublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        ctor.setAccessible(true);
+        ctor.newInstance();
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        findNoArgConstructorAndInvoke(clazz, lookup);
+    }
+
+    @Test
+    public void testPublicTypeInConcealedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("q.internal.PublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            ctor.setAccessible(true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+    }
+
+    @Test
+    public void testNotPublicTypeInConcealedPackage() throws Throwable {
+        Class<?> clazz = Class.forName("q.internal.NotPublicType");
+
+        // core reflection
+        Constructor<?> ctor = clazz.getConstructor();
+        try {
+            ctor.newInstance();
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            ctor.setAccessible(true);
+            assertTrue(false);
+        } catch (InaccessibleObjectException expected) { }
+
+        // method handles
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.publicLookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            findNoArgConstructorAndInvoke(clazz, MethodHandles.lookup());
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.publicLookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+    }
+
+    /**
+     * Produces the method handle for the no-arg constructor and invokes it
+     */
+    Object findNoArgConstructorAndInvoke(Class<?> clazz, Lookup lookup) throws Throwable {
+        MethodType mt = MethodType.methodType(void.class);
+        MethodHandle mh = lookup.findConstructor(clazz, mt);
+        return mh.invoke();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+open module m1 {
+    exports p;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/p/NotPublicType.java	Thu Dec 01 21:39:49 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.
+ */
+package p;
+
+class NotPublicType {
+    public NotPublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/p/PublicType.java	Thu Dec 01 21:39:49 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.
+ */
+package p;
+
+public class PublicType {
+    public PublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/p/internal/NotPublicType.java	Thu Dec 01 21:39:49 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.
+ */
+package p.internal;
+
+class NotPublicType {
+    public NotPublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m1/p/internal/PublicType.java	Thu Dec 01 21:39:49 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.
+ */
+package p.internal;
+
+public class PublicType {
+    public PublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/module-info.java	Thu Dec 01 21:39:49 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 m2 {
+    exports q;
+    opens q;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/q/NotPublicType.java	Thu Dec 01 21:39:49 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.
+ */
+package q;
+
+class NotPublicType {
+    public NotPublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/q/PublicType.java	Thu Dec 01 21:39:49 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.
+ */
+package q;
+
+public class PublicType {
+    public PublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/q/internal/NotPublicType.java	Thu Dec 01 21:39:49 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.
+ */
+package q.internal;
+
+class NotPublicType {
+    public NotPublicType() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/modules/open/modules/m2/q/internal/PublicType.java	Thu Dec 01 21:39:49 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.
+ */
+package q.internal;
+
+public class PublicType {
+    public PublicType() { }
+}
--- a/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -58,10 +58,10 @@
         assertTrue(requires.contains("java.base"));
 
         // uses ScriptEngineFactory
-        Map<String, Provides> provides = descriptor.provides();
+        Set<Provides> provides = descriptor.provides();
         assertTrue(provides.size() == 1);
         String sn = ScriptEngineFactory.class.getName();
-        assertTrue(provides.containsKey(sn));
+        assertTrue(provides.iterator().next().service().equals(sn));
 
         // Check that it is iterated over with ServiceLoader
         ServiceLoader<ScriptEngineFactory> sl
--- a/jdk/test/sun/net/idn/TestStringPrep.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/net/idn/TestStringPrep.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,8 @@
  * @test
  * @summary Unit test for sun.net.idn.Punycode
  * @bug 4737170 8060097
- * @modules java.base/sun.net.idn java.base/sun.text.normalizer
+ * @modules java.base/sun.net.idn:+open
+ *          java.base/sun.text.normalizer
  * @library .
  * @compile -XDignore.symbol.file TestStringPrep.java NFS4StringPrep.java
  *     TestData.java
--- a/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/net/www/http/HttpClient/IsAvailable.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,7 +27,7 @@
  * @summary HttpClient available() check throws SocketException when connection
  * has been closed
  * @modules java.base/sun.net
- *          java.base/sun.net.www.http
+ *          java.base/sun.net.www.http:+open
  */
 
 import java.net.URL;
--- a/jdk/test/sun/net/www/httptest/TestHttpServer.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/net/www/httptest/TestHttpServer.java	Thu Dec 01 21:39:49 2016 +0000
@@ -116,15 +116,26 @@
         }
     }
 
-    /** Tell all threads in the server to exit within 5 seconds.
-     *  This is an abortive termination. Just prior to the thread exiting
-     *  all channels in that thread waiting to be closed are forceably closed.
+    /**
+     * Tell all threads in the server to exit within 5 seconds.
+     * This is an abortive termination. Just prior to the thread exiting
+     * all channels in that thread waiting to be closed are forceably closed.
+     * @throws InterruptedException
      */
 
     public void terminate () {
         for (int i=0; i<threads; i++) {
             servers[i].terminate ();
         }
+
+        for (int i = 0; i < threads; i++) {
+            try {
+                servers[i].join();
+            } catch (InterruptedException e) {
+                System.err.println("Unexpected InterruptedException during terminating server");
+                throw new RuntimeException(e);
+            }
+        }
     }
 
     /**
@@ -147,7 +158,7 @@
         int maxconn;
         int nconn;
         ClosedChannelList clist;
-        boolean shutdown;
+        volatile boolean shutdown;
 
         Server (HttpCallback cb, ServerSocketChannel schan, int maxconn) {
             this.schan = schan;
@@ -166,18 +177,18 @@
         }
 
         /* Stop the thread as soon as possible */
-        public synchronized void terminate () {
+        public void terminate () {
             shutdown = true;
         }
 
         public void run ()  {
             try {
                 while (true) {
-                    selector.select (1000);
-                    Set selected = selector.selectedKeys();
-                    Iterator iter = selected.iterator();
+                    selector.select(1000);
+                    Set<SelectionKey> selected = selector.selectedKeys();
+                    Iterator<SelectionKey> iter = selected.iterator();
                     while (iter.hasNext()) {
-                        key = (SelectionKey)iter.next();
+                        key = iter.next();
                         if (key.equals (listenerKey)) {
                             SocketChannel sock = schan.accept ();
                             if (sock == null) {
@@ -200,7 +211,7 @@
                                 SocketChannel chan = (SocketChannel) key.channel();
                                 System.out.println("SERVER: connection readable. chan[" + chan + "]");
                                 if (key.attachment() != null) {
-                                    System.out.println("Server: comsume");
+                                    System.out.println("Server: consume");
                                     closed = consume (chan);
                                 } else {
                                     closed = read (chan, key);
@@ -219,7 +230,16 @@
                     }
                     clist.check();
                     if (shutdown) {
+                        System.out.println("Force to Shutdown");
+                        SelectionKey sKey = schan.keyFor(selector);
+                        if (sKey != null) {
+                            sKey.cancel();
+                        }
+
                         clist.terminate ();
+                        selector.close();
+                        schan.socket().close();
+                        schan.close();
                         return;
                     }
                 }
@@ -726,3 +746,4 @@
         }
     }
 }
+
--- a/jdk/test/sun/net/www/protocol/http/NoNTLM.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/net/www/protocol/http/NoNTLM.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,7 +26,7 @@
  * @summary Sanity check that NTLM will not be selected by the http protocol
  *    handler when running on a profile that does not support NTLM
  * @modules java.base/sun.net.www
- *          java.base/sun.net.www.protocol.http
+ *          java.base/sun.net.www.protocol.http:open
  * @run main/othervm NoNTLM
  */
 
--- a/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/jgss/spnego/NotPreferredMech.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,7 +26,7 @@
  * @bug 8048194
  * @modules java.base/sun.security.util
  *          java.security.jgss/sun.security.jgss
- *          java.security.jgss/sun.security.jgss.spnego
+ *          java.security.jgss/sun.security.jgss.spnego:+open
  * @run main/othervm NotPreferredMech
  * @summary GSSContext.acceptSecContext fails when a supported mech is not initiator preferred
  */
--- a/jdk/test/sun/security/krb5/RFC396xTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/krb5/RFC396xTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,7 @@
  * @bug 6862679
  * @modules java.security.jgss/sun.security.krb5
  *          java.security.jgss/sun.security.krb5.internal.crypto
- *          java.security.jgss/sun.security.krb5.internal.crypto.dk
+ *          java.security.jgss/sun.security.krb5.internal.crypto.dk:+open
  * @run main/othervm RFC396xTest
  * @summary ESC: AD Authentication with user with umlauts fails
  */
--- a/jdk/test/sun/security/krb5/auto/Renew.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/krb5/auto/Renew.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,8 +27,8 @@
  * @summary JAAS Krb5LoginModule has suspect ticket-renewal logic,
  *          relies on clockskew grace
  * @modules java.base/sun.security.util
- *          java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
  *          java.security.jgss/sun.security.krb5.internal.ccache
  *          java.security.jgss/sun.security.krb5.internal.crypto
  *          java.security.jgss/sun.security.krb5.internal.ktab
--- a/jdk/test/sun/security/krb5/auto/TEST.properties	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/krb5/auto/TEST.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -1,8 +1,8 @@
 modules java.base/jdk.internal.misc \
         java.base/sun.security.util \
         java.security.jgss/sun.security.jgss \
-        java.security.jgss/sun.security.krb5 \
-        java.security.jgss/sun.security.krb5.internal \
+        java.security.jgss/sun.security.krb5:+open \
+        java.security.jgss/sun.security.krb5.internal:+open \
         java.security.jgss/sun.security.krb5.internal.ccache \
         java.security.jgss/sun.security.krb5.internal.rcache \
         java.security.jgss/sun.security.krb5.internal.crypto \
--- a/jdk/test/sun/security/krb5/ccache/TimeInCCache.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/krb5/ccache/TimeInCCache.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,7 @@
  * @test
  * @bug 6590930
  * @modules java.security.jgss/sun.security.krb5
- *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.ccache:+open
  * @run main/othervm TimeInCCache
  * @summary read/write does not match for ccache
  */
--- a/jdk/test/sun/security/krb5/config/DefUdpLimit.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/krb5/config/DefUdpLimit.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,8 +25,7 @@
  * @test
  * @bug 8009875
  * @summary Provide a default udp_preference_limit for krb5.conf
- * @modules java.security.jgss/sun.security.krb5
- * @compile -XDignore.symbol.file DefUdpLimit.java
+ * @modules java.security.jgss/sun.security.krb5:+open
  * @run main/othervm DefUdpLimit -1 1465
  * @run main/othervm DefUdpLimit 0 0
  * @run main/othervm DefUdpLimit 1234 1234
--- a/jdk/test/sun/security/krb5/config/DnsFallback.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/krb5/config/DnsFallback.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,7 +23,7 @@
 /*
  * @test
  * @bug 6673164 6552334 8077102
- * @modules java.security.jgss/sun.security.krb5
+ * @modules java.security.jgss/sun.security.krb5:+open
  * @run main/othervm DnsFallback
  * @summary fix dns_fallback parse error, and use dns by default
  */
--- a/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,7 @@
  * @test
  * @bug 7184246
  * @summary Simplify Config.get() of krb5
- * @modules java.security.jgss/sun.security.krb5
+ * @modules java.security.jgss/sun.security.krb5:+open
  */
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
--- a/jdk/test/sun/security/krb5/tools/KtabZero.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/krb5/tools/KtabZero.java	Thu Dec 01 21:39:49 2016 +0000
@@ -34,7 +34,7 @@
  * @bug 8014196
  * @summary ktab creates a file with zero kt_vno
  * @requires os.family == "windows"
- * @modules java.security.jgss/sun.security.krb5.internal.ktab
+ * @modules java.security.jgss/sun.security.krb5.internal.ktab:+open
  *          java.security.jgss/sun.security.krb5.internal.tools
  */
 public class KtabZero {
--- a/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/provider/FileInputStreamPool/FileInputStreamPoolTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -24,7 +24,8 @@
 /**
  * @test
  * @bug 8047769
- * @modules java.base/sun.security.provider
+ * @modules java.base/java.lang.ref:open
+ *          java.base/sun.security.provider:open
  * @summary SecureRandom should be more frugal with file descriptors
  */
 
--- a/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/provider/SecureRandom/CommonSeeder.java	Thu Dec 01 21:39:49 2016 +0000
@@ -33,7 +33,8 @@
 /**
  * @test
  * @bug 8051408
- * @modules java.base/sun.security.provider
+ * @modules java.base/java.lang.reflect:open
+ *          java.base/sun.security.provider:+open
  * @run main/othervm CommonSeeder
  * @summary check entropy reading of DRBGs
  */
--- a/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/provider/SecureRandom/DRBGS11n.java	Thu Dec 01 21:39:49 2016 +0000
@@ -32,7 +32,7 @@
 /**
  * @test
  * @bug 8157308
- * @modules java.base/sun.security.provider
+ * @modules java.base/sun.security.provider:+open
  * @summary Make AbstractDrbg non-Serializable
  * @run main DRBGS11n mech
  * @run main DRBGS11n capability
--- a/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,7 +26,8 @@
  * @bug 8080535
  * @summary Expected size of Character.UnicodeBlock.map is not optimal
  * @library /lib/testlibrary
- * @modules java.base/sun.security.ssl
+ * @modules java.base/java.util:open
+ *          java.base/sun.security.ssl:open
  * @build jdk.testlibrary.OptimalCapacity
  * @run main OptimalListSize
  */
--- a/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/tools/jarsigner/LargeJarEntry.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,7 +27,7 @@
  * @summary Make sure jar files with large entries (more than max heap size)
  *    can be signed
  * @modules jdk.jartool/sun.security.tools.jarsigner
- * @run main/othervm -Xmx8M LargeJarEntry
+ * @run main/othervm -Xmx16m LargeJarEntry
  * @author Sean Mullan
  */
 
--- a/jdk/test/sun/security/tools/keytool/StartDateTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/tools/keytool/StartDateTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,8 +25,7 @@
  * @test
  * @bug 6468285
  * @summary keytool ability to backdate self-signed certificates to compensate for clock skew
- * @modules java.base/sun.security.tools.keytool
- * @compile -XDignore.symbol.file StartDateTest.java
+ * @modules java.base/sun.security.tools.keytool:+open
  * @run main StartDateTest
  */
 
--- a/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/security/util/DerInputBuffer/DerInputBufferEqualsHashCode.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,7 +26,7 @@
  * @author Gary Ellison
  * @bug 4170635
  * @summary Verify equals()/hashCode() contract honored
- * @modules java.base/sun.security.util
+ * @modules java.base/sun.security.util:+open
  *          java.base/sun.security.x509
  * @run main/othervm/policy=Allow.policy DerInputBufferEqualsHashCode
  */
--- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -27,6 +27,7 @@
  *  @bug 5008856 5023573 5024917 5062569 7172176
  *  @summary 'missing resource key' error for key = "Operating system"
  *  @modules jdk.jconsole/sun.tools.jconsole
+ *           jdk.jconsole/sun.tools.jconsole.resources:open
  *  @run main ResourceCheckTest
  */
 
--- a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,7 +26,7 @@
  * @bug 8007572 8008161 8157792
  * @summary Test whether the TimeZone generated from JSR310 tzdb is the same
  * as the one from the tz data from javazic
- * @modules java.base/sun.util.calendar
+ * @modules java.base/sun.util.calendar:+open
  * @build BackEnd Checksum DayOfWeek Gen GenDoc Main Mappings Month
  *        Rule RuleDay RuleRec Simple TestZoneInfo310 Time Timezone
  *        TzIDOldMapping Zone ZoneInfoFile ZoneInfoOld ZoneRec Zoneinfo
--- a/jdk/test/tools/jar/mmrjar/ConcealedPackage.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jar/mmrjar/ConcealedPackage.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,6 +26,8 @@
  * @bug 8146486
  * @summary Fail to create a MR modular JAR with a versioned entry in
  *          base-versioned empty package
+ * @modules jdk.compiler
+ *          jdk.jartool
  * @library /lib/testlibrary
  * @build jdk.testlibrary.FileUtils
  * @run testng ConcealedPackage
@@ -56,6 +58,7 @@
     private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac")
             .orElseThrow(() -> new RuntimeException("javac tool not found"));
     private final String linesep = System.lineSeparator();
+    private final Path testsrc;
     private final Path userdir;
     private final ByteArrayOutputStream outbytes = new ByteArrayOutputStream();
     private final PrintStream out = new PrintStream(outbytes, true);
@@ -63,7 +66,7 @@
     private final PrintStream err = new PrintStream(errbytes, true);
 
     public ConcealedPackage() throws IOException {
-        Path testsrc = Paths.get(System.getProperty("test.src"));
+        testsrc = Paths.get(System.getProperty("test.src"));
         userdir = Paths.get(System.getProperty("user.dir", "."));
 
         // compile the classes directory
@@ -124,8 +127,7 @@
 
         jar("-tf mmr.jar");
 
-        String s = new String(outbytes.toByteArray());
-        Set<String> actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet());
+        Set<String> actual = lines(outbytes);
         Set<String> expected = Set.of(
                 "META-INF/",
                 "META-INF/MANIFEST.MF",
@@ -139,10 +141,8 @@
         rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class");
         Assert.assertEquals(rc, 1);
 
-        s = new String(errbytes.toByteArray());
-        Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public "
-                + "class not found in base entries")
-        );
+        String s = new String(errbytes.toByteArray());
+        Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
     }
 
     // updates a valid multi-release jar with a module-info class and new
@@ -158,15 +158,11 @@
         Assert.assertEquals(rc, 0);
 
         String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a "
-                        + "concealed package, \nplacing this jar on the class path "
-                        + "will result in incompatible public interfaces")
-        );
+        Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
 
         jar("-tf mmr.jar");
 
-        s = new String(outbytes.toByteArray());
-        Set<String> actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet());
+        Set<String> actual = lines(outbytes);
         Set<String> expected = Set.of(
                 "META-INF/",
                 "META-INF/MANIFEST.MF",
@@ -186,9 +182,7 @@
         Assert.assertEquals(rc, 1);
 
         String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(s.contains("p/internal/Bar.class, contains a new public "
-                + "class not found in base entries")
-        );
+        Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
     }
 
     // jar tool succeeds building mmr.jar because of concealed package
@@ -199,15 +193,11 @@
         Assert.assertEquals(rc, 0);
 
         String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(s.contains("p/internal/Bar.class is a public class in a "
-                + "concealed package, \nplacing this jar on the class path "
-                + "will result in incompatible public interfaces")
-        );
+        Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
 
         jar("-tf mmr.jar");
 
-        s = new String(outbytes.toByteArray());
-        Set<String> actual = Arrays.stream(s.split(linesep)).collect(Collectors.toSet());
+        Set<String> actual = lines(outbytes);
         Set<String> expected = Set.of(
                 "META-INF/",
                 "META-INF/MANIFEST.MF",
@@ -222,4 +212,128 @@
         );
         Assert.assertEquals(actual, expected);
     }
+
+    // jar tool does two updates, no exported packages, all concealed
+    @Test
+    public void test5() throws IOException {
+        // compile the mr10 directory
+        Path source = testsrc.resolve("src").resolve("mr10");
+        Path destination = Paths.get("mr10");
+        javac(source, destination);
+
+        // create a directory for this tests special files
+        Files.createDirectory(Paths.get("test5"));
+
+        // create an empty module-info.java
+        String hi = "module hi {" + linesep + "}" + linesep;
+        Path modinfo = Paths.get("test5", "module-info.java");
+        Files.write(modinfo, hi.getBytes());
+
+        // and compile it
+        javac(modinfo, Paths.get("test5"));
+
+        int rc = jar("--create --file mr.jar -C classes .");
+        Assert.assertEquals(rc, 0);
+
+        rc = jar("--update --file mr.jar -C test5 module-info.class"
+                + " --release 9 -C mr9 .");
+        Assert.assertEquals(rc, 0);
+
+        jar("tf mr.jar");
+
+        Set<String> actual = lines(outbytes);
+        Set<String> expected = Set.of(
+                "META-INF/",
+                "META-INF/MANIFEST.MF",
+                "p/",
+                "p/Hi.class",
+                "META-INF/versions/9/p/",
+                "META-INF/versions/9/p/Hi.class",
+                "META-INF/versions/9/p/internal/",
+                "META-INF/versions/9/p/internal/Bar.class",
+                "module-info.class"
+        );
+        Assert.assertEquals(actual, expected);
+
+        jar("-d --file mr.jar");
+
+        actual = lines(outbytes);
+        expected = Set.of(
+                "hi",
+                "requires mandated java.base",
+                "contains p",
+                "contains p.internal"
+        );
+        Assert.assertEquals(actual, expected);
+
+        rc = jar("--update --file mr.jar --release 10 -C mr10 .");
+        Assert.assertEquals(rc, 0);
+
+        jar("tf mr.jar");
+
+        actual = lines(outbytes);
+        expected = Set.of(
+                "META-INF/",
+                "META-INF/MANIFEST.MF",
+                "p/",
+                "p/Hi.class",
+                "META-INF/versions/9/p/",
+                "META-INF/versions/9/p/Hi.class",
+                "META-INF/versions/9/p/internal/",
+                "META-INF/versions/9/p/internal/Bar.class",
+                "META-INF/versions/10/p/",
+                "META-INF/versions/10/p/internal/",
+                "META-INF/versions/10/p/internal/bar/",
+                "META-INF/versions/10/p/internal/bar/Gee.class",
+                "module-info.class"
+        );
+        Assert.assertEquals(actual, expected);
+
+        jar("-d --file mr.jar");
+
+        actual = lines(outbytes);
+        expected = Set.of(
+                "hi",
+                "requires mandated java.base",
+                "contains p",
+                "contains p.internal",
+                "contains p.internal.bar"
+        );
+        Assert.assertEquals(actual, expected);
+    }
+
+    private static Set<String> lines(ByteArrayOutputStream baos) {
+        String s = new String(baos.toByteArray());
+        return Arrays.stream(s.split("\\R"))
+                     .map(l -> l.trim())
+                     .filter(l -> l.length() > 0)
+                     .collect(Collectors.toSet());
+    }
+
+    static enum Message {
+        NOT_FOUND_IN_BASE_ENTRY(
+          ", contains a new public class not found in base entries"
+        ),
+        NEW_CONCEALED_PACKAGE_WARNING(
+            " is a public class" +
+            " in a concealed package, placing this jar on the class path will result" +
+            " in incompatible public interfaces"
+        );
+
+        final String msg;
+        Message(String msg) {
+            this.msg = msg;
+        }
+
+        /*
+         * Test if the given output contains this message ignoring the line break.
+         */
+        boolean match(String output, String entry) {
+            System.out.println("Expected: " + entry + msg);
+            System.out.println("Found: " + output);
+            return Arrays.stream(output.split("\\R"))
+                         .collect(Collectors.joining(" "))
+                         .contains(entry + msg);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/mmrjar/src/mr10/p/internal/bar/Gee.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,7 @@
+package p.internal.bar;
+
+public class Gee {
+    public void geeWhiz() {
+        System.out.println("Gee whiz");
+    }
+}
--- a/jdk/test/tools/jar/modularJar/Basic.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jar/modularJar/Basic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,19 +22,18 @@
  */
 
 import java.io.*;
+import java.lang.module.ModuleDescriptor;
 import java.lang.reflect.Method;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
+import java.nio.file.*;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.*;
 import java.util.function.Consumer;
 import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
 import java.util.jar.JarInputStream;
 import java.util.jar.Manifest;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import jdk.testlibrary.FileUtils;
@@ -76,7 +75,8 @@
                                                    Set.of("jdk.test.foo"),
                                                    null, // no uses
                                                    null, // no provides
-                                                   Set.of("jdk.test.foo.internal"));
+                                                   Set.of("jdk.test.foo.internal",
+                                                          "jdk.test.foo.resources"));
     static TestModuleData BAR = new TestModuleData("bar",
                                                    "4.5.6.7",
                                                    "jdk.test.bar.Bar",
@@ -99,17 +99,18 @@
         final String version;
         final String message;
         final String hashes;
-        final Set<String> conceals;
+        final Set<String> packages;
 
         TestModuleData(String mn, String v, String mc, String m, String h,
                        Set<String> requires, Set<String> exports, Set<String> uses,
-                       Set<String> provides, Set<String> conceals) {
+                       Set<String> provides, Set<String> contains) {
             moduleName = mn; mainClass = mc; version = v; message = m; hashes = h;
-            this.requires = requires;
-            this.exports = exports;
-            this.uses = uses;
-            this.provides = provides;
-            this.conceals = conceals;
+            this.requires = requires != null ? requires : Collections.emptySet();
+            this.exports = exports != null ? exports : Collections.emptySet();
+            this.uses = uses != null ? uses : Collections.emptySet();;
+            this.provides = provides != null ? provides : Collections.emptySet();
+            this.packages = Stream.concat(this.exports.stream(), contains.stream())
+                                  .collect(Collectors.toSet());
         }
         static TestModuleData from(String s) {
             try {
@@ -148,8 +149,8 @@
                         provides = stringToSet(line);
                     } else if (line.startsWith("hashes:")) {
                         hashes = line.substring("hashes:".length());
-                    } else if (line.startsWith("conceals:")) {
-                        line = line.substring("conceals:".length());
+                    } else if (line.startsWith("contains:")) {
+                        line = line.substring("contains:".length());
                         conceals = stringToSet(line);
                     } else {
                         throw new AssertionError("Unknown value " + line);
@@ -192,16 +193,14 @@
         assertSetsEqual(expected.exports, received.exports);
         assertSetsEqual(expected.uses, received.uses);
         assertSetsEqual(expected.provides, received.provides);
-        assertSetsEqual(expected.conceals, received.conceals);
+        assertSetsEqual(expected.packages, received.packages);
     }
 
     static void assertSetsEqual(Set<String> s1, Set<String> s2) {
-        if (s1 == null && s2 == null) // none expected, or received
-            return;
-        assertTrue(s1.size() == s2.size(),
-                   "Unexpected set size difference: ", s1.size(), ", ", s2.size());
-        s1.forEach(p -> assertTrue(s2.contains(p), "Expected ", p, ", in ", s2));
-    }
+        if (!s1.equals(s2)) {
+            org.testng.Assert.assertTrue(false, s1 + " vs " + s2);
+        }
+     }
 
     @BeforeTest
     public void compileModules() throws Exception {
@@ -209,6 +208,11 @@
         compileModule(BAR.moduleName, MODULE_CLASSES);
         compileModule("baz");  // for service provider consistency checking
 
+        // copy resources
+        copyResource(TEST_SRC.resolve("src").resolve(FOO.moduleName),
+                     MODULE_CLASSES.resolve(FOO.moduleName),
+                     "jdk/test/foo/resources/foo.properties");
+
         setupMRJARModuleInfo(FOO.moduleName);
         setupMRJARModuleInfo(BAR.moduleName);
         setupMRJARModuleInfo("baz");
@@ -228,6 +232,12 @@
             "--no-manifest",
             "-C", modClasses.toString(), ".")
             .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo",
+                               "jdk.test.foo.resources",
+                               "jdk.test.foo.internal"));
+
         java(mp, FOO.moduleName + "/" + FOO.mainClass)
             .assertSuccess()
             .resultChecker(r -> assertModuleData(r, FOO));
@@ -375,7 +385,8 @@
             "--file=" + modularJar.toString(),
             "--no-manifest",
             "-C", modClasses.toString(), "module-info.class",
-            "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
+            "-C", modClasses.toString(), "jdk/test/foo/Foo.class",
+            "-C", modClasses.toString(), "jdk/test/foo/resources/foo.properties")
             .assertSuccess();
         jar("--update",
             "--file=" + modularJar.toString(),
@@ -471,13 +482,63 @@
                            "Expecting to find \"bar, requires foo,...\"",
                            "in output, but did not: [" + r.output + "]");
                 p = Pattern.compile(
-                        "conceals\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal");
+                        "contains\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal");
                 assertTrue(p.matcher(r.output).find(),
-                           "Expecting to find \"conceals jdk.test.foo,...\"",
+                           "Expecting to find \"contains jdk.test.foo,...\"",
                            "in output, but did not: [" + r.output + "]");
             });
     }
 
+
+    @Test
+    public void partialUpdateFooPackagesAttribute() throws IOException {
+        Path mp = Paths.get("partialUpdateFooPackagesAttribute");
+        createTestDir(mp);
+        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+
+        // Not all files, and none from non-exported packages,
+        // i.e. no concealed list in first create
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--no-manifest",
+            "-C", modClasses.toString(), "module-info.class",
+            "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
+            .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo"));
+
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "jdk/test/foo/resources/foo.properties")
+            .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo", "jdk.test.foo.resources"));
+
+        jar("--update",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), "jdk/test/foo/internal/Message.class")
+            .assertSuccess();
+
+        assertSetsEqual(readPackagesAttribute(modularJar),
+                        Set.of("jdk.test.foo",
+                               "jdk.test.foo.resources",
+                               "jdk.test.foo.internal"));
+
+        java(mp, FOO.moduleName + "/" + FOO.mainClass)
+            .assertSuccess()
+            .resultChecker(r -> assertModuleData(r, FOO));
+    }
+
+    private Set<String> readPackagesAttribute(Path jar) {
+        return getModuleDescriptor(jar).packages();
+    }
+
     @Test
     public void hashBarInFooModule() throws IOException {
         Path mp = Paths.get("dependencesFooBar");
@@ -506,6 +567,7 @@
             .assertSuccess();
 
         java(mp, BAR.moduleName + "/" + BAR.mainClass,
+             "--add-exports", "java.base/jdk.internal.misc=bar",
              "--add-exports", "java.base/jdk.internal.module=bar")
             .assertSuccess()
             .resultChecker(r -> {
@@ -550,6 +612,7 @@
             "-C", barClasses.toString(), ".").assertSuccess();
 
         java(mp, BAR.moduleName + "/" + BAR.mainClass,
+             "--add-exports", "java.base/jdk.internal.misc=bar",
              "--add-exports", "java.base/jdk.internal.module=bar")
             .assertFailure()
             .resultChecker(r -> {
@@ -750,12 +813,22 @@
     static Path compileModule(String mn, Path mp)
         throws IOException
     {
-        Path fooSourcePath = TEST_SRC.resolve("src").resolve(mn);
+        Path sourcePath = TEST_SRC.resolve("src").resolve(mn);
         Path build = Files.createDirectories(MODULE_CLASSES.resolve(mn));
-        javac(build, mp, fileList(fooSourcePath));
+        javac(build, mp, sourceList(sourcePath));
         return build;
     }
 
+    static void copyResource(Path srcDir, Path dir, String resource)
+        throws IOException
+    {
+        Path dest = dir.resolve(resource);
+        Files.deleteIfExists(dest);
+
+        Files.createDirectories(dest.getParent());
+        Files.copy(srcDir.resolve(resource), dest);
+    }
+
     static void setupMRJARModuleInfo(String moduleName) throws IOException {
         Path modClasses = MODULE_CLASSES.resolve(moduleName);
         Path metaInfDir = MRJAR_DIR.resolve(moduleName).resolve("META-INF");
@@ -774,6 +847,18 @@
         }
     }
 
+    static ModuleDescriptor getModuleDescriptor(Path jar) {
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        try (JarFile jf = new JarFile(jar.toFile())) {
+            JarEntry entry = jf.getJarEntry("module-info.class");
+            try (InputStream in = jf.getInputStream(entry)) {
+                return ModuleDescriptor.read(in);
+            }
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
     // Re-enable when there is support in javax.tools for module path
 //    static void javac(Path dest, Path... sourceFiles) throws IOException {
 //        out.printf("Compiling %d source files %s%n", sourceFiles.length,
@@ -817,6 +902,8 @@
         commands.add(dest.toString());
         if (dest.toString().contains("bar")) {
             commands.add("--add-exports");
+            commands.add("java.base/jdk.internal.misc=bar");
+            commands.add("--add-exports");
             commands.add("java.base/jdk.internal.module=bar");
         }
         if (modulePath != null) {
@@ -848,17 +935,10 @@
         return run(new ProcessBuilder(commands));
     }
 
-    static Path[] fileList(Path directory) throws IOException {
-        final List<Path> filePaths = new ArrayList<>();
-        Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
-            @Override
-            public FileVisitResult visitFile(Path file,
-                                             BasicFileAttributes attrs) {
-                filePaths.add(file);
-                return FileVisitResult.CONTINUE;
-            }
-        });
-        return filePaths.toArray(new Path[filePaths.size()]);
+    static Path[] sourceList(Path directory) throws IOException {
+        return Files.find(directory, Integer.MAX_VALUE,
+                          (file, attrs) -> (file.toString().endsWith(".java")))
+                    .toArray(Path[]::new);
     }
 
     static void createTestDir(Path p) throws IOException{
--- a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,10 +26,14 @@
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Requires;
-import java.lang.reflect.Method;
+import java.lang.module.ModuleDescriptor.Provides;
 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.test.bar.internal.Message;
 
@@ -56,19 +60,20 @@
             System.out.println("uses:" + sj.toString());
 
         sj = new StringJoiner(",");
-        md.provides().keySet().stream().sorted().forEach(sj::add);
+        md.provides().stream().map(Provides::service).sorted().forEach(sj::add);
         if (!sj.toString().equals(""))
             System.out.println("provides:" + sj.toString());
 
         sj = new StringJoiner(",");
-        md.conceals().forEach(sj::add);
+        Set<String> concealed = new HashSet<>(md.packages());
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        concealed.forEach(sj::add);
         if (!sj.toString().equals(""))
-            System.out.println("conceals:" + sj.toString());
+            System.out.println("contains:" + sj.toString());
 
-        Method m = ModuleDescriptor.class.getDeclaredMethod("hashes");
-        m.setAccessible(true);
         ModuleDescriptor foo = jdk.test.foo.Foo.class.getModule().getDescriptor();
-        Optional<ModuleHashes> oHashes = (Optional<ModuleHashes>) m.invoke(foo);
+        JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess();
+        Optional<ModuleHashes> oHashes = jlma.hashes(foo);
         System.out.println("hashes:" + oHashes.get().hashFor("bar"));
     }
 }
--- a/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java	Thu Dec 01 21:39:49 2016 +0000
@@ -26,7 +26,10 @@
 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.util.StringJoiner;
+import java.util.HashSet;
+import java.util.Set;
 
 import jdk.test.foo.internal.Message;
 
@@ -53,13 +56,15 @@
             System.out.println("uses:" + sj.toString());
 
         sj = new StringJoiner(",");
-        md.provides().keySet().stream().sorted().forEach(sj::add);
+        md.provides().stream().map(Provides::service).sorted().forEach(sj::add);
         if (!sj.toString().equals(""))
             System.out.println("provides:" + sj.toString());
 
         sj = new StringJoiner(",");
-        md.conceals().forEach(sj::add);
+        Set<String> concealed = new HashSet<>(md.packages());
+        md.exports().stream().map(Exports::source).forEach(concealed::remove);
+        concealed.forEach(sj::add);
         if (!sj.toString().equals(""))
-            System.out.println("conceals:" + sj.toString());
+            System.out.println("contains:" + sj.toString());
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/resources/foo.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,1 @@
+name = foo
--- a/jdk/test/tools/jar/multiRelease/Basic.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jar/multiRelease/Basic.java	Thu Dec 01 21:39:49 2016 +0000
@@ -25,7 +25,9 @@
  * @test
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
- * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Platform
+ *          jdk.compiler
+ *          jdk.jartool
+ * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils
  * @run testng Basic
  */
 
@@ -39,12 +41,14 @@
 import java.util.*;
 import java.util.function.Consumer;
 import java.util.jar.*;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.zip.*;
 
 import jdk.test.lib.JDKToolFinder;
 import jdk.test.lib.Utils;
 
+
 import static java.lang.String.format;
 import static java.lang.System.out;
 
@@ -292,7 +296,7 @@
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
                 .assertSuccess()
                 .resultChecker(r ->
-                        assertTrue(r.output.contains("contains a class that is identical"), r.output)
+                        assertTrue(r.outputContains("contains a class that is identical"), r.output)
                 );
 
         delete(jarfile);
@@ -450,7 +454,7 @@
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
                 .assertFailure()
                 .resultChecker(r ->
-                        assertTrue(r.output.contains("an isolated nested class"), r.output)
+                        assertTrue(r.outputContains("an isolated nested class"), r.output)
                 );
 
         delete(jarfile);
@@ -605,6 +609,13 @@
             this.ec = ec;
             this.output = output;
         }
+
+        boolean outputContains(String msg) {
+            return Arrays.stream(output.split("\\R"))
+                         .collect(Collectors.joining(" "))
+                         .contains(msg);
+        }
+
         Result assertSuccess() {
             assertTrue(ec == 0, format("ec: %d, output: %s", ec, output));
             return this;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/multiRelease/Basic1.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,245 @@
+/*
+ * 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
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          jdk.compiler
+ *          jdk.jartool
+ * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils
+ * @run testng Basic1
+ */
+
+import static org.testng.Assert.*;
+
+import org.testng.annotations.*;
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.jar.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.*;
+
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.Utils;
+
+
+import static java.lang.String.format;
+import static java.lang.System.out;
+
+public class Basic1 {
+    private final String src = System.getProperty("test.src", ".");
+
+    @BeforeTest
+    public void setup() throws IOException {
+        String test = "test01";
+        Path classes = Paths.get("classes", "base");
+        Files.createDirectories(classes);
+        Path source = Paths.get(src, "data", test, "base", "version");
+        javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
+
+        Path v9 = Paths.get("v9").resolve("META-INF").resolve("versions").resolve("9");
+        Files.createDirectories(v9);
+        source = Paths.get(src, "data", test, "v9", "version");
+        javac(v9, source.resolve("Version.java"));
+
+        Path v10 = Paths.get("v10").resolve("META-INF").resolve("versions").resolve("10");
+        Files.createDirectories(v10);
+        source = Paths.get(src, "data", test, "v10", "version");
+        javac(v10, source.resolve("Version.java"));
+    }
+
+    @Test
+    public void test() throws IOException {
+        String jarfile = "test.jar";
+        Path classes = Paths.get("classes");
+        Path v9 = Paths.get("v9");
+        Path v10 = Paths.get("v10");
+
+        jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+            "--release", "9", "-C", v9.toString(), ".",
+            "--release", "10", "-C", v10.toString(), ".")
+            .assertSuccess();
+
+        checkMultiRelease(jarfile, true);
+
+        Map<String,String[]> names = Map.of(
+            "version/Main.class",
+            new String[] {"classes", "base", "version", "Main.class"},
+
+            "version/Version.class",
+            new String[] {"classes", "base", "version", "Version.class"},
+
+            "META-INF/versions/9/version/Version.class",
+            new String[] {"v9", "META-INF", "versions", "9", "version", "Version.class"},
+
+            "META-INF/versions/10/version/Version.class",
+            new String[] {"v10", "META-INF", "versions", "10", "version", "Version.class"}
+        );
+
+        compare(jarfile, names);
+    }
+
+    @Test
+    public void testFail() throws IOException {
+        String jarfile = "test.jar";
+        Path classes = Paths.get("classes");
+        Path v9 = Paths.get("v9");
+        Path v10 = Paths.get("v10");
+
+        jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+            "--release", "9", "-C", v10.toString(), ".")
+            .assertFailure()
+            .outputContains("unexpected versioned entry META-INF/versions/");
+    }
+
+    private void checkMultiRelease(String jarFile, boolean expected) throws IOException {
+        try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ,
+                JarFile.runtimeVersion())) {
+            assertEquals(jf.isMultiRelease(), expected);
+        }
+    }
+
+    // compares the bytes found in the jar entries with the bytes found in the
+    // corresponding data files used to create the entries
+    private void compare(String jarfile, Map<String,String[]> names) throws IOException {
+        try (JarFile jf = new JarFile(jarfile)) {
+            for (String name : names.keySet()) {
+                Path path = Paths.get("", names.get(name));
+                byte[] b1 = Files.readAllBytes(path);
+                byte[] b2;
+                JarEntry je = jf.getJarEntry(name);
+                try (InputStream is = jf.getInputStream(je)) {
+                    b2 = is.readAllBytes();
+                }
+                assertEquals(b1,b2);
+            }
+        }
+    }
+
+    /*
+     * The following methods were taken from modular jar and other jar tests
+     */
+
+    void javac(Path dest, Path... sourceFiles) throws IOException {
+        String javac = JDKToolFinder.getJDKTool("javac");
+
+        List<String> commands = new ArrayList<>();
+        commands.add(javac);
+        String opts = System.getProperty("test.compiler.opts");
+        if (!opts.isEmpty()) {
+            commands.addAll(Arrays.asList(opts.split(" +")));
+        }
+        commands.add("-d");
+        commands.add(dest.toString());
+        Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x));
+
+        quickFail(run(new ProcessBuilder(commands)));
+    }
+
+    Result jarWithStdin(File stdinSource, String... args) {
+        String jar = JDKToolFinder.getJDKTool("jar");
+        List<String> commands = new ArrayList<>();
+        commands.add(jar);
+        commands.addAll(Utils.getForwardVmOptions());
+        Stream.of(args).forEach(x -> commands.add(x));
+        ProcessBuilder p = new ProcessBuilder(commands);
+        if (stdinSource != null)
+            p.redirectInput(stdinSource);
+        return run(p);
+    }
+
+    Result jar(String... args) {
+        return jarWithStdin(null, args);
+    }
+
+    void quickFail(Result r) {
+        if (r.ec != 0)
+            throw new RuntimeException(r.output);
+    }
+
+    Result run(ProcessBuilder pb) {
+        Process p;
+        out.printf("Running: %s%n", pb.command());
+        try {
+            p = pb.start();
+        } catch (IOException e) {
+            throw new RuntimeException(
+                    format("Couldn't start process '%s'", pb.command()), e);
+        }
+
+        String output;
+        try {
+            output = toString(p.getInputStream(), p.getErrorStream());
+        } catch (IOException e) {
+            throw new RuntimeException(
+                    format("Couldn't read process output '%s'", pb.command()), e);
+        }
+
+        try {
+            p.waitFor();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(
+                    format("Process hasn't finished '%s'", pb.command()), e);
+        }
+        return new Result(p.exitValue(), output);
+    }
+
+    String toString(InputStream in1, InputStream in2) throws IOException {
+        try (ByteArrayOutputStream dst = new ByteArrayOutputStream();
+             InputStream concatenated = new SequenceInputStream(in1, in2)) {
+            concatenated.transferTo(dst);
+            return new String(dst.toByteArray(), "UTF-8");
+        }
+    }
+
+    static class Result {
+        final int ec;
+        final String output;
+
+        private Result(int ec, String output) {
+            this.ec = ec;
+            this.output = output;
+        }
+
+        boolean outputContains(String msg) {
+            return Arrays.stream(output.split("\\R"))
+                         .collect(Collectors.joining(" "))
+                         .contains(msg);
+        }
+
+        Result assertSuccess() {
+            assertTrue(ec == 0, format("ec: %d, output: %s", ec, output));
+            return this;
+        }
+        Result assertFailure() {
+            assertTrue(ec != 0, format("ec: %d, output: %s", ec, output));
+            return this;
+        }
+        Result resultChecker(Consumer<Result> r) { r.accept(this); return this; }
+    }
+}
--- a/jdk/test/tools/jlink/IntegrationTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jlink/IntegrationTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -59,7 +59,6 @@
  * @library ../lib
  * @modules java.base/jdk.internal.jimage
  *          jdk.jdeps/com.sun.tools.classfile
- *          jdk.jlink/jdk.tools.jlink
  *          jdk.jlink/jdk.tools.jlink.builder
  *          jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
--- a/jdk/test/tools/jlink/JLinkNegativeTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jlink/JLinkNegativeTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -274,7 +274,7 @@
                 helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName2, classNames);
 
         try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) {
-            ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1)
+            ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1)
                     .requires("java.base").build(), out);
         }
 
@@ -332,7 +332,7 @@
                 helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName2, classNames);
 
         try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) {
-            ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1)
+            ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1)
                     .requires("java.base").build(), out);
         }
 
--- a/jdk/test/tools/jlink/JLinkTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jlink/JLinkTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -62,9 +62,11 @@
     // number of built-in plugins from jdk.jlink module
     private static int getNumJlinkPlugins() {
         ModuleDescriptor desc = Plugin.class.getModule().getDescriptor();
-        return desc.provides().
-                    get(Plugin.class.getName()).
-                    providers().size();
+        return desc.provides().stream()
+                .filter(p -> p.service().equals(Plugin.class.getName()))
+                .map(p -> p.providers().size())
+                .findAny()
+                .orElse(0);
     }
 
     private static boolean isOfJLinkModule(Plugin p) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/basic/AllModulePath.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,178 @@
+/**
+ * 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
+ * @summary jlink test of --add-module ALL-MODULE-PATH
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build jdk.testlibrary.ProcessTools
+ *        jdk.testlibrary.OutputAnalyzer
+ *        CompilerUtils
+ * @run testng AllModulePath
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.spi.ToolProvider;
+
+import jdk.testlibrary.ProcessTools;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class AllModulePath {
+
+    private final Path JMODS = Paths.get(System.getProperty("test.jdk")).resolve("jmods");
+    private final Path SRC = Paths.get(System.getProperty("test.src")).resolve("src");
+    private final Path MODS = Paths.get("mods");
+
+    private final static Set<String> MODULES = Set.of("test", "m1");
+
+    static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
+        .orElseThrow(() ->
+            new RuntimeException("jlink tool not found")
+        );
+
+    @BeforeClass
+    public void setup() throws Throwable {
+        if (Files.notExists(JMODS)) {
+            return;
+        }
+
+        Files.createDirectories(MODS);
+
+        for (String mn : MODULES) {
+            Path mod = MODS.resolve(mn);
+            if (!CompilerUtils.compile(SRC.resolve(mn), mod)) {
+                throw new AssertionError("Compilation failure. See log.");
+            }
+        }
+    }
+
+    @Test
+    public void testAllModulePath() throws Throwable {
+        if (Files.notExists(JMODS)) {
+            return;
+        }
+
+        // create custom image
+        Path image = Paths.get("image");
+        createImage(image, "--add-modules", "ALL-MODULE-PATH");
+
+        Set<String> modules = new HashSet<>();
+        Files.find(JMODS, 1, (Path p, BasicFileAttributes attr) ->
+                                p.toString().endsWith(".jmod"))
+             .map(p -> JMODS.relativize(p).toString())
+             .map(n -> n.substring(0, n.length()-5))
+             .forEach(modules::add);
+        modules.add("m1");
+        modules.add("test");
+        checkModules(image, modules);
+    }
+
+    @Test
+    public void testLimitModules() throws Throwable {
+        if (Files.notExists(JMODS)) {
+            return;
+        }
+
+        // create custom image
+        Path image = Paths.get("image1");
+        createImage(image,
+                    "--add-modules", "ALL-MODULE-PATH",
+                    "--limit-modules", "m1");
+
+        checkModules(image, Set.of("m1", "java.base"));
+    }
+
+    @Test
+    public void testAddModules() throws Throwable {
+        if (Files.notExists(JMODS)) {
+            return;
+        }
+
+        // create custom image
+        Path image = Paths.get("image2");
+        createImage(image,
+                    "--add-modules", "m1,test",
+                    "--add-modules", "ALL-MODULE-PATH",
+                    "--limit-modules", "java.base");
+
+        checkModules(image, Set.of("m1", "test", "java.base"));
+    }
+
+    /*
+     * check the modules linked in the image
+     */
+    private void checkModules(Path image, Set<String> modules) throws Throwable {
+        Path cmd = findTool(image, "java");
+
+        List<String> options = new ArrayList<>();
+        options.add(cmd.toString());
+        options.add("-m");
+        options.add("m1/p.ListModules");
+        options.addAll(modules);
+
+        ProcessBuilder pb = new ProcessBuilder(options);
+        ProcessTools.executeCommand(pb)
+                    .shouldHaveExitValue(0);
+    }
+
+    private Path findTool(Path image, String tool)  {
+        String suffix = System.getProperty("os.name").startsWith("Windows")
+                            ? ".exe" : "";
+
+        Path cmd = image.resolve("bin").resolve(tool + suffix);
+        if (Files.notExists(cmd)) {
+            throw new RuntimeException(cmd + " not found");
+        }
+        return cmd;
+    }
+
+    private void createImage(Path image, String... options) throws IOException {
+        String modulepath = JMODS.toString() + File.pathSeparator + MODS.toString();
+        List<String> opts = List.of("--module-path", modulepath,
+                                    "--output", image.toString());
+        String[] args = Stream.concat(opts.stream(), Arrays.stream(options))
+                              .toArray(String[]::new);
+
+        System.out.println("jlink " + Arrays.stream(args).collect(Collectors.joining(" ")));
+        PrintWriter pw = new PrintWriter(System.out);
+        int rc = JLINK_TOOL.run(pw, pw, args);
+        assertTrue(rc == 0);
+    }
+}
--- a/jdk/test/tools/jlink/basic/BasicTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jlink/basic/BasicTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -59,10 +59,11 @@
             new RuntimeException("jlink tool not found")
         );
 
+    private final String TEST_MODULE = "test";
     private final Path jdkHome = Paths.get(System.getProperty("test.jdk"));
     private final Path jdkMods = jdkHome.resolve("jmods");
     private final Path testSrc = Paths.get(System.getProperty("test.src"));
-    private final Path src = testSrc.resolve("src");
+    private final Path src = testSrc.resolve("src").resolve(TEST_MODULE);
     private final Path classes = Paths.get("classes");
     private final Path jmods = Paths.get("jmods");
     private final Path jars = Paths.get("jars");
@@ -80,23 +81,22 @@
             throw new AssertionError("Compilation failure. See log.");
         }
 
-        String modName = "test";
         Files.createDirectories(jmods);
         Files.createDirectories(jars);
         Path jarfile = jars.resolve("test.jar");
         JarUtils.createJarFile(jarfile, classes);
 
         Path image = Paths.get("mysmallimage");
-        runJmod(jarfile.toString(), modName);
-        runJlink(image, modName, "--compress", "2");
-        execute(image, modName);
+        runJmod(jarfile.toString(), TEST_MODULE);
+        runJlink(image, TEST_MODULE, "--compress", "2");
+        execute(image, TEST_MODULE);
 
-        Files.delete(jmods.resolve(modName + ".jmod"));
+        Files.delete(jmods.resolve(TEST_MODULE + ".jmod"));
 
         image = Paths.get("myimage");
-        runJmod(classes.toString(), modName);
-        runJlink(image, modName);
-        execute(image, modName);
+        runJmod(classes.toString(), TEST_MODULE);
+        runJlink(image, TEST_MODULE);
+        execute(image, TEST_MODULE);
     }
 
     private void execute(Path image, String moduleName) throws Throwable {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/basic/src/m1/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,25 @@
+/*
+ * 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 m1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/basic/src/m1/p/ListModules.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,48 @@
+/**
+ * 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 p;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class ListModules {
+    public static void main(String... args) {
+        Set<String> modules = ModuleFinder.ofSystem().findAll()
+            .stream()
+            .map(ModuleReference::descriptor)
+            .map(ModuleDescriptor::name)
+            .collect(Collectors.toSet());
+
+        Set<String> expected = Arrays.stream(args).collect(Collectors.toSet());
+
+        if (!modules.equals(expected)) {
+            throw new RuntimeException(modules + " != " + expected);
+        }
+
+    }
+}
--- a/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -75,11 +75,11 @@
 
         String target = "target" + File.separator + name;
         Files.write(txt.toPath(), content.getBytes());
-        File lic = new File(System.getProperty("java.home"), "LICENSE");
+        File lic = new File(System.getProperty("java.home"), "LICENSE.txt");
         StringBuilder builder = new StringBuilder();
         int expected = lic.exists() ? 4 : 3;
         if (lic.exists()) {
-            builder.append("LICENSE,");
+            builder.append("LICENSE.txt,");
         }
         builder.append(txt.getAbsolutePath()+",");
         builder.append(txt.getAbsolutePath() + "=" + target+",");
@@ -116,9 +116,9 @@
         imgbuilder.storeFiles(pool);
 
         if (lic.exists()) {
-            File license = new File(root.toFile(), "LICENSE");
+            File license = new File(root.toFile(), "LICENSE.txt");
             if (!license.exists() || license.length() == 0) {
-                throw new AssertionError("Invalide license file "
+                throw new AssertionError("Invalid license file "
                         + license.getAbsoluteFile());
             }
         }
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,11 +22,10 @@
  */
 
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Requires.Modifier;
+import java.lang.module.ModuleDescriptor.*;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReference;
-import java.util.Collections;
-import java.util.EnumSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -58,14 +57,32 @@
     }
 
     private void testModuleDescriptor(ModuleDescriptor md) {
-        assertUnmodifiable(md.conceals(), "conceal");
         assertUnmodifiable(md.packages(), "package");
         assertUnmodifiable(md.requires(),
-                           jlma.newRequires(EnumSet.allOf(Modifier.class), "require"));
-        assertUnmodifiable(md.exports(), jlma.newExports("export"));
+                           jlma.newRequires(Set.of(Requires.Modifier.TRANSITIVE), "require"));
+        for (Requires req : md.requires()) {
+            assertUnmodifiable(req.modifiers(), Requires.Modifier.TRANSITIVE);
+        }
+
+        assertUnmodifiable(md.exports(), jlma.newExports(Set.of(), "export", Set.of()));
+        for (Exports exp : md.exports()) {
+            assertUnmodifiable(exp.modifiers(), Exports.Modifier.SYNTHETIC);
+            assertUnmodifiable(exp.targets(), "target");
+        }
+
+        assertUnmodifiable(md.opens(), jlma.newOpens(Set.of(), "open", Set.of()));
+        for (Opens opens : md.opens()) {
+            assertUnmodifiable(opens.modifiers(), Opens.Modifier.SYNTHETIC);
+            assertUnmodifiable(opens.targets(), "target");
+        }
+
         assertUnmodifiable(md.uses(), "use");
-        assertUnmodifiable(md.provides(), "provide",
-                           jlma.newProvides("provide", Collections.singleton("provide")));
+
+        assertUnmodifiable(md.provides(),
+                           jlma.newProvides("provide", List.of("provide")));
+        for (Provides provides : md.provides()) {
+            assertUnmodifiable(provides.providers(), "provide");
+        }
 
     }
 
@@ -80,6 +97,17 @@
         }
     }
 
+    private <T> void assertUnmodifiable(List<T> list, T dummy) {
+        try {
+            list.add(dummy);
+            fail("Should throw UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+            // pass
+        } catch (Exception e) {
+            fail("Should throw UnsupportedOperationException");
+        }
+    }
+
     private <T, V> void assertUnmodifiable(Map<T, V> set, T dummyKey, V dummyValue) {
         try {
             set.put(dummyKey, dummyValue);
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -52,9 +52,11 @@
     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 = "m1/p1.Main";
 
     // the names of the modules in this test
-    private static String[] modules = new String[] {"m1", "m2", "m3"};
+    private static String[] modules = new String[] {"m1", "m2", "m3", "m4"};
+
 
     private static boolean hasJmods() {
         if (!Files.exists(JMODS)) {
@@ -80,7 +82,7 @@
             FileUtils.deleteFileTreeUnchecked(IMAGE);
         }
 
-        createImage(IMAGE, "java.base", "m1");
+        createImage(IMAGE, "java.base", "m1", "m3");
     }
 
     private void createImage(Path outputDir, String... modules) throws Throwable {
@@ -96,20 +98,34 @@
 
     /*
      * Test the image created when linking with a module with
-     * no ConcealedPackages attribute
+     * no Packages attribute
      */
     @Test
-    public void test() throws Throwable {
+    public void testPackagesAttribute() throws Throwable {
         if (!hasJmods()) return;
 
         Path java = IMAGE.resolve("bin").resolve("java");
-        assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main")
+        assertTrue(executeProcess(java.toString(), "-m", MAIN_MID)
                         .outputTo(System.out)
                         .errorTo(System.out)
                         .getExitValue() == 0);
     }
 
     /*
+     * Test the image created when linking with an open module
+    */
+    @Test
+    public void testOpenModule() throws Throwable {
+        if (!hasJmods()) return;
+
+        Path java = IMAGE.resolve("bin").resolve("java");
+        assertTrue(executeProcess(java.toString(), "-m", "m3/p3.Main")
+            .outputTo(System.out)
+            .errorTo(System.out)
+            .getExitValue() == 0);
+    }
+
+    /*
      * Disable the fast loading of system modules.
      * Parsing module-info.class
      */
@@ -120,7 +136,7 @@
         Path java = IMAGE.resolve("bin").resolve("java");
         assertTrue(executeProcess(java.toString(),
                                   "-Djdk.system.module.finder.disabledFastPath",
-                                  "-m", "m1/p1.Main")
+                                  "-m", MAIN_MID)
                         .outputTo(System.out)
                         .errorTo(System.out)
                         .getExitValue() == 0);
@@ -135,9 +151,9 @@
         if (!hasJmods()) return;
 
         Path dir = Paths.get("newImage");
-        createImage(dir, "java.base", "m1", "m2", "m3");
+        createImage(dir, "java.base", "m1", "m2", "m3", "m4");
         Path java = dir.resolve("bin").resolve("java");
-        assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main")
+        assertTrue(executeProcess(java.toString(), "-m", MAIN_MID)
                         .outputTo(System.out)
                         .errorTo(System.out)
                         .getExitValue() == 0);
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m1/p1/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -48,7 +48,6 @@
     }
 
     static void validate(ModuleDescriptor md) {
-        checkPackages(md.conceals(), "p1", "p2");
         checkPackages(md.packages(), "p1", "p2");
     }
 
--- a/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,4 +22,5 @@
  */
 
 module m3 {
+    requires m4;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m3/p3/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,74 @@
+/*
+ * 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 p3;
+
+import p4.Foo;
+import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Module;
+
+import static java.lang.module.ModuleDescriptor.Exports.Modifier.*;
+
+/**
+ * Test if m4 is an open module and p4 is package that m3 can access
+ */
+public class Main {
+    public static void main(String... args) throws Exception {
+        Module m4 = Foo.class.getModule();
+        if (!m4.isOpen("p4")) {
+            throw new RuntimeException("m3 can't access p4");
+        }
+
+        // Test if it can access a private field
+        Foo foo = Foo.create("foo");
+
+        Field field = Foo.class.getDeclaredField("name");
+        field.setAccessible(true);
+        String name = (String) field.get(foo);
+        if (!name.equals("foo")) {
+            throw new RuntimeException("unexpected Foo::name value = " + name);
+        }
+
+        checkOpenModule();
+    }
+
+    // check the module descriptor of the open module m4
+    static void checkOpenModule() {
+        ModuleDescriptor md = Foo.class.getModule().getDescriptor();
+        System.out.println(md);
+
+        if (!md.isOpen()) {
+            throw new RuntimeException("m4 is a open module");
+        }
+
+        if (md.packages().size() != 1 || !md.packages().contains("p4")) {
+            throw new RuntimeException("unexpected m4 packages: " + md.packages());
+        }
+
+        if (!md.opens().isEmpty()) {
+            throw new RuntimeException("unexpected m4 opens: " + md.opens());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/module-info.java	Thu Dec 01 21:39:49 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.
+ */
+
+open module m4 {
+    exports p4;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Foo.java	Thu Dec 01 21:39:49 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.
+ *
+ * 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 p4;
+
+public class Foo {
+    private final String name;
+
+    private Foo(String name) {
+        this.name = name;
+    }
+
+    public static Foo create(String name) {
+        return new Foo(name);
+    }
+}
--- a/jdk/test/tools/jmod/JmodTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jmod/JmodTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,13 +23,13 @@
 
 /*
  * @test
+ * @bug 8142968
+ * @summary Basic test for jmod
  * @library /lib/testlibrary
  * @modules jdk.compiler
  *          jdk.jlink
  * @build jdk.testlibrary.FileUtils CompilerUtils
  * @run testng JmodTest
- * @bug 8142968
- * @summary Basic test for jmod
  */
 
 import java.io.*;
@@ -76,6 +76,9 @@
         for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) {
             Path dir = EXPLODED_DIR.resolve(name);
             assertTrue(compileModule(name, dir.resolve("classes")));
+            copyResource(SRC_DIR.resolve("foo"),
+                         dir.resolve("classes"),
+                         "jdk/test/foo/resources/foo.properties");
             createCmds(dir.resolve("bin"));
             createLibs(dir.resolve("lib"));
             createConfigs(dir.resolve("conf"));
@@ -127,6 +130,7 @@
                 assertContains(r.output, CLASSES_PREFIX + "module-info.class");
                 assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class");
                 assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class");
+                assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties");
             });
     }
 
@@ -279,6 +283,7 @@
                  Set<String> expectedFilenames = new HashSet<>();
                  expectedFilenames.add(CLASSES_PREFIX + "module-info.class");
                  expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/Foo.class");
+                 expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/resources/foo.properties");
                  expectedFilenames.add(LIBS_PREFIX + "second.so");
                  expectedFilenames.add(LIBS_PREFIX + "third/third.so");
                  assertJmodContent(jmod, expectedFilenames);
@@ -303,15 +308,15 @@
              .assertSuccess()
              .resultChecker(r -> {
                  // Expect similar output: "foo,  requires mandated java.base
-                 // exports jdk.test.foo,  conceals jdk.test.foo.internal"
+                 // exports jdk.test.foo,  contains jdk.test.foo.internal"
                  Pattern p = Pattern.compile("\\s+foo\\s+requires\\s+mandated\\s+java.base");
                  assertTrue(p.matcher(r.output).find(),
                            "Expecting to find \"foo, requires java.base\"" +
                                 "in output, but did not: [" + r.output + "]");
                  p = Pattern.compile(
-                        "exports\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal");
+                        "exports\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal");
                  assertTrue(p.matcher(r.output).find(),
-                           "Expecting to find \"exports ..., conceals ...\"" +
+                           "Expecting to find \"exports ..., contains ...\"" +
                                 "in output, but did not: [" + r.output + "]");
              });
     }
@@ -369,6 +374,26 @@
     }
 
     @Test
+    public void testPackagesAttribute() throws IOException {
+        Path jmod = MODS_DIR.resolve("foo.jmod");
+        FileUtils.deleteFileIfExistsWithRetry(jmod);
+        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
+
+        Set<String> expectedPackages = Set.of("jdk.test.foo",
+                                              "jdk.test.foo.internal",
+                                              "jdk.test.foo.resources");
+
+        jmod("create",
+             "--class-path", cp,
+             jmod.toString())
+             .assertSuccess()
+             .resultChecker(r -> {
+                 Set<String> pkgs = getModuleDescriptor(jmod).packages();
+                 assertEquals(pkgs, expectedPackages);
+             });
+        }
+
+    @Test
     public void testVersion() {
         jmod("--version")
             .assertSuccess()
@@ -557,6 +582,14 @@
         }
     }
 
+    static void copyResource(Path srcDir, Path dir, String resource) throws IOException {
+        Path dest = dir.resolve(resource);
+        Files.deleteIfExists(dest);
+
+        Files.createDirectories(dest.getParent());
+        Files.copy(srcDir.resolve(resource), dest);
+    }
+
     // Standalone entry point.
     public static void main(String[] args) throws Throwable {
         JmodTest test = new JmodTest();
--- a/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,5 +22,5 @@
  */
 
 module org.bar {
-    requires public m1;
+    requires transitive m1;
 }
--- a/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,5 +22,5 @@
  */
 
 module org.foo {
-    requires public org.bar;
+    requires transitive org.bar;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/src/foo/jdk/test/foo/resources/foo.properties	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,1 @@
+name = foo 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/InfoStreams.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,78 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @build InfoStreams jdk.testlibrary.ProcessTools
+ * @run main InfoStreams
+ * @summary Test that informational options use the correct streams
+ */
+
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.OutputAnalyzer;
+
+
+public class InfoStreams {
+
+    public static OutputAnalyzer run(String ... opts) throws Exception {
+        return ProcessTools.executeTestJava(opts).shouldHaveExitValue(0);
+    }
+
+    private static final String
+        java_version = System.getProperty("java.version"),
+        USAGE = "^Usage: java ",
+        VERSION_ERR = "^(java|openjdk) version \"" + java_version + "\"",
+        VERSION_OUT = "^(java|openjdk) " + java_version,
+        FULLVERSION_ERR = "^(java|openjdk) full version \"" + java_version + ".*\"",
+        FULLVERSION_OUT = "^(java|openjdk) " + java_version,
+        NONSTD = ".*These extra options are subject to change";
+
+    public static void main(String ... args) throws Exception {
+
+        String classPath = System.getProperty("java.class.path");
+
+        run("-help").stderrShouldMatch(USAGE).stdoutShouldNotMatch(".");
+        run("--help").stdoutShouldMatch(USAGE).stderrShouldNotMatch(".");
+
+        run("-version").stderrShouldMatch(VERSION_ERR).stdoutShouldNotMatch(".");
+        run("--version").stdoutShouldMatch(VERSION_OUT).stderrShouldNotMatch(".");
+
+        run("-showversion", "--dry-run", "-cp", classPath, "InfoStreams")
+            .stderrShouldMatch(VERSION_ERR)
+            .stdoutShouldNotMatch(".");
+        run("--show-version", "--dry-run", "-cp", classPath, "InfoStreams")
+            .stdoutShouldMatch(VERSION_OUT)
+            .stderrShouldNotMatch(".");
+
+        run("-fullversion").stderrShouldMatch(FULLVERSION_ERR)
+            .stdoutShouldNotMatch(".");
+        run("--full-version").stdoutShouldMatch(FULLVERSION_OUT)
+            .stderrShouldNotMatch(".");
+
+        run("-X").stderrShouldMatch(NONSTD).stdoutShouldNotMatch(".");
+        run("--help-extra").stdoutShouldMatch(NONSTD).stderrShouldNotMatch(".");
+
+    }
+
+}
--- a/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -32,7 +32,9 @@
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.stream.Stream;
 
+import jdk.testlibrary.OutputAnalyzer;
 import static jdk.testlibrary.ProcessTools.*;
 
 import org.testng.annotations.BeforeTest;
@@ -202,13 +204,15 @@
 
 
     /**
-     * --add-exports allows duplicates
+     * --add-exports and --add-opens allows duplicates
      */
     public void testWithDuplicateOption() throws Exception {
 
         int exitValue
             =  executeTestJava("--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED",
                                "--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED",
+                               "--add-opens", "java.base/java.util=ALL-UNNAMED",
+                               "--add-opens", "java.base/java.util=ALL-UNNAMED",
                                "-version")
                 .outputTo(System.out)
                 .errorTo(System.out)
@@ -218,23 +222,33 @@
     }
 
 
+    private OutputAnalyzer execJava(String... options) {
+        try {
+            return executeTestJava(options);
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+
     /**
-     * Exercise --add-exports with unknown values.  Warning is emitted.
+     * Exercise --add-exports and --add-opens with unknown values.
+     * Warning is emitted.
      */
     @Test(dataProvider = "unknownvalues")
-    public void testWithUnknownValue(String value, String ignore) throws Exception {
+    public void testWithUnknownValue(String value, String ignore) {
+        Stream.of("--add-exports", "--add-opens")
+            .forEach(option -> {
+                //  --add-exports $VALUE -version
+                int exitValue = execJava(option, value, "-version")
+                    .stderrShouldMatch("WARNING: .*.monkey.*")
+                    .outputTo(System.out)
+                    .errorTo(System.out)
+                    .getExitValue();
 
-        //  --add-exports $VALUE -version
-        int exitValue =
-            executeTestJava("--add-exports", value,
-                            "-version")
-                .stderrShouldMatch("WARNING: .*.monkey.*")
-                .outputTo(System.out)
-                .errorTo(System.out)
-                .getExitValue();
+                assertTrue(exitValue == 0);
+            });
+    }
 
-        assertTrue(exitValue == 0);
-    }
 
     @DataProvider(name = "unknownvalues")
     public Object[][] unknownValues() {
@@ -250,20 +264,20 @@
 
 
     /**
-     * Exercise --add-exports with bad values
+     * Exercise --add-exports and --add-opens with bad values
      */
     @Test(dataProvider = "badvalues")
-    public void testWithBadValue(String value, String ignore) throws Exception {
-
-        //  --add-exports $VALUE -version
-        int exitValue =
-            executeTestJava("--add-exports", value,
-                            "-version")
-                .outputTo(System.out)
-                .errorTo(System.out)
-                .getExitValue();
+    public void testWithBadValue(String value, String ignore) {
+        Stream.of("--add-exports", "--add-opens")
+            .forEach(option -> {
+                //  --add-exports $VALUE -version
+                int exitValue = execJava(option, value, "-version")
+                    .outputTo(System.out)
+                    .errorTo(System.out)
+                    .getExitValue();
 
         assertTrue(exitValue != 0);
+            });
     }
 
     @DataProvider(name = "badvalues")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addexports/manifest/AddExportsAndOpensInManifest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,175 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @modules jdk.compiler
+ * @build AddExportsAndOpensInManifest Test2 JarUtils jdk.testlibrary.*
+ * @compile --add-exports=java.base/jdk.internal.misc=ALL-UNNAMED Test1.java
+ * @run testng AddExportsAndOpensInManifest
+ * @summary Basic test for Add-Exports and Add-Opens attributes in the
+ *          manifest of a main application JAR
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+
+@Test
+public class AddExportsAndOpensInManifest {
+
+    /**
+     * Package Test1 and Test2 into a JAR file with the given attributes
+     * in the JAR manifest, then execute the JAR file with `java -jar`.
+     */
+    private OutputAnalyzer runTest(String attributes) throws Exception {
+        Manifest man = new Manifest();
+        Attributes attrs = man.getMainAttributes();
+        attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
+
+        for (String nameAndValue : attributes.split(",")) {
+            String[] s = nameAndValue.split("=");
+            if (s.length != 2)
+                throw new RuntimeException("Malformed: " + nameAndValue);
+            String name = s[0];
+            String value = s[1];
+            attrs.put(new Attributes.Name(name), value);
+        }
+
+        // create the JAR file with Test1 and Test2
+        Path jarfile = Paths.get("test.jar");
+        Files.deleteIfExists(jarfile);
+
+        Path classes = Paths.get(System.getProperty("test.classes", ""));
+        JarUtils.createJarFile(jarfile, man, classes,
+                Paths.get("Test1.class"), Paths.get("Test2.class"));
+
+        // java -jar test.jar
+        return ProcessTools.executeTestJava("-jar", jarfile.toString())
+                .outputTo(System.out)
+                .errorTo(System.out);
+    }
+
+    /**
+     * Run test with the given JAR attributes, expecting the test to pass
+     */
+    private void runExpectingPass(String attrs) throws Exception {
+        int exitValue = runTest(attrs).getExitValue();
+        assertTrue(exitValue == 0);
+    }
+
+    /**
+     * Run test with the given JAR attributes, expecting the test to fail
+     * with at least the given output
+     */
+    private void runExpectingFail(String attrs, String errorString) throws Exception {
+        int exitValue = runTest(attrs).shouldContain(errorString).getExitValue();
+        assertTrue(exitValue != 0);
+    }
+
+
+    /**
+     * Run tests to make sure that they fail in the expected way.
+     */
+    public void testSanity() throws Exception {
+        runExpectingFail("Main-Class=Test1", "IllegalAccessError");
+        runExpectingFail("Main-Class=Test2", "InaccessibleObjectException");
+    }
+
+    /**
+     * Run tests with the Add-Exports attribute in the main manifest.
+     */
+    public void testWithAddExports() throws Exception {
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc");
+        runExpectingFail("Main-Class=Test2,Add-Exports=java.base/jdk.internal.misc",
+                         "InaccessibleObjectException");
+
+        // run with leading and trailing spaces
+        runExpectingPass("Main-Class=Test1,Add-Exports=  java.base/jdk.internal.misc");
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc  ");
+
+        // run with multiple values
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc"
+                + " java.base/jdk.internal.loader");
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.loader"
+                + " java.base/jdk.internal.misc");
+
+        // run with duplicate values
+        runExpectingPass("Main-Class=Test1,Add-Exports=java.base/jdk.internal.misc"
+                + " java.base/jdk.internal.misc");
+    }
+
+    /**
+     * Run tests with the Add-Opens attribute in the main manifest.
+     */
+    public void testWithAddOpens() throws Exception {
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc");
+        runExpectingPass("Main-Class=Test2,Add-Opens=java.base/jdk.internal.misc");
+
+        // run with leading and trailing spaces
+        runExpectingPass("Main-Class=Test1,Add-Opens=  java.base/jdk.internal.misc");
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc  ");
+
+        // run with multiple values
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc"
+                + " java.base/jdk.internal.loader");
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.loader"
+                + " java.base/jdk.internal.misc");
+
+        // run with duplicate values
+        runExpectingPass("Main-Class=Test1,Add-Opens=java.base/jdk.internal.misc"
+                + " java.base/jdk.internal.misc");
+    }
+
+    /**
+     * Run tests a bad module or package name
+     */
+    public void testWithBadModuleOrPackage() throws Exception {
+        // Add-Exports with bad module name
+        String attrs = "Main-Class=Test1,Add-Exports=java.DoesNotExist/jdk.internal.misc";
+        runExpectingFail(attrs, "IllegalAccessError");
+
+        // Add-Exports with bad package name
+        attrs = "Main-Class=Test1,Add-Exports=java.base/jdk.internal.DoesNotExit";
+        runExpectingFail(attrs, "IllegalAccessError");
+
+        // Add-Opens with bad module name
+        attrs = "Main-Class=Test1,Add-Opens=java.DoesNotExist/jdk.internal.misc";
+        runExpectingFail(attrs, "IllegalAccessError");
+
+        // Add-Opens with bad package name
+        attrs = "Main-Class=Test1,Add-Opens=java.base/jdk.internal.DoesNotExit";
+        runExpectingFail(attrs, "IllegalAccessError");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addexports/manifest/Test1.java	Thu Dec 01 21:39:49 2016 +0000
@@ -0,0 +1,30 @@
+/**
+ * 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 jdk.internal.misc.Unsafe;
+
+public class Test1 {
+    public static void main(String[] args) throws Exception {
+        Unsafe unsafe = Unsafe.getUnsafe();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addexports/manifest/Test2.java	Thu Dec 01 21:39:49 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.
+ *
+ * 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.lang.reflect.Field;
+
+/**
+ * Use core reflection and setAccessible(true) to access private field.
+ */
+
+public class Test2 {
+    public static void main(String[] args) throws Exception {
+        Class<?> c = Class.forName("jdk.internal.misc.Unsafe");
+        Field f = c.getDeclaredField("theUnsafe");
+        f.setAccessible(true);
+        Object unsafe = f.get(null);
+    }
+}
--- a/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java	Thu Dec 01 21:39:49 2016 +0000
@@ -23,13 +23,10 @@
 
 package jdk.test1;
 
-import java.lang.reflect.Field;
 import jdk.internal.misc.Unsafe;
 
 public class Main {
     public static void main(String[] args) throws Exception {
-        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-        theUnsafe.setAccessible(true);
-        Unsafe unsafe = (Unsafe) theUnsafe.get(null);
+        Unsafe unsafe = Unsafe.getUnsafe();
     }
 }
--- a/jdk/test/tools/launcher/modules/listmods/ListModsTest.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java	Thu Dec 01 21:39:49 2016 +0000
@@ -115,7 +115,7 @@
                 .outputTo(System.out)
                 .errorTo(System.out);
         output.shouldNotContain("java.base");
-        output.shouldNotContain("java.rhubarb");
+        output.shouldContain("java.rhubarb not observable");
         assertTrue(output.getExitValue() == 0);
     }
 
--- a/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java	Thu Dec 01 21:39:49 2016 +0000
@@ -22,6 +22,6 @@
  */
 
 module java.transaction {
-    requires public java.enterprise;
+    requires transitive java.enterprise;
     exports javax.transaction;
 }
--- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java	Thu Dec 01 21:01:53 2016 +0000
+++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java	Thu Dec 01 21:39:49 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -39,7 +39,6 @@
 import com.sun.tools.classfile.ClassFile;
 import com.sun.tools.classfile.Code_attribute;
 import com.sun.tools.classfile.CompilationID_attribute;
-import com.sun.tools.classfile.ConcealedPackages_attribute;
 import com.sun.tools.classfile.ConstantPool;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
 import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info;
@@ -65,8 +64,6 @@
 import com.sun.tools.classfile.EnclosingMethod_attribute;
 import com.sun.tools.classfile.Exceptions_attribute;
 import com.sun.tools.classfile.Field;
-import com.sun.tools.classfile.Hashes_attribute;
-import com.sun.tools.classfile.Hashes_attribute.Entry;
 import com.sun.tools.classfile.InnerClasses_attribute;
 import com.sun.tools.classfile.InnerClasses_attribute.Info;
 import com.sun.tools.classfile.Instruction;
@@ -74,13 +71,18 @@
 import com.sun.tools.classfile.LineNumberTable_attribute;
 import com.sun.tools.classfile.LocalVariableTable_attribute;
 import com.sun.tools.classfile.LocalVariableTypeTable_attribute;
-import com.sun.tools.classfile.MainClass_attribute;
 import com.sun.tools.classfile.Method;
 import com.sun.tools.classfile.MethodParameters_attribute;
 import com.sun.tools.classfile.Module_attribute;
 import com.sun.tools.classfile.Module_attribute.ExportsEntry;
 import com.sun.tools.classfile.Module_attribute.ProvidesEntry;
 import com.sun.tools.classfile.Module_attribute.RequiresEntry;
+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.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;
@@ -102,11 +104,9 @@
 import com.sun.tools.classfile.StackMapTable_attribute.same_locals_1_stack_item_frame_extended;
 import com.sun.tools.classfile.StackMap_attribute;
 import com.sun.tools.classfile.Synthetic_attribute;
-import com.sun.tools.classfile.TargetPlatform_attribute;
 import com.sun.tools.classfile.TypeAnnotation;
 import com.sun.tools.classfile.TypeAnnotation.Position;
 import static com.sun.tools.classfile.TypeAnnotation.TargetType.THROWS;
-import com.sun.tools.classfile.Version_attribute;
 import java.io.*;
 import java.util.*;
 import java.util.jar.JarEntry;
@@ -1017,7 +1017,7 @@
     }
 
     @Override
-    public Element visitConcealedPackages(ConcealedPackages_attribute attr, Element p) {
+    public Element visitModulePackages(ModulePackages_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
         for (int i : attr.packages_index) {
             Element ee = new Element("Package");
@@ -1128,7 +1128,7 @@
         for (ExportsEntry export : exports) {
             Element exto = new Element("exports");
             exto.setAttr("package", x.getCpString(export.exports_index));
-            for ( int idx : export.exports_to_index) {
+            for (int idx : export.exports_to_index) {
                 exto.setAttr("module", x.getCpString(idx));
             }
             ex.add(exto);
@@ -1140,7 +1140,9 @@
         Element ex = new Element("Provides");
         for (ProvidesEntry provide : provides) {
             ex.setAttr("provides", x.getCpString(provide.provides_index));
-            ex.setAttr("with", x.getCpString(provide.with_index));
+            for (int idx : provide.with_index) {
+                ex.setAttr("with", x.getCpString(idx));
+            }
         }
         p.add(ex);
     }
@@ -1461,14 +1463,20 @@
     }
 
     @Override
-    public Element visitHashes(Hashes_attribute attr, Element p) {
+    public Element visitModuleHashes(ModuleHashes_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
         e.setAttr("Algorithm", x.getCpString(attr.algorithm_index));
         for (Entry entry : attr.hashes_table) {
             Element ee = new Element("Entry");
-            String requires = x.getCpString(entry.requires_index);
-            String hashValue = x.getCpString(entry.hash_index);
-            ee.setAttr(requires, hashValue);
+            String mn = x.getCpString(entry.module_name_index);
+            ee.setAttr("module_name", mn);
+            ee.setAttr("hash_length", "" + entry.hash.length);
+            StringBuilder sb = new StringBuilder();
+            for (byte b: entry.hash) {
+                sb.append(String.format("%02x", b & 0xff));
+            }
+            ee.setAttr("hash", sb.toString());
+            ee.trimToSize();
             e.add(ee);
         }
         e.trimToSize();
@@ -1478,7 +1486,7 @@
     }
 
     @Override
-    public Element visitMainClass(MainClass_attribute attr, Element p) {
+    public Element visitModuleMainClass(ModuleMainClass_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
         e.add(x.getCpString(attr.main_class_index));
         e.trimToSize();
@@ -1487,7 +1495,7 @@
     }
 
     @Override
-    public Element visitTargetPlatform(TargetPlatform_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.os_name_index));
         e.add(x.getCpString(attr.os_arch_index));
@@ -1498,7 +1506,7 @@
     }
 
     @Override
-    public Element visitVersion(Version_attribute attr, Element p) {
+    public Element visitModuleVersion(ModuleVersion_attribute attr, Element p) {
         Element e = new Element(x.getCpString(attr.attribute_name_index));
         e.add(x.getCpString(attr.version_index));
         e.trimToSize();
@@ -1813,7 +1821,7 @@
 
     @Override
     public Element visitArray(Array_element_value a, Element p) {
-     Element el = new Element("Array");
+        Element el = new Element("Array");
         for (Annotation.element_value v : a.values) {
            Element child = visit(v, el);
            if (child != null) {