changeset 17732:7975190ee1b6

Merge
author prr
date Mon, 07 Aug 2017 09:45:38 -0700
parents 4b0d12ba70b8 ab069116200b
children 8c41faaf67ba
files src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java test/java/lang/ClassLoader/getResource/GetResource.sh test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java
diffstat 93 files changed, 2747 insertions(+), 1694 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Aug 07 10:02:39 2017 +0530
+++ b/.hgtags	Mon Aug 07 09:45:38 2017 -0700
@@ -439,3 +439,5 @@
 3281b964ab104002623d744e8b77a12269b70acd jdk-10+16
 443025bee731eb2225371b92c1c74b519b7baf33 jdk-9+178
 06df1ce4b9b887d05ce6a13f4def3547e434dd1a jdk-9+179
+d93f2fd542b7d7855c2cd49ae15ebcc3d441a83b jdk-10+17
+c4b709bad6c5d29294124de5e74e1e2ac84fcf1f jdk-10+18
--- a/src/java.base/share/classes/java/io/FilterOutputStream.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/io/FilterOutputStream.java	Mon Aug 07 09:45:38 2017 -0700
@@ -50,7 +50,12 @@
     /**
      * Whether the stream is closed; implicitly initialized to false.
      */
-    private boolean closed;
+    private volatile boolean closed;
+
+    /**
+     * Object used to prevent a race on the 'closed' instance variable.
+     */
+    private final Object closeLock = new Object();
 
     /**
      * Creates an output stream filter built on top of the specified
@@ -165,7 +170,12 @@
         if (closed) {
             return;
         }
-        closed = true;
+        synchronized (closeLock) {
+            if (closed) {
+                return;
+            }
+            closed = true;
+        }
 
         Throwable flushException = null;
         try {
--- a/src/java.base/share/classes/java/lang/Class.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/lang/Class.java	Mon Aug 07 09:45:38 2017 -0700
@@ -364,9 +364,9 @@
             // Reflective call to get caller class is only needed if a security manager
             // is present.  Avoid the overhead of making this call otherwise.
             caller = Reflection.getCallerClass();
-            if (VM.isSystemDomainLoader(loader)) {
+            if (loader == null) {
                 ClassLoader ccl = ClassLoader.getClassLoader(caller);
-                if (!VM.isSystemDomainLoader(ccl)) {
+                if (ccl != null) {
                     sm.checkPermission(
                         SecurityConstants.GET_CLASSLOADER_PERMISSION);
                 }
@@ -432,18 +432,21 @@
         Objects.requireNonNull(module);
         Objects.requireNonNull(name);
 
-        Class<?> caller = Reflection.getCallerClass();
-        if (caller != null && caller.getModule() != module) {
-            // if caller is null, Class.forName is the last java frame on the stack.
-            // java.base has all permissions
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
+        ClassLoader cl;
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            Class<?> caller = Reflection.getCallerClass();
+            if (caller != null && caller.getModule() != module) {
+                // if caller is null, Class.forName is the last java frame on the stack.
+                // java.base has all permissions
                 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
             }
+            PrivilegedAction<ClassLoader> pa = module::getClassLoader;
+            cl = AccessController.doPrivileged(pa);
+        } else {
+            cl = module.getClassLoader();
         }
 
-        PrivilegedAction<ClassLoader> pa = module::getClassLoader;
-        ClassLoader cl = AccessController.doPrivileged(pa);
         if (cl != null) {
             return cl.loadClass(module, name);
         } else {
--- a/src/java.base/share/classes/java/lang/Module.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/lang/Module.java	Mon Aug 07 09:45:38 2017 -0700
@@ -246,7 +246,6 @@
         return null;
     }
 
-
     // --
 
     // special Module to mean "all unnamed modules"
@@ -257,17 +256,38 @@
     private static final Module EVERYONE_MODULE = new Module(null);
     private static final Set<Module> EVERYONE_SET = Set.of(EVERYONE_MODULE);
 
+    /**
+     * The holder of data structures to support readability, exports, and
+     * service use added at runtime with the reflective APIs.
+     */
+    private static class ReflectionData {
+        /**
+         * A module (1st key) reads another module (2nd key)
+         */
+        static final WeakPairMap<Module, Module, Boolean> reads =
+            new WeakPairMap<>();
+
+        /**
+         * A module (1st key) exports or opens a package to another module
+         * (2nd key). The map value is a map of package name to a boolean
+         * that indicates if the package is opened.
+         */
+        static final WeakPairMap<Module, Module, Map<String, Boolean>> exports =
+            new WeakPairMap<>();
+
+        /**
+         * A module (1st key) uses a service (2nd key)
+         */
+        static final WeakPairMap<Module, Class<?>, Boolean> uses =
+            new WeakPairMap<>();
+    }
+
 
     // -- readability --
 
     // 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> reflectivelyReads
-        = new WeakPairMap<>();
-
-
     /**
      * Indicates if this module reads the given module. This method returns
      * {@code true} if invoked to test if this module reads itself. It also
@@ -300,13 +320,13 @@
         }
 
         // check if this module reads the other module reflectively
-        if (reflectivelyReads.containsKeyPair(this, other))
+        if (ReflectionData.reads.containsKeyPair(this, other))
             return true;
 
         // if other is an unnamed module then check if this module reads
         // all unnamed modules
         if (!other.isNamed()
-            && reflectivelyReads.containsKeyPair(this, ALL_UNNAMED_MODULE))
+            && ReflectionData.reads.containsKeyPair(this, ALL_UNNAMED_MODULE))
             return true;
 
         return false;
@@ -393,7 +413,7 @@
             }
 
             // add reflective read
-            reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE);
+            ReflectionData.reads.putIfAbsent(this, other, Boolean.TRUE);
         }
     }
 
@@ -408,13 +428,6 @@
     // if the value contains EVERYONE_MODULE then the package is exported to all
     private volatile Map<String, Set<Module>> exportedPackages;
 
-    // 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>>
-        reflectivelyExports = new WeakPairMap<>();
-
-
     /**
      * Returns {@code true} if this module exports the given package to at
      * least the given module.
@@ -600,7 +613,7 @@
      */
     private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) {
         // exported or open to all modules
-        Map<String, Boolean> exports = reflectivelyExports.get(this, EVERYONE_MODULE);
+        Map<String, Boolean> exports = ReflectionData.exports.get(this, EVERYONE_MODULE);
         if (exports != null) {
             Boolean b = exports.get(pn);
             if (b != null) {
@@ -612,7 +625,7 @@
         if (other != EVERYONE_MODULE) {
 
             // exported or open to other
-            exports = reflectivelyExports.get(this, other);
+            exports = ReflectionData.exports.get(this, other);
             if (exports != null) {
                 Boolean b = exports.get(pn);
                 if (b != null) {
@@ -623,7 +636,7 @@
 
             // other is an unnamed module && exported or open to all unnamed
             if (!other.isNamed()) {
-                exports = reflectivelyExports.get(this, ALL_UNNAMED_MODULE);
+                exports = ReflectionData.exports.get(this, ALL_UNNAMED_MODULE);
                 if (exports != null) {
                     Boolean b = exports.get(pn);
                     if (b != null) {
@@ -886,8 +899,8 @@
             }
         }
 
-        // add package name to reflectivelyExports if absent
-        Map<String, Boolean> map = reflectivelyExports
+        // add package name to exports if absent
+        Map<String, Boolean> map = ReflectionData.exports
             .computeIfAbsent(this, other,
                              (m1, m2) -> new ConcurrentHashMap<>());
         if (open) {
@@ -932,10 +945,6 @@
 
     // -- services --
 
-    // additional service type (2nd key) that some module (1st key) uses
-    private static final WeakPairMap<Module, Class<?>, Boolean> reflectivelyUses
-        = new WeakPairMap<>();
-
     /**
      * If the caller's module is this module then update this module to add a
      * service dependence on the given service type. This method is intended
@@ -980,7 +989,7 @@
      */
     void implAddUses(Class<?> service) {
         if (!canUse(service)) {
-            reflectivelyUses.putIfAbsent(this, service, Boolean.TRUE);
+            ReflectionData.uses.putIfAbsent(this, service, Boolean.TRUE);
         }
     }
 
@@ -1011,7 +1020,7 @@
             return true;
 
         // uses added via addUses
-        return reflectivelyUses.containsKeyPair(this, service);
+        return ReflectionData.uses.containsKeyPair(this, service);
     }
 
 
@@ -1060,8 +1069,11 @@
                                              Function<String, ClassLoader> clf,
                                              ModuleLayer layer)
     {
-        Map<String, Module> nameToModule = new HashMap<>();
-        Map<String, ClassLoader> moduleToLoader = new HashMap<>();
+        boolean isBootLayer = (ModuleLayer.boot() == null);
+
+        int cap = (int)(cf.modules().size() / 0.75f + 1.0f);
+        Map<String, Module> nameToModule = new HashMap<>(cap);
+        Map<String, ClassLoader> nameToLoader = new HashMap<>(cap);
 
         Set<ClassLoader> loaders = new HashSet<>();
         boolean hasPlatformModules = false;
@@ -1070,7 +1082,7 @@
         for (ResolvedModule resolvedModule : cf.modules()) {
             String name = resolvedModule.name();
             ClassLoader loader = clf.apply(name);
-            moduleToLoader.put(name, loader);
+            nameToLoader.put(name, loader);
             if (loader == null || loader == ClassLoaders.platformClassLoader()) {
                 if (!(clf instanceof ModuleLoaderMap.Mapper)) {
                     throw new IllegalArgumentException("loader can't be 'null'"
@@ -1087,20 +1099,19 @@
             ModuleReference mref = resolvedModule.reference();
             ModuleDescriptor descriptor = mref.descriptor();
             String name = descriptor.name();
-            URI uri = mref.location().orElse(null);
-            ClassLoader loader = moduleToLoader.get(resolvedModule.name());
+            ClassLoader loader = nameToLoader.get(name);
             Module m;
             if (loader == null && name.equals("java.base")) {
                 // java.base is already defined to the VM
                 m = Object.class.getModule();
             } else {
+                URI uri = mref.location().orElse(null);
                 m = new Module(layer, loader, descriptor, uri);
             }
             nameToModule.put(name, m);
-            moduleToLoader.put(name, loader);
         }
 
-        // setup readability and exports
+        // setup readability and exports/opens
         for (ResolvedModule resolvedModule : cf.modules()) {
             ModuleReference mref = resolvedModule.reference();
             ModuleDescriptor descriptor = mref.descriptor();
@@ -1146,7 +1157,18 @@
             }
 
             // exports and opens
-            initExportsAndOpens(m, nameToSource, nameToModule, layer.parents());
+            if (descriptor.isOpen() || descriptor.isAutomatic()) {
+                // The VM doesn't special case open or automatic modules yet
+                // so need to export all packages
+                for (String source : descriptor.packages()) {
+                    addExportsToAll0(m, source);
+                }
+            } else if (isBootLayer && descriptor.opens().isEmpty()) {
+                // no open packages, no qualified exports to modules in parent layers
+                initExports(m, nameToModule);
+            } else {
+                initExportsAndOpens(m, nameToSource, nameToModule, layer.parents());
+            }
         }
 
         // if there are modules defined to the boot or platform class loaders
@@ -1161,7 +1183,7 @@
                 if (!descriptor.provides().isEmpty()) {
                     String name = descriptor.name();
                     Module m = nameToModule.get(name);
-                    ClassLoader loader = moduleToLoader.get(name);
+                    ClassLoader loader = nameToLoader.get(name);
                     if (loader == null) {
                         bootCatalog.register(m);
                     } else if (loader == pcl) {
@@ -1179,7 +1201,6 @@
         return nameToModule;
     }
 
-
     /**
      * Find the runtime Module corresponding to the given ResolvedModule
      * in the given parent layer (or its parents).
@@ -1201,25 +1222,55 @@
                 .orElse(null);
     }
 
+    /**
+     * Initialize/setup a module's exports.
+     *
+     * @param m the module
+     * @param nameToModule map of module name to Module (for qualified exports)
+     */
+    private static void initExports(Module m, Map<String, Module> nameToModule) {
+        Map<String, Set<Module>> exportedPackages = new HashMap<>();
+
+        for (Exports exports : m.getDescriptor().exports()) {
+            String source = exports.source();
+            if (exports.isQualified()) {
+                // qualified exports
+                Set<Module> targets = new HashSet<>();
+                for (String target : exports.targets()) {
+                    Module m2 = nameToModule.get(target);
+                    if (m2 != null) {
+                        addExports0(m, source, m2);
+                        targets.add(m2);
+                    }
+                }
+                if (!targets.isEmpty()) {
+                    exportedPackages.put(source, targets);
+                }
+            } else {
+                // unqualified exports
+                addExportsToAll0(m, source);
+                exportedPackages.put(source, EVERYONE_SET);
+            }
+        }
+
+        if (!exportedPackages.isEmpty())
+            m.exportedPackages = exportedPackages;
+    }
 
     /**
-     * Initialize the maps of exported and open packages for module m.
+     * Initialize/setup a module's exports.
+     *
+     * @param m the module
+     * @param nameToSource map of module name to Module for modules that m reads
+     * @param nameToModule map of module name to Module for modules in the layer
+     *                     under construction
+     * @param parents the parent layers
      */
     private static void initExportsAndOpens(Module m,
                                             Map<String, Module> nameToSource,
                                             Map<String, Module> nameToModule,
                                             List<ModuleLayer> parents) {
-        // The VM doesn't special case open or automatic modules so need to
-        // export all packages
         ModuleDescriptor descriptor = m.getDescriptor();
-        if (descriptor.isOpen() || descriptor.isAutomatic()) {
-            assert descriptor.opens().isEmpty();
-            for (String source : descriptor.packages()) {
-                addExportsToAll0(m, source);
-            }
-            return;
-        }
-
         Map<String, Set<Module>> openPackages = new HashMap<>();
         Map<String, Set<Module>> exportedPackages = new HashMap<>();
 
@@ -1272,7 +1323,6 @@
                 if (!targets.isEmpty()) {
                     exportedPackages.put(source, targets);
                 }
-
             } else {
                 // unqualified exports
                 addExportsToAll0(m, source);
--- a/src/java.base/share/classes/java/lang/System.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/lang/System.java	Mon Aug 07 09:45:38 2017 -0700
@@ -313,6 +313,10 @@
      * @see java.lang.RuntimePermission
      */
     public static void setSecurityManager(final SecurityManager s) {
+        if (security == null) {
+            // ensure image reader is initialized
+            Object.class.getResource("java/lang/ANY");
+        }
         if (s != null) {
             try {
                 s.checkPackageAccess("java.lang");
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Mon Aug 07 09:45:38 2017 -0700
@@ -2476,7 +2476,7 @@
                 return false;
             }
             ClassLoader loader = defc.getClassLoader();
-            if (!jdk.internal.misc.VM.isSystemDomainLoader(loader)) {
+            if (loader != null) {
                 ClassLoader sysl = ClassLoader.getSystemClassLoader();
                 boolean found = false;
                 while (sysl != null) {
--- a/src/java.base/share/classes/java/lang/module/Configuration.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/lang/module/Configuration.java	Mon Aug 07 09:45:38 2017 -0700
@@ -31,6 +31,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Deque;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -41,6 +42,9 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import jdk.internal.module.ModuleReferenceImpl;
+import jdk.internal.module.ModuleTarget;
+
 /**
  * A configuration that is the result of <a href="package-summary.html#resolution">
  * resolution</a> or resolution with <a href="#service-binding">service binding</a>.
@@ -121,11 +125,8 @@
         this.targetPlatform = null;
     }
 
-    private Configuration(List<Configuration> parents,
-                          Resolver resolver,
-                          boolean check)
-    {
-        Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check);
+    private Configuration(List<Configuration> parents, Resolver resolver) {
+        Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this);
 
         @SuppressWarnings(value = {"rawtypes", "unchecked"})
         Entry<String, ResolvedModule>[] nameEntries
@@ -147,6 +148,62 @@
     }
 
     /**
+     * Creates the Configuration for the boot layer from a pre-generated
+     * readability graph.
+     *
+     * @apiNote This method is coded for startup performance.
+     */
+    Configuration(ModuleFinder finder, Map<String, Set<String>> map) {
+        int moduleCount = map.size();
+
+        // create map of name -> ResolvedModule
+        @SuppressWarnings(value = {"rawtypes", "unchecked"})
+        Entry<String, ResolvedModule>[] nameEntries
+            = (Entry<String, ResolvedModule>[])new Entry[moduleCount];
+        ResolvedModule[] moduleArray = new ResolvedModule[moduleCount];
+        String targetPlatform = null;
+        int i = 0;
+        for (String name : map.keySet()) {
+            ModuleReference mref = finder.find(name).orElse(null);
+            assert mref != null;
+
+            if (targetPlatform == null && mref instanceof ModuleReferenceImpl) {
+                ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget();
+                if (target != null) {
+                    targetPlatform = target.targetPlatform();
+                }
+            }
+
+            ResolvedModule resolvedModule = new ResolvedModule(this, mref);
+            moduleArray[i] = resolvedModule;
+            nameEntries[i] = Map.entry(name, resolvedModule);
+            i++;
+        }
+        Map<String, ResolvedModule> nameToModule = Map.ofEntries(nameEntries);
+
+        // create entries for readability graph
+        @SuppressWarnings(value = {"rawtypes", "unchecked"})
+        Entry<ResolvedModule, Set<ResolvedModule>>[] moduleEntries
+            = (Entry<ResolvedModule, Set<ResolvedModule>>[])new Entry[moduleCount];
+        i = 0;
+        for (ResolvedModule resolvedModule : moduleArray) {
+            Set<String> names = map.get(resolvedModule.name());
+            ResolvedModule[] readsArray = new ResolvedModule[names.size()];
+            int j = 0;
+            for (String name : names) {
+                readsArray[j++] = nameToModule.get(name);
+            }
+            moduleEntries[i++] = Map.entry(resolvedModule, Set.of(readsArray));
+        }
+
+        this.parents = List.of(empty());
+        this.graph = Map.ofEntries(moduleEntries);
+        this.modules = Set.of(moduleArray);
+        this.nameToModule = nameToModule;
+        this.targetPlatform = targetPlatform;
+    }
+
+    /**
      * Resolves a collection of root modules, with this configuration as its
      * parent, to create a new configuration. This method works exactly as
      * specified by the static {@link
@@ -233,24 +290,20 @@
 
     /**
      * Resolves a collection of root modules, with service binding, and with
-     * the empty configuration as its parent. The consistency checks
-     * are optionally run.
+     * the empty configuration as its parent.
      *
      * This method is used to create the configuration for the boot layer.
      */
     static Configuration resolveAndBind(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.resolve(roots).bind();
-
-        return new Configuration(parents, resolver, check);
+        return new Configuration(parents, resolver);
     }
 
-
     /**
      * Resolves a collection of root modules to create a configuration.
      *
@@ -356,7 +409,7 @@
         Resolver resolver = new Resolver(before, parentList, after, null);
         resolver.resolve(roots);
 
-        return new Configuration(parentList, resolver, true);
+        return new Configuration(parentList, resolver);
     }
 
     /**
@@ -427,7 +480,7 @@
         Resolver resolver = new Resolver(before, parentList, after, null);
         resolver.resolve(roots).bind();
 
-        return new Configuration(parentList, resolver, true);
+        return new Configuration(parentList, resolver);
     }
 
 
--- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Mon Aug 07 09:45:38 2017 -0700
@@ -2728,10 +2728,15 @@
                 @Override
                 public Configuration resolveAndBind(ModuleFinder finder,
                                                     Collection<String> roots,
-                                                    boolean check,
                                                     PrintStream traceOutput)
                 {
-                    return Configuration.resolveAndBind(finder, roots, check, traceOutput);
+                    return Configuration.resolveAndBind(finder, roots, traceOutput);
+                }
+
+                @Override
+                public Configuration newConfiguration(ModuleFinder finder,
+                                                      Map<String, Set<String>> graph) {
+                    return new Configuration(finder, graph);
                 }
             });
     }
--- a/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Mon Aug 07 09:45:38 2017 -0700
@@ -25,9 +25,7 @@
 
 package java.lang.module;
 
-import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.security.AccessController;
 import java.security.Permission;
 import java.security.PrivilegedAction;
@@ -40,10 +38,8 @@
 import java.util.Optional;
 import java.util.Set;
 
-import jdk.internal.module.ModuleBootstrap;
-import jdk.internal.module.ModulePatcher;
 import jdk.internal.module.ModulePath;
-import jdk.internal.module.SystemModuleFinder;
+import jdk.internal.module.SystemModuleFinders;
 
 /**
  * A finder of modules. A {@code ModuleFinder} is used to find modules during
@@ -157,53 +153,14 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             sm.checkPermission(new RuntimePermission("accessSystemModules"));
-            PrivilegedAction<ModuleFinder> pa = ModuleFinder::privilegedOfSystem;
+            PrivilegedAction<ModuleFinder> pa = SystemModuleFinders::ofSystem;
             return AccessController.doPrivileged(pa);
         } else {
-            return privilegedOfSystem();
+            return SystemModuleFinders.ofSystem();
         }
     }
 
     /**
-     * Returns a module finder that locates the system modules. This method
-     * assumes it has permissions to access the runtime image.
-     */
-    private static ModuleFinder privilegedOfSystem() {
-        String home = System.getProperty("java.home");
-        Path modules = Paths.get(home, "lib", "modules");
-        if (Files.isRegularFile(modules)) {
-            return SystemModuleFinder.getInstance();
-        } else {
-            Path dir = Paths.get(home, "modules");
-            if (Files.isDirectory(dir)) {
-                return privilegedOf(ModuleBootstrap.patcher(), dir);
-            } else {
-                throw new InternalError("Unable to detect the run-time image");
-            }
-        }
-    }
-
-    /**
-     * Returns a module finder that locates the system modules in an exploded
-     * image. The image may be patched.
-     */
-    private static ModuleFinder privilegedOf(ModulePatcher patcher, Path dir) {
-        ModuleFinder finder = ModulePath.of(patcher, dir);
-        return new ModuleFinder() {
-            @Override
-            public Optional<ModuleReference> find(String name) {
-                PrivilegedAction<Optional<ModuleReference>> pa = () -> finder.find(name);
-                return AccessController.doPrivileged(pa);
-            }
-            @Override
-            public Set<ModuleReference> findAll() {
-                PrivilegedAction<Set<ModuleReference>> pa = finder::findAll;
-                return AccessController.doPrivileged(pa);
-            }
-        };
-    }
-
-    /**
      * Returns a module finder that locates modules on the file system by
      * searching a sequence of directories and/or packaged modules.
      *
--- a/src/java.base/share/classes/java/lang/module/Resolver.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/lang/module/Resolver.java	Mon Aug 07 09:45:38 2017 -0700
@@ -353,25 +353,13 @@
 
     /**
      * Execute post-resolution checks and returns the module graph of resolved
-     * modules as {@code Map}. The resolved modules will be in the given
-     * configuration.
-     *
-     * @param check {@true} to execute the post resolution checks
+     * modules as a map.
      */
-    Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf,
-                                                    boolean check)
-    {
-        if (check) {
-            detectCycles();
-            checkHashes();
-        }
-
+    Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf) {
+        detectCycles();
+        checkHashes();
         Map<ResolvedModule, Set<ResolvedModule>> graph = makeGraph(cf);
-
-        if (check) {
-            checkExportSuppliers(graph);
-        }
-
+        checkExportSuppliers(graph);
         return graph;
     }
 
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java	Mon Aug 07 09:45:38 2017 -0700
@@ -453,7 +453,7 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             ClassLoader ccl = caller.getClassLoader();
-            if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
+            if (loader == null && ccl != null) {
                 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
             }
             ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
--- a/src/java.base/share/classes/java/net/URL.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/net/URL.java	Mon Aug 07 09:45:38 2017 -0700
@@ -409,7 +409,7 @@
             }
         }
 
-        protocol = protocol.toLowerCase(Locale.ROOT);
+        protocol = toLowerCase(protocol);
         this.protocol = protocol;
         if (host != null) {
 
@@ -585,7 +585,7 @@
             for (i = start ; !aRef && (i < limit) &&
                      ((c = spec.charAt(i)) != '/') ; i++) {
                 if (c == ':') {
-                    String s = spec.substring(start, i).toLowerCase(Locale.ROOT);
+                    String s = toLowerCase(spec.substring(start, i));
                     if (isValidProtocol(s)) {
                         newProtocol = s;
                         start = i + 1;
@@ -1318,6 +1318,17 @@
         }
     }
 
+    /**
+     * Returns the protocol in lower case. Special cases known protocols
+     * to avoid loading locale classes during startup.
+     */
+    static String toLowerCase(String protocol) {
+        if (protocol.equals("jrt") || protocol.equals("file") || protocol.equals("jar")) {
+            return protocol;
+        } else {
+            return protocol.toLowerCase(Locale.ROOT);
+        }
+    }
 
     /**
      * Non-overrideable protocols: "jrt" and "file"
--- a/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java	Mon Aug 07 09:45:38 2017 -0700
@@ -70,7 +70,7 @@
     extends Selector
 {
 
-    private AtomicBoolean selectorOpen = new AtomicBoolean(true);
+    private final AtomicBoolean selectorOpen = new AtomicBoolean(true);
 
     // The provider that created this selector
     private final SelectorProvider provider;
--- a/src/java.base/share/classes/java/security/MessageDigest.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/security/MessageDigest.java	Mon Aug 07 09:45:38 2017 -0700
@@ -57,7 +57,7 @@
  * and catching the CloneNotSupportedException:
  *
  * <pre>{@code
- * MessageDigest md = MessageDigest.getInstance("SHA");
+ * MessageDigest md = MessageDigest.getInstance("SHA-256");
  *
  * try {
  *     md.update(toChapter1);
@@ -496,7 +496,7 @@
     /**
      * Returns a string that identifies the algorithm, independent of
      * implementation details. The name should be a standard
-     * Java Security name (such as "SHA", "MD5", and so on).
+     * Java Security name (such as "SHA-256").
      * See the MessageDigest section in the <a href=
      * "{@docRoot}/../specs/security/standard-names.html#messagedigest-algorithms">
      * Java Security Standard Algorithm Names Specification</a>
--- a/src/java.base/share/classes/java/security/Signature.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/security/Signature.java	Mon Aug 07 09:45:38 2017 -0700
@@ -51,11 +51,10 @@
  * authentication and integrity assurance of digital data.
  *
  * <p> The signature algorithm can be, among others, the NIST standard
- * DSA, using DSA and SHA-1. The DSA algorithm using the
- * SHA-1 message digest algorithm can be specified as {@code SHA1withDSA}.
- * In the case of RSA, there are multiple choices for the message digest
- * algorithm, so the signing algorithm could be specified as, for example,
- * {@code MD2withRSA}, {@code MD5withRSA}, or {@code SHA1withRSA}.
+ * DSA, using DSA and SHA-256. The DSA algorithm using the
+ * SHA-256 message digest algorithm can be specified as {@code SHA256withDSA}.
+ * In the case of RSA the signing algorithm could be specified as, for example,
+ * {@code SHA256withRSA}.
  * The algorithm name must be specified, as there is no default.
  *
  * <p> A Signature object can be used to generate and verify digital
--- a/src/java.base/share/classes/java/security/SignedObject.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/security/SignedObject.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -81,13 +81,12 @@
  * verification in an attempt to bypass a security check.
  *
  * <p> The signature algorithm can be, among others, the NIST standard
- * DSA, using DSA and SHA-1.  The algorithm is specified using the
+ * DSA, using DSA and SHA-256.  The algorithm is specified using the
  * same convention as that for signatures. The DSA algorithm using the
- * SHA-1 message digest algorithm can be specified, for example, as
- * "SHA/DSA" or "SHA-1/DSA" (they are equivalent).  In the case of
- * RSA, there are multiple choices for the message digest algorithm,
- * so the signing algorithm could be specified as, for example,
- * "MD2/RSA", "MD5/RSA" or "SHA-1/RSA".  The algorithm name must be
+ * SHA-256 message digest algorithm can be specified, for example, as
+ * "SHA256withDSA".  In the case of
+ * RSA the signing algorithm could be specified as, for example,
+ * "SHA256withRSA".  The algorithm name must be
  * specified, as there is no default.
  *
  * <p> The name of the Cryptography Package Provider is designated
--- a/src/java.base/share/classes/java/util/regex/Pattern.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/java/util/regex/Pattern.java	Mon Aug 07 09:45:38 2017 -0700
@@ -667,11 +667,11 @@
  * <tr><td>{@code \p{Alpha}}</td>
  *     <td>An alphabetic character:{@code \p{IsAlphabetic}}</td></tr>
  * <tr><td>{@code \p{Digit}}</td>
- *     <td>A decimal digit character:{@code p{IsDigit}}</td></tr>
+ *     <td>A decimal digit character:{@code \p{IsDigit}}</td></tr>
  * <tr><td>{@code \p{Alnum}}</td>
  *     <td>An alphanumeric character:{@code [\p{IsAlphabetic}\p{IsDigit}]}</td></tr>
  * <tr><td>{@code \p{Punct}}</td>
- *     <td>A punctuation character:{@code p{IsPunctuation}}</td></tr>
+ *     <td>A punctuation character:{@code \p{IsPunctuation}}</td></tr>
  * <tr><td>{@code \p{Graph}}</td>
  *     <td>A visible character: {@code [^\p{IsWhite_Space}\p{gc=Cc}\p{gc=Cs}\p{gc=Cn}]}</td></tr>
  * <tr><td>{@code \p{Print}}</td>
--- a/src/java.base/share/classes/javax/crypto/Cipher.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/javax/crypto/Cipher.java	Mon Aug 07 09:45:38 2017 -0700
@@ -59,7 +59,7 @@
  * <p>A <i>transformation</i> is a string that describes the operation (or
  * set of operations) to be performed on the given input, to produce some
  * output. A transformation always includes the name of a cryptographic
- * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and
+ * algorithm (e.g., <i>AES</i>), and may be followed by a feedback mode and
  * padding scheme.
  *
  * <p> A transformation is of the form:
@@ -75,17 +75,19 @@
  * For example, the following is a valid transformation:
  *
  * <pre>
- *     Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>");
+ *     Cipher c = Cipher.getInstance("<i>AES/CBC/PKCS5Padding</i>");
  * </pre>
  *
  * Using modes such as {@code CFB} and {@code OFB}, block
  * ciphers can encrypt data in units smaller than the cipher's actual
  * block size.  When requesting such a mode, you may optionally specify
  * the number of bits to be processed at a time by appending this number
- * to the mode name as shown in the "{@code DES/CFB8/NoPadding}" and
- * "{@code DES/OFB32/PKCS5Padding}" transformations. If no such
- * number is specified, a provider-specific default is used. (For
- * example, the SunJCE provider uses a default of 64 bits for DES.)
+ * to the mode name as shown in the "{@code AES/CFB8/NoPadding}" and
+ * "{@code AES/OFB32/PKCS5Padding}" transformations. If no such
+ * number is specified, a provider-specific default is used.
+ * (See the
+ * {@extLink security_guide_jdk_providers JDK Providers Documentation}
+ * for the JDK Providers default values.)
  * Thus, block ciphers can be turned into byte-oriented stream ciphers by
  * using an 8 bit mode such as CFB8 or OFB8.
  * <p>
@@ -308,7 +310,7 @@
         /*
          * array containing the components of a Cipher transformation:
          *
-         * index 0: algorithm component (e.g., DES)
+         * index 0: algorithm component (e.g., AES)
          * index 1: feedback component (e.g., CFB)
          * index 2: padding component (e.g., PKCS5Padding)
          */
@@ -354,8 +356,8 @@
         // transform string to lookup in the provider
         final String transform;
         // the mode/padding suffix in upper case. for example, if the algorithm
-        // to lookup is "DES/CBC/PKCS5Padding" suffix is "/CBC/PKCS5PADDING"
-        // if loopup is "DES", suffix is the empty string
+        // to lookup is "AES/CBC/PKCS5Padding" suffix is "/CBC/PKCS5PADDING"
+        // if lookup is "AES", suffix is the empty string
         // needed because aliases prevent straight transform.equals()
         final String suffix;
         // value to pass to setMode() or null if no such call required
@@ -440,11 +442,11 @@
         }
 
         if ((mode == null) && (pad == null)) {
-            // DES
+            // AES
             Transform tr = new Transform(alg, "", null, null);
             return Collections.singletonList(tr);
         } else { // if ((mode != null) && (pad != null)) {
-            // DES/CBC/PKCS5Padding
+            // AES/CBC/PKCS5Padding
             List<Transform> list = new ArrayList<>(4);
             list.add(new Transform(alg, "/" + mode + "/" + pad, null, null));
             list.add(new Transform(alg, "/" + mode, null, pad));
@@ -488,7 +490,7 @@
      * {@link Security#getProviders() Security.getProviders()}.
      *
      * @param transformation the name of the transformation, e.g.,
-     * <i>DES/CBC/PKCS5Padding</i>.
+     * <i>AES/CBC/PKCS5Padding</i>.
      * See the Cipher section in the <a href=
      *   "{@docRoot}/../specs/security/standard-names.html#cipher-algorithm-names">
      * Java Security Standard Algorithm Names Specification</a>
@@ -566,7 +568,7 @@
      * the {@link Security#getProviders() Security.getProviders()} method.
      *
      * @param transformation the name of the transformation,
-     * e.g., <i>DES/CBC/PKCS5Padding</i>.
+     * e.g., <i>AES/CBC/PKCS5Padding</i>.
      * See the Cipher section in the <a href=
      *   "{@docRoot}/../specs/security/standard-names.html#cipher-algorithm-names">
      * Java Security Standard Algorithm Names Specification</a>
@@ -626,7 +628,7 @@
      * does not have to be registered in the provider list.
      *
      * @param transformation the name of the transformation,
-     * e.g., <i>DES/CBC/PKCS5Padding</i>.
+     * e.g., <i>AES/CBC/PKCS5Padding</i>.
      * See the Cipher section in the <a href=
      *   "{@docRoot}/../specs/security/standard-names.html#cipher-algorithm-names">
      * Java Security Standard Algorithm Names Specification</a>
--- a/src/java.base/share/classes/javax/crypto/CipherSpi.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/javax/crypto/CipherSpi.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -59,7 +59,7 @@
  * <p>A <i>transformation</i> is a string that describes the operation (or
  * set of operations) to be performed on the given input, to produce some
  * output. A transformation always includes the name of a cryptographic
- * algorithm (e.g., <i>DES</i>), and may be followed by a feedback mode and
+ * algorithm (e.g., <i>AES</i>), and may be followed by a feedback mode and
  * padding scheme.
  *
  * <p> A transformation is of the form:
@@ -75,7 +75,7 @@
  * For example, the following is a valid transformation:
  *
  * <pre>
- *     Cipher c = Cipher.getInstance("<i>DES/CBC/PKCS5Padding</i>");
+ *     Cipher c = Cipher.getInstance("<i>AES/CBC/PKCS5Padding</i>");
  * </pre>
  *
  * <p>A provider may supply a separate class for each combination
@@ -125,32 +125,32 @@
  * </ul>
  *
  * <p>For example, a provider may supply a subclass of <code>CipherSpi</code>
- * that implements <i>DES/ECB/PKCS5Padding</i>, one that implements
- * <i>DES/CBC/PKCS5Padding</i>, one that implements
- * <i>DES/CFB/PKCS5Padding</i>, and yet another one that implements
- * <i>DES/OFB/PKCS5Padding</i>. That provider would have the following
+ * that implements <i>AES/ECB/PKCS5Padding</i>, one that implements
+ * <i>AES/CBC/PKCS5Padding</i>, one that implements
+ * <i>AES/CFB/PKCS5Padding</i>, and yet another one that implements
+ * <i>AES/OFB/PKCS5Padding</i>. That provider would have the following
  * <code>Cipher</code> properties in its master class:
  *
  * <ul>
  *
  * <li>
  * <pre>
- *     <code>Cipher.</code><i>DES/ECB/PKCS5Padding</i>
+ *     <code>Cipher.</code><i>AES/ECB/PKCS5Padding</i>
  * </pre>
  *
  * <li>
  * <pre>
- *     <code>Cipher.</code><i>DES/CBC/PKCS5Padding</i>
+ *     <code>Cipher.</code><i>AES/CBC/PKCS5Padding</i>
  * </pre>
  *
  * <li>
  * <pre>
- *     <code>Cipher.</code><i>DES/CFB/PKCS5Padding</i>
+ *     <code>Cipher.</code><i>AES/CFB/PKCS5Padding</i>
  * </pre>
  *
  * <li>
  * <pre>
- *     <code>Cipher.</code><i>DES/OFB/PKCS5Padding</i>
+ *     <code>Cipher.</code><i>AES/OFB/PKCS5Padding</i>
  * </pre>
  *
  * </ul>
@@ -158,7 +158,7 @@
  * <p>Another provider may implement a class for each of the above modes
  * (i.e., one class for <i>ECB</i>, one for <i>CBC</i>, one for <i>CFB</i>,
  * and one for <i>OFB</i>), one class for <i>PKCS5Padding</i>,
- * and a generic <i>DES</i> class that subclasses from <code>CipherSpi</code>.
+ * and a generic <i>AES</i> class that subclasses from <code>CipherSpi</code>.
  * That provider would have the following
  * <code>Cipher</code> properties in its master class:
  *
@@ -166,7 +166,7 @@
  *
  * <li>
  * <pre>
- *     <code>Cipher.</code><i>DES</i>
+ *     <code>Cipher.</code><i>AES</i>
  * </pre>
  *
  * </ul>
--- a/src/java.base/share/classes/javax/crypto/Mac.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/javax/crypto/Mac.java	Mon Aug 07 09:45:38 2017 -0700
@@ -50,7 +50,7 @@
  *
  * <p> A MAC mechanism that is based on cryptographic hash functions is
  * referred to as HMAC. HMAC can be used with any cryptographic hash function,
- * e.g., MD5 or SHA-1, in combination with a secret shared key. HMAC is
+ * e.g., SHA256 or SHA384, in combination with a secret shared key. HMAC is
  * specified in RFC 2104.
  *
  * <p> Every implementation of the Java platform is required to support
--- a/src/java.base/share/classes/javax/crypto/SealedObject.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/javax/crypto/SealedObject.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -40,7 +40,7 @@
  * <p> Given any Serializable object, one can create a SealedObject
  * that encapsulates the original object, in serialized
  * format (i.e., a "deep copy"), and seals (encrypts) its serialized contents,
- * using a cryptographic algorithm such as DES, to protect its
+ * using a cryptographic algorithm such as AES, to protect its
  * confidentiality.  The encrypted content can later be decrypted (with
  * the corresponding algorithm using the correct decryption key) and
  * de-serialized, yielding the original object.
--- a/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Mon Aug 07 09:45:38 2017 -0700
@@ -55,13 +55,13 @@
 import java.util.NoSuchElementException;
 import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
 import java.util.jar.Attributes;
 import java.util.jar.Manifest;
 import java.util.stream.Stream;
 
 import jdk.internal.misc.VM;
 import jdk.internal.module.ModulePatcher.PatchedModuleReader;
-import jdk.internal.module.SystemModules;
 import jdk.internal.module.Resources;
 
 
@@ -139,7 +139,7 @@
 
     // maps package name to loaded module for modules in the boot layer
     private static final Map<String, LoadedModule> packageToModule
-        = new ConcurrentHashMap<>(SystemModules.PACKAGES_IN_BOOT_LAYER);
+        = new ConcurrentHashMap<>(1024);
 
     // maps a module name to a module reference
     private final Map<String, ModuleReference> nameToModule;
@@ -946,9 +946,16 @@
         URL url = cs.getLocation();
         if (url == null)
             return perms;
-        Permission p = null;
+
+        // avoid opening connection when URL is to resource in run-time image
+        if (url.getProtocol().equals("jrt")) {
+            perms.add(new RuntimePermission("accessSystemModules"));
+            return perms;
+        }
+
+        // open connection to determine the permission needed
         try {
-            p = url.openConnection().getPermission();
+            Permission p = url.openConnection().getPermission();
             if (p != null) {
                 // for directories then need recursive access
                 if (p instanceof FilePermission) {
@@ -969,23 +976,26 @@
     // -- miscellaneous supporting methods
 
     /**
-     * Returns the ModuleReader for the given module.
+     * Returns the ModuleReader for the given module, creating it if needed
      */
     private ModuleReader moduleReaderFor(ModuleReference mref) {
-        return moduleToReader.computeIfAbsent(mref, BuiltinClassLoader::createModuleReader);
-    }
-
-    /**
-     * Creates a ModuleReader for the given module.
-     */
-    private static ModuleReader createModuleReader(ModuleReference mref) {
-        try {
-            return mref.open();
-        } catch (IOException e) {
-            // Return a null module reader to avoid a future class load
-            // attempting to open the module again.
-            return new NullModuleReader();
+        ModuleReader reader = moduleToReader.get(mref);
+        if (reader == null) {
+            // avoid method reference during startup
+            Function<ModuleReference, ModuleReader> create = new Function<>() {
+                public ModuleReader apply(ModuleReference moduleReference) {
+                    try {
+                        return mref.open();
+                    } catch (IOException e) {
+                        // Return a null module reader to avoid a future class
+                        // load attempting to open the module again.
+                        return new NullModuleReader();
+                    }
+                }
+            };
+            reader = moduleToReader.computeIfAbsent(mref, create);
         }
+        return reader;
     }
 
     /**
--- a/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java	Mon Aug 07 09:45:38 2017 -0700
@@ -25,7 +25,6 @@
 
 package jdk.internal.loader;
 
-import java.io.File;
 import java.io.IOException;
 import java.net.URL;
 import java.nio.file.InvalidPathException;
@@ -38,7 +37,6 @@
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
 
-
 /**
  * Creates and provides access to the built-in platform and application class
  * loaders. It also creates the class loader that is used to locate resources
@@ -61,23 +59,30 @@
      */
     static {
 
-        // -Xbootclasspth/a or -javaagent Boot-Class-Path
+        // -Xbootclasspath/a or -javaagent with Boot-Class-Path attribute
         URLClassPath bcp = null;
         String s = VM.getSavedProperty("jdk.boot.class.path.append");
         if (s != null && s.length() > 0)
-            bcp = toURLClassPath(s);
+            bcp = new URLClassPath(s, true);
 
         // we have a class path if -cp is specified or -m is not specified.
         // If neither is specified then default to -cp <working directory>
         // If -cp is not specified and -m is specified, the value of
         // java.class.path is an empty string, then no class path.
-        URLClassPath ucp = new URLClassPath(new URL[0]);
         String mainMid = System.getProperty("jdk.module.main");
         String cp = System.getProperty("java.class.path");
-        if (cp == null)
-            cp = "";
-        if (mainMid == null || cp.length() > 0)
-            addClassPathToUCP(cp, ucp);
+        if (mainMid == null) {
+            // no main module specified so class path required
+            if (cp == null) {
+                cp = "";
+            }
+        } else {
+            // main module specified, ignore empty class path
+            if (cp != null && cp.length() == 0) {
+                cp = null;
+            }
+        }
+        URLClassPath ucp = new URLClassPath(cp, false);
 
         // create the class loaders
         BOOT_LOADER = new BootClassLoader(bcp);
@@ -198,7 +203,7 @@
          * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
          */
         void appendToClassPathForInstrumentation(String path) {
-            addClassPathToUCP(path, ucp);
+            ucp.addFile(path);
         }
 
         /**
@@ -220,40 +225,11 @@
     }
 
     /**
-     * Returns a {@code URLClassPath} of file URLs to each of the elements in
-     * the given class path.
-     */
-    private static URLClassPath toURLClassPath(String cp) {
-        URLClassPath ucp = new URLClassPath(new URL[0]);
-        addClassPathToUCP(cp, ucp);
-        return ucp;
-    }
-
-    /**
-     * Converts the elements in the given class path to file URLs and adds
-     * them to the given URLClassPath.
-     */
-    private static void addClassPathToUCP(String cp, URLClassPath ucp) {
-        int off = 0;
-        int next;
-        while ((next = cp.indexOf(File.pathSeparator, off)) != -1) {
-            URL url = toFileURL(cp.substring(off, next));
-            if (url != null)
-                ucp.addURL(url);
-            off = next + 1;
-        }
-
-        // remaining
-        URL url = toFileURL(cp.substring(off));
-        if (url != null)
-            ucp.addURL(url);
-    }
-
-    /**
      * Attempts to convert the given string to a file URL.
      *
      * @apiNote This is called by the VM
      */
+    @Deprecated
     private static URL toFileURL(String s) {
         try {
             // Use an intermediate File object to construct a URI/URL without
@@ -265,5 +241,4 @@
             return null;
         }
     }
-
 }
--- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java	Mon Aug 07 09:45:38 2017 -0700
@@ -46,6 +46,7 @@
 import java.security.PrivilegedExceptionAction;
 import java.security.cert.Certificate;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -66,7 +67,6 @@
 import java.util.zip.ZipFile;
 
 import jdk.internal.misc.JavaNetURLAccess;
-import jdk.internal.misc.JavaNetURLClassLoaderAccess;
 import jdk.internal.misc.JavaUtilZipFileAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.util.jar.InvalidJarIndexError;
@@ -100,19 +100,19 @@
     }
 
     /* The original search path of URLs. */
-    private ArrayList<URL> path = new ArrayList<>();
+    private final List<URL> path;
 
     /* The stack of unopened URLs */
-    Stack<URL> urls = new Stack<>();
+    private final Stack<URL> urls = new Stack<>();
 
     /* The resulting search path of Loaders */
-    ArrayList<Loader> loaders = new ArrayList<>();
+    private final ArrayList<Loader> loaders = new ArrayList<>();
 
     /* Map of each URL opened to its corresponding Loader */
-    HashMap<String, Loader> lmap = new HashMap<>();
+    private final HashMap<String, Loader> lmap = new HashMap<>();
 
     /* The jar protocol handler to use when creating new URLs */
-    private URLStreamHandler jarHandler;
+    private final URLStreamHandler jarHandler;
 
     /* Whether this URLClassLoader has been closed yet */
     private boolean closed = false;
@@ -137,12 +137,16 @@
     public URLClassPath(URL[] urls,
                         URLStreamHandlerFactory factory,
                         AccessControlContext acc) {
-        for (int i = 0; i < urls.length; i++) {
-            path.add(urls[i]);
+        List<URL> path = new ArrayList<>(urls.length);
+        for (URL url : urls) {
+            path.add(url);
         }
+        this.path = path;
         push(urls);
         if (factory != null) {
             jarHandler = factory.createURLStreamHandler("jar");
+        } else {
+            jarHandler = null;
         }
         if (DISABLE_ACC_CHECKING)
             this.acc = null;
@@ -150,16 +154,50 @@
             this.acc = acc;
     }
 
-    /**
-     * Constructs a URLClassPath with no additional security restrictions.
-     * Used by code that implements the class path.
-     */
-    public URLClassPath(URL[] urls) {
-        this(urls, null, null);
+    public URLClassPath(URL[] urls, AccessControlContext acc) {
+        this(urls, null, acc);
     }
 
-    public URLClassPath(URL[] urls, AccessControlContext acc) {
-        this(urls, null, acc);
+    /**
+     * Constructs a URLClassPath from a class path string.
+     *
+     * @param cp the class path string
+     * @param skipEmptyElements indicates if empty elements are ignored or
+     *        treated as the current working directory
+     *
+     * @apiNote Used to create the application class path.
+     */
+    URLClassPath(String cp, boolean skipEmptyElements) {
+        List<URL> path = new ArrayList<>();
+        if (cp != null) {
+            // map each element of class path to a file URL
+            int off = 0;
+            int next;
+            while ((next = cp.indexOf(File.pathSeparator, off)) != -1) {
+                String element = cp.substring(off, next);
+                if (element.length() > 0 || !skipEmptyElements) {
+                    URL url = toFileURL(element);
+                    if (url != null) path.add(url);
+                }
+                off = next + 1;
+            }
+
+            // remaining element
+            String element = cp.substring(off);
+            if (element.length() > 0 || !skipEmptyElements) {
+                URL url = toFileURL(element);
+                if (url != null) path.add(url);
+            }
+
+            // push the URLs
+            for (int i = path.size() - 1; i >= 0; --i) {
+                urls.push(path.get(i));
+            }
+        }
+
+        this.path = path;
+        this.jarHandler = null;
+        this.acc = null;
     }
 
     public synchronized List<IOException> closeLoaders() {
@@ -198,6 +236,28 @@
     }
 
     /**
+     * Appends the specified file path as a file URL to the search path.
+     */
+    public void addFile(String s) {
+        URL url = toFileURL(s);
+        if (url != null) {
+            addURL(url);
+        }
+    }
+
+    /**
+     * Returns a file URL for the given file path.
+     */
+    private static URL toFileURL(String s) {
+        try {
+            File f = new File(s).getCanonicalFile();
+            return ParseUtil.fileToEncodedURL(f);
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
      * Returns the original search path of URLs.
      */
     public URL[] getURLs() {
--- a/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/logger/DefaultLoggerFinder.java	Mon Aug 07 09:45:38 2017 -0700
@@ -25,6 +25,8 @@
 
 package jdk.internal.logger;
 
+import jdk.internal.misc.VM;
+
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import java.util.HashMap;
@@ -140,15 +142,9 @@
         return AccessController.doPrivileged(new PrivilegedAction<>() {
             @Override
             public Boolean run() {
-                final ClassLoader moduleCL = m.getClassLoader();
-                if (moduleCL == null) return true;
-                ClassLoader cl = ClassLoader.getPlatformClassLoader();
-                while (cl != null && moduleCL != cl) {
-                    cl = cl.getParent();
-                }
                 // returns true if moduleCL is the platform class loader
                 // or one of its ancestors.
-                return moduleCL == cl;
+                return VM.isSystemDomainLoader(m.getClassLoader());
             }
         });
     }
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Mon Aug 07 09:45:38 2017 -0700
@@ -34,16 +34,10 @@
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Version;
 import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReader;
-import java.lang.module.ModuleReference;
-import java.net.URI;
-import java.nio.file.Path;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
-import java.util.function.Supplier;
-
-import jdk.internal.module.ModuleHashes;
 
 /**
  * Provides access to non-public methods in java.lang.module.
@@ -131,12 +125,16 @@
 
     /**
      * Resolves a collection of root modules, with service binding
-     * and the empty configuration as the parent. The post resolution
-     * checks are optionally run.
+     * and the empty configuration as the parent.
      */
     Configuration resolveAndBind(ModuleFinder finder,
                                  Collection<String> roots,
-                                 boolean check,
                                  PrintStream traceOutput);
 
+    /**
+     * Creates a configuration from a pre-generated readability graph.
+     */
+    Configuration newConfiguration(ModuleFinder finder,
+                                   Map<String, Set<String>> graph);
+
 }
--- a/src/java.base/share/classes/jdk/internal/misc/VM.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/misc/VM.java	Mon Aug 07 09:45:38 2017 -0700
@@ -124,11 +124,11 @@
     }
 
     /**
-     * Returns true if the given class loader is in the system domain
-     * in which all permissions are granted.
+     * Returns true if the given class loader is the bootstrap class loader
+     * or the platform class loader.
      */
     public static boolean isSystemDomainLoader(ClassLoader loader) {
-        return loader == null;
+        return loader == null || loader == ClassLoader.getPlatformClassLoader();
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/DefaultRoots.java	Mon Aug 07 09:45:38 2017 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Defines methods to compute the default set of root modules for the unnamed
+ * module.
+ */
+
+public final class DefaultRoots {
+    private static final String JAVA_SE = "java.se";
+
+    private DefaultRoots() { }
+
+    /**
+     * Returns the default set of root modules for the unnamed module computed from
+     * the system modules observable with the given module finder.
+     */
+    static Set<String> compute(ModuleFinder systemModuleFinder, ModuleFinder finder) {
+        Set<String> roots = new HashSet<>();
+
+        boolean hasJava = false;
+        if (systemModuleFinder.find(JAVA_SE).isPresent()) {
+            if (finder == systemModuleFinder || finder.find(JAVA_SE).isPresent()) {
+                // java.se is a system module
+                hasJava = true;
+                roots.add(JAVA_SE);
+            }
+        }
+
+        for (ModuleReference mref : systemModuleFinder.findAll()) {
+            String mn = mref.descriptor().name();
+            if (hasJava && mn.startsWith("java.")) {
+                // not a root
+                continue;
+            }
+
+            if (ModuleResolution.doNotResolveByDefault(mref)) {
+                // not a root
+                continue;
+            }
+
+            if ((finder == systemModuleFinder || finder.find(mn).isPresent())) {
+                // add as root if exports at least one package to all modules
+                ModuleDescriptor descriptor = mref.descriptor();
+                for (ModuleDescriptor.Exports e : descriptor.exports()) {
+                    if (!e.isQualified()) {
+                        roots.add(mn);
+                        break;
+                    }
+                }
+            }
+        }
+
+        return roots;
+    }
+
+    /**
+     * Returns the default set of root modules for the unnamed module from the
+     * modules observable with the given module finder.
+     */
+    public static Set<String> compute(ModuleFinder finder) {
+        return compute(finder, finder);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ExplodedSystemModules.java	Mon Aug 07 09:45:38 2017 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.lang.module.ModuleDescriptor;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A dummy SystemModules for use with exploded builds or testing.
+ */
+
+class ExplodedSystemModules implements SystemModules {
+    @Override
+    public boolean hasSplitPackages() {
+        return true;  // not known
+    }
+
+    @Override
+    public boolean hasIncubatorModules() {
+        return true;  // not known
+    }
+
+    @Override
+    public ModuleDescriptor[] moduleDescriptors() {
+        throw new InternalError();
+    }
+
+    @Override
+    public ModuleTarget[] moduleTargets() {
+        throw new InternalError();
+    }
+
+    @Override
+    public ModuleHashes[] moduleHashes() {
+        throw new InternalError();
+    }
+
+    @Override
+    public ModuleResolution[] moduleResolutions() {
+        throw new InternalError();
+    }
+
+    @Override
+    public Map<String, Set<String>> moduleReads() {
+        throw new InternalError();
+    }
+
+    @Override
+    public  Map<String, Set<String>> concealedPackagesToOpen() {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public  Map<String, Set<String>> exportedPackagesToOpen() {
+        return Collections.emptyMap();
+    }
+}
--- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Mon Aug 07 09:45:38 2017 -0700
@@ -40,16 +40,20 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;
 import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.perf.PerfCounter;
 
@@ -70,8 +74,6 @@
 
     private static final String JAVA_BASE = "java.base";
 
-    private static final String JAVA_SE = "java.se";
-
     // the token for "all default modules"
     private static final String ALL_DEFAULT = "ALL-DEFAULT";
 
@@ -84,13 +86,13 @@
     // the token for "all modules on the module path"
     private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
 
+    // access to java.lang/module
+    private static final JavaLangModuleAccess JLMA
+        = SharedSecrets.getJavaLangModuleAccess();
+
     // The ModulePatcher for the initial configuration
     private static final ModulePatcher patcher = initModulePatcher();
 
-    // ModuleFinders for the initial configuration
-    private static ModuleFinder unlimitedFinder;
-    private static ModuleFinder limitedFinder;
-
     /**
      * Returns the ModulePatcher for the initial configuration.
      */
@@ -98,21 +100,38 @@
         return patcher;
     }
 
+    // ModuleFinders for the initial configuration
+    private static volatile ModuleFinder unlimitedFinder;
+    private static volatile ModuleFinder limitedFinder;
+
     /**
-     * Returns the ModuleFinder for the initial configuration before observability
-     * is limited by the --limit-modules command line option.
+     * Returns the ModuleFinder for the initial configuration before
+     * observability is limited by the --limit-modules command line option.
+     *
+     * @apiNote Used to support locating modules {@code java.instrument} and
+     * {@code jdk.management.agent} modules when they are loaded dynamically.
      */
     public static ModuleFinder unlimitedFinder() {
-        assert unlimitedFinder != null;
-        return unlimitedFinder;
+        ModuleFinder finder = unlimitedFinder;
+        if (finder == null) {
+            return ModuleFinder.ofSystem();
+        } else {
+            return finder;
+        }
     }
 
     /**
      * Returns the ModuleFinder for the initial configuration.
+     *
+     * @apiNote Used to support "{@code java --list-modules}".
      */
     public static ModuleFinder limitedFinder() {
-        assert limitedFinder != null;
-        return limitedFinder;
+        ModuleFinder finder = limitedFinder;
+        if (finder == null) {
+            return unlimitedFinder();
+        } else {
+            return finder;
+        }
     }
 
     /**
@@ -120,13 +139,60 @@
      *
      * @see java.lang.System#initPhase2()
      */
-    public static ModuleLayer boot() {
+    public static ModuleLayer boot() throws Exception {
 
-        // Step 1: Locate system modules (may be patched)
+        // Step 0: Command line options
+
+        long t0 = System.nanoTime();
+
+        ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path");
+        ModuleFinder appModulePath = finderFor("jdk.module.path");
+        boolean isPatched = patcher.hasPatches();
+
+        String mainModule = System.getProperty("jdk.module.main");
+        Set<String> addModules = addModules();
+        Set<String> limitModules = limitModules();
+
+        PrintStream traceOutput = null;
+        String trace = getAndRemoveProperty("jdk.module.showModuleResolution");
+        if (trace != null && Boolean.parseBoolean(trace))
+            traceOutput = System.out;
+
+
+        // Step 1: The observable system modules, either all system modules
+        // or the system modules pre-generated for the initial module (the
+        // initial module may be the unnamed module). If the system modules
+        // are pre-generated for the initial module then resolution can be
+        // skipped.
 
         long t1 = System.nanoTime();
-        ModuleFinder systemModules = ModuleFinder.ofSystem();
-        PerfCounters.systemModulesTime.addElapsedTimeFrom(t1);
+
+        SystemModules systemModules = null;
+        ModuleFinder systemModuleFinder;
+
+        boolean haveModulePath = (appModulePath != null || upgradeModulePath != null);
+        boolean needResolution = true;
+
+        if (!haveModulePath && addModules.isEmpty() && limitModules.isEmpty()) {
+            systemModules = SystemModuleFinders.systemModules(mainModule);
+            if (systemModules != null && !isPatched && (traceOutput == null)) {
+                needResolution = false;
+            }
+        }
+        if (systemModules == null) {
+            // all system modules are observable
+            systemModules = SystemModuleFinders.allSystemModules();
+        }
+        if (systemModules != null) {
+            // images build
+            systemModuleFinder = SystemModuleFinders.of(systemModules);
+        } else {
+            // exploded build or testing
+            systemModules = new ExplodedSystemModules();
+            systemModuleFinder = SystemModuleFinders.ofSystem();
+        }
+
+        Counters.add("jdk.module.boot.1.systemModulesTime", t1);
 
 
         // Step 2: Define and load java.base. This patches all classes loaded
@@ -136,7 +202,7 @@
 
         long t2 = System.nanoTime();
 
-        ModuleReference base = systemModules.find(JAVA_BASE).orElse(null);
+        ModuleReference base = systemModuleFinder.find(JAVA_BASE).orElse(null);
         if (base == null)
             throw new InternalError(JAVA_BASE + " not found");
         URI baseUri = base.location().orElse(null);
@@ -145,171 +211,138 @@
         BootLoader.loadModule(base);
         Modules.defineModule(null, base.descriptor(), baseUri);
 
-        PerfCounters.defineBaseTime.addElapsedTimeFrom(t2);
+        Counters.add("jdk.module.boot.2.defineBaseTime", t2);
 
 
         // Step 2a: If --validate-modules is specified then the VM needs to
         // start with only java.base, all other options are ignored.
 
-        String propValue = getAndRemoveProperty("jdk.module.minimumBoot");
-        if (propValue != null) {
+        if (getAndRemoveProperty("jdk.module.minimumBoot") != null) {
             return createMinimalBootLayer();
         }
 
 
-        // Step 3: Construct the module path and the set of root modules to
-        // resolve. If --limit-modules is specified then it limits the set
-        // modules that are observable.
+        // Step 3: If resolution is needed then create the module finder and
+        // the set of root modules to resolve.
 
         long t3 = System.nanoTime();
 
-        // --upgrade-module-path option specified to launcher
-        ModuleFinder upgradeModulePath
-            = createModulePathFinder("jdk.module.upgrade.path");
-        if (upgradeModulePath != null)
-            systemModules = ModuleFinder.compose(upgradeModulePath, systemModules);
+        ModuleFinder savedModuleFinder = null;
+        ModuleFinder finder;
+        Set<String> roots;
+        if (needResolution) {
 
-        // --module-path option specified to the launcher
-        ModuleFinder appModulePath = createModulePathFinder("jdk.module.path");
+            // upgraded modules override the modules in the run-time image
+            if (upgradeModulePath != null)
+                systemModuleFinder = ModuleFinder.compose(upgradeModulePath,
+                                                          systemModuleFinder);
 
-        // The module finder: [--upgrade-module-path] system [--module-path]
-        ModuleFinder finder = systemModules;
-        if (appModulePath != null)
-            finder = ModuleFinder.compose(finder, appModulePath);
+            // The module finder: [--upgrade-module-path] system [--module-path]
+            if (appModulePath != null) {
+                finder = ModuleFinder.compose(systemModuleFinder, appModulePath);
+            } else {
+                finder = systemModuleFinder;
+            }
 
-        // The root modules to resolve
-        Set<String> roots = new HashSet<>();
+            // The root modules to resolve
+            roots = new HashSet<>();
 
-        // launcher -m option to specify the main/initial module
-        String mainModule = System.getProperty("jdk.module.main");
-        if (mainModule != null)
-            roots.add(mainModule);
+            // launcher -m option to specify the main/initial module
+            if (mainModule != null)
+                roots.add(mainModule);
 
-        // additional module(s) specified by --add-modules
-        boolean addAllDefaultModules = false;
-        boolean addAllSystemModules = false;
-        boolean addAllApplicationModules = false;
-        for (String mod: getExtraAddModules()) {
-            switch (mod) {
-                case ALL_DEFAULT:
-                    addAllDefaultModules = true;
-                    break;
-                case ALL_SYSTEM:
-                    addAllSystemModules = true;
-                    break;
-                case ALL_MODULE_PATH:
-                    addAllApplicationModules = true;
-                    break;
-                default :
-                    roots.add(mod);
-            }
-        }
-
-        // --limit-modules
-        unlimitedFinder = finder;
-        propValue = getAndRemoveProperty("jdk.module.limitmods");
-        if (propValue != null) {
-            Set<String> mods = new HashSet<>();
-            for (String mod: propValue.split(",")) {
-                mods.add(mod);
-            }
-            finder = limitFinder(finder, mods, roots);
-        }
-        limitedFinder = finder;
-
-        // If there is no initial module specified then assume that the initial
-        // module is the unnamed module of the application class loader. This
-        // is implemented by resolving "java.se" and all (non-java.*) modules
-        // that export an API. If "java.se" is not observable then all java.*
-        // modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
-        // bit set in their ModuleResolution attribute flags are excluded from
-        // the default set of roots.
-        if (mainModule == null || addAllDefaultModules) {
-            boolean hasJava = false;
-            if (systemModules.find(JAVA_SE).isPresent()) {
-                // java.se is a system module
-                if (finder == systemModules || finder.find(JAVA_SE).isPresent()) {
-                    // java.se is observable
-                    hasJava = true;
-                    roots.add(JAVA_SE);
+            // additional module(s) specified by --add-modules
+            boolean addAllDefaultModules = false;
+            boolean addAllSystemModules = false;
+            boolean addAllApplicationModules = false;
+            for (String mod : addModules) {
+                switch (mod) {
+                    case ALL_DEFAULT:
+                        addAllDefaultModules = true;
+                        break;
+                    case ALL_SYSTEM:
+                        addAllSystemModules = true;
+                        break;
+                    case ALL_MODULE_PATH:
+                        addAllApplicationModules = true;
+                        break;
+                    default:
+                        roots.add(mod);
                 }
             }
 
-            for (ModuleReference mref : systemModules.findAll()) {
-                String mn = mref.descriptor().name();
-                if (hasJava && mn.startsWith("java."))
-                    continue;
+            // --limit-modules
+            savedModuleFinder = finder;
+            if (!limitModules.isEmpty()) {
+                finder = limitFinder(finder, limitModules, roots);
+            }
 
-                if (ModuleResolution.doNotResolveByDefault(mref))
-                    continue;
+            // If there is no initial module specified then assume that the initial
+            // module is the unnamed module of the application class loader. This
+            // is implemented by resolving "java.se" and all (non-java.*) modules
+            // that export an API. If "java.se" is not observable then all java.*
+            // modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
+            // bit set in their ModuleResolution attribute flags are excluded from
+            // the default set of roots.
+            if (mainModule == null || addAllDefaultModules) {
+                roots.addAll(DefaultRoots.compute(systemModuleFinder, finder));
+            }
 
-                // add as root if observable and exports at least one package
-                if ((finder == systemModules || finder.find(mn).isPresent())) {
-                    ModuleDescriptor descriptor = mref.descriptor();
-                    for (ModuleDescriptor.Exports e : descriptor.exports()) {
-                        if (!e.isQualified()) {
-                            roots.add(mn);
-                            break;
-                        }
-                    }
-                }
+            // If `--add-modules ALL-SYSTEM` is specified then all observable system
+            // modules will be resolved.
+            if (addAllSystemModules) {
+                ModuleFinder f = finder;  // observable modules
+                systemModuleFinder.findAll()
+                    .stream()
+                    .map(ModuleReference::descriptor)
+                    .map(ModuleDescriptor::name)
+                    .filter(mn -> f.find(mn).isPresent())  // observable
+                    .forEach(mn -> roots.add(mn));
             }
+
+            // If `--add-modules ALL-MODULE-PATH` is specified then all observable
+            // modules on the application module path will be resolved.
+            if (appModulePath != null && addAllApplicationModules) {
+                ModuleFinder f = finder;  // observable modules
+                appModulePath.findAll()
+                    .stream()
+                    .map(ModuleReference::descriptor)
+                    .map(ModuleDescriptor::name)
+                    .filter(mn -> f.find(mn).isPresent())  // observable
+                    .forEach(mn -> roots.add(mn));
+            }
+        } else {
+            // no resolution case
+            finder = systemModuleFinder;
+            roots = null;
         }
 
-        // If `--add-modules ALL-SYSTEM` is specified then all observable system
-        // modules will be resolved.
-        if (addAllSystemModules) {
-            ModuleFinder f = finder;  // observable modules
-            systemModules.findAll()
-                .stream()
-                .map(ModuleReference::descriptor)
-                .map(ModuleDescriptor::name)
-                .filter(mn -> f.find(mn).isPresent())  // observable
-                .forEach(mn -> roots.add(mn));
-        }
-
-        // If `--add-modules ALL-MODULE-PATH` is specified then all observable
-        // modules on the application module path will be resolved.
-        if (appModulePath != null && addAllApplicationModules) {
-            ModuleFinder f = finder;  // observable modules
-            appModulePath.findAll()
-                .stream()
-                .map(ModuleReference::descriptor)
-                .map(ModuleDescriptor::name)
-                .filter(mn -> f.find(mn).isPresent())  // observable
-                .forEach(mn -> roots.add(mn));
-        }
-
-        PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t3);
-
+        Counters.add("jdk.module.boot.3.optionsAndRootsTime", t3);
 
         // Step 4: Resolve the root modules, with service binding, to create
-        // the configuration for the boot layer.
+        // the configuration for the boot layer. If resolution is not needed
+        // then create the configuration for the boot layer from the
+        // readability graph created at link time.
 
         long t4 = System.nanoTime();
 
-        // determine if post resolution checks are needed
-        boolean needPostResolutionChecks = true;
-        if (baseUri.getScheme().equals("jrt")   // toLowerCase not needed here
-                && (upgradeModulePath == null)
-                && (appModulePath == null)
-                && (patcher.isEmpty())) {
-            needPostResolutionChecks = false;
+        Configuration cf;
+        if (needResolution) {
+            cf = JLMA.resolveAndBind(finder, roots, traceOutput);
+        } else {
+            Map<String, Set<String>> map = systemModules.moduleReads();
+            cf = JLMA.newConfiguration(systemModuleFinder, map);
         }
 
-        PrintStream traceOutput = null;
-        propValue = getAndRemoveProperty("jdk.module.showModuleResolution");
-        if (propValue != null && Boolean.parseBoolean(propValue))
-            traceOutput = System.out;
+        // check that modules specified to --patch-module are resolved
+        if (isPatched) {
+            patcher.patchedModules()
+                    .stream()
+                    .filter(mn -> !cf.findModule(mn).isPresent())
+                    .forEach(mn -> warnUnknownModule(PATCH_MODULE, mn));
+        }
 
-        // run the resolver to create the configuration
-        Configuration cf = SharedSecrets.getJavaLangModuleAccess()
-                .resolveAndBind(finder,
-                                roots,
-                                needPostResolutionChecks,
-                                traceOutput);
-
-        PerfCounters.resolveTime.addElapsedTimeFrom(t4);
+        Counters.add("jdk.module.boot.4.resolveTime", t4);
 
 
         // Step 5: Map the modules in the configuration to class loaders.
@@ -326,7 +359,7 @@
 
         // check that all modules to be mapped to the boot loader will be
         // loaded from the runtime image
-        if (needPostResolutionChecks) {
+        if (haveModulePath) {
             for (ResolvedModule resolvedModule : cf.modules()) {
                 ModuleReference mref = resolvedModule.reference();
                 String name = mref.descriptor().name();
@@ -335,51 +368,54 @@
                     if (upgradeModulePath != null
                             && upgradeModulePath.find(name).isPresent())
                         fail(name + ": cannot be loaded from upgrade module path");
-                    if (!systemModules.find(name).isPresent())
+                    if (!systemModuleFinder.find(name).isPresent())
                         fail(name + ": cannot be loaded from application module path");
                 }
             }
-
-            // check if module specified in --patch-module is present
-            for (String mn: patcher.patchedModules()) {
-                if (!cf.findModule(mn).isPresent()) {
-                    warnUnknownModule(PATCH_MODULE, mn);
-                }
-            }
         }
 
         // check for split packages in the modules mapped to the built-in loaders
-        if (SystemModules.hasSplitPackages() || needPostResolutionChecks) {
+        if (systemModules.hasSplitPackages() || isPatched || haveModulePath) {
             checkSplitPackages(cf, clf);
         }
 
         // load/register the modules with the built-in class loaders
         loadModules(cf, clf);
 
-        PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
+        Counters.add("jdk.module.boot.5.loadModulesTime", t5);
 
 
         // Step 6: Define all modules to the VM
 
         long t6 = System.nanoTime();
         ModuleLayer bootLayer = ModuleLayer.empty().defineModules(cf, clf);
-        PerfCounters.layerCreateTime.addElapsedTimeFrom(t6);
+        Counters.add("jdk.module.boot.6.layerCreateTime", t6);
 
 
         // Step 7: Miscellaneous
 
         // check incubating status
-        checkIncubatingStatus(cf);
+        if (systemModules.hasIncubatorModules() || haveModulePath) {
+            checkIncubatingStatus(cf);
+        }
 
-        // --add-reads, --add-exports/--add-opens, and -illegal-access
+        // --add-reads, --add-exports/--add-opens, and --illegal-access
         long t7 = System.nanoTime();
         addExtraReads(bootLayer);
         boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer);
-        addIllegalAccess(bootLayer, upgradeModulePath, extraExportsOrOpens);
-        PerfCounters.adjustModulesTime.addElapsedTimeFrom(t7);
+        addIllegalAccess(upgradeModulePath, systemModules, bootLayer, extraExportsOrOpens);
+        Counters.add("jdk.module.boot.7.adjustModulesTime", t7);
+
+        // save module finders for later use
+        if (savedModuleFinder != null) {
+            unlimitedFinder = new SafeModuleFinder(savedModuleFinder);
+            if (savedModuleFinder != finder)
+                limitedFinder = new SafeModuleFinder(finder);
+        }
 
         // total time to initialize
-        PerfCounters.bootstrapTime.addElapsedTimeFrom(t1);
+        Counters.add("jdk.module.boot.totalTime", t0);
+        Counters.publish();
 
         return bootLayer;
     }
@@ -391,7 +427,6 @@
         Configuration cf = SharedSecrets.getJavaLangModuleAccess()
             .resolveAndBind(ModuleFinder.ofSystem(),
                             Set.of(JAVA_BASE),
-                            false,
                             null);
 
         Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
@@ -439,7 +474,6 @@
                     }
                 }
             }
-
         }
     }
 
@@ -489,7 +523,7 @@
      * Creates a finder from the module path that is the value of the given
      * system property and optionally patched by --patch-module
      */
-    private static ModuleFinder createModulePathFinder(String prop) {
+    private static ModuleFinder finderFor(String prop) {
         String s = System.getProperty(prop);
         if (s == null) {
             return null;
@@ -510,35 +544,48 @@
      */
     private static ModulePatcher initModulePatcher() {
         Map<String, List<String>> map = decode("jdk.module.patch.",
-                File.pathSeparator,
-                false);
+                                               File.pathSeparator,
+                                               false);
         return new ModulePatcher(map);
     }
 
     /**
-     * Returns the set of module names specified via --add-modules options
-     * on the command line
+     * Returns the set of module names specified by --add-module options.
      */
-    private static Set<String> getExtraAddModules() {
+    private static Set<String> addModules() {
         String prefix = "jdk.module.addmods.";
         int index = 0;
-
         // the system property is removed after decoding
         String value = getAndRemoveProperty(prefix + index);
         if (value == null) {
             return Collections.emptySet();
+        } else {
+            Set<String> modules = new HashSet<>();
+            while (value != null) {
+                for (String s : value.split(",")) {
+                    if (s.length() > 0) modules.add(s);
+                }
+                index++;
+                value = getAndRemoveProperty(prefix + index);
+            }
+            return modules;
         }
+    }
 
-        Set<String> modules = new HashSet<>();
-        while (value != null) {
-            for (String s : value.split(",")) {
-                if (s.length() > 0) modules.add(s);
+    /**
+     * Returns the set of module names specified by --limit-modules.
+     */
+    private static Set<String> limitModules() {
+        String value = getAndRemoveProperty("jdk.module.limitmods");
+        if (value == null) {
+            return Collections.emptySet();
+        } else {
+            Set<String> names = new HashSet<>();
+            for (String name : value.split(",")) {
+                if (name.length() > 0) names.add(name);
             }
-            index++;
-            value = getAndRemoveProperty(prefix + index);
+            return names;
         }
-
-        return modules;
     }
 
     /**
@@ -676,8 +723,9 @@
      * Process the --illegal-access option (and its default) to open packages
      * of system modules in the boot layer to code in unnamed modules.
      */
-    private static void addIllegalAccess(ModuleLayer bootLayer,
-                                         ModuleFinder upgradeModulePath,
+    private static void addIllegalAccess(ModuleFinder upgradeModulePath,
+                                         SystemModules systemModules,
+                                         ModuleLayer bootLayer,
                                          boolean extraExportsOrOpens) {
         String value = getAndRemoveProperty("jdk.module.illegalAccess");
         IllegalAccessLogger.Mode mode = IllegalAccessLogger.Mode.ONESHOT;
@@ -702,10 +750,10 @@
         IllegalAccessLogger.Builder builder
             = new IllegalAccessLogger.Builder(mode, System.err);
 
-        Map<String, Set<String>> map1 = SystemModules.concealedPackagesToOpen();
-        Map<String, Set<String>> map2 = SystemModules.exportedPackagesToOpen();
+        Map<String, Set<String>> map1 = systemModules.concealedPackagesToOpen();
+        Map<String, Set<String>> map2 = systemModules.exportedPackagesToOpen();
         if (map1.isEmpty() && map2.isEmpty()) {
-            // need to generate maps when on exploded build
+            // need to generate (exploded build)
             IllegalAccessMaps maps = IllegalAccessMaps.generate(limitedFinder());
             map1 = maps.concealedPackagesToOpen();
             map2 = maps.exportedPackagesToOpen();
@@ -906,6 +954,10 @@
         }
     }
 
+    /**
+     * Returns an iterator that yields all elements of the first iterator
+     * followed by all the elements of the second iterator.
+     */
     static <T> Iterator<T> concat(Iterator<T> iterator1, Iterator<T> iterator2) {
         return new Iterator<T>() {
             @Override
@@ -921,23 +973,76 @@
         };
     }
 
-    static class PerfCounters {
+    /**
+     * Wraps a (potentially not thread safe) ModuleFinder created during startup
+     * for use after startup.
+     */
+    static class SafeModuleFinder implements ModuleFinder {
+        private final Set<ModuleReference> mrefs;
+        private volatile Map<String, ModuleReference> nameToModule;
 
-        static PerfCounter systemModulesTime
-            = PerfCounter.newPerfCounter("jdk.module.bootstrap.systemModulesTime");
-        static PerfCounter defineBaseTime
-            = PerfCounter.newPerfCounter("jdk.module.bootstrap.defineBaseTime");
-        static PerfCounter optionsAndRootsTime
-            = PerfCounter.newPerfCounter("jdk.module.bootstrap.optionsAndRootsTime");
-        static PerfCounter resolveTime
-            = PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime");
-        static PerfCounter layerCreateTime
-            = PerfCounter.newPerfCounter("jdk.module.bootstrap.layerCreateTime");
-        static PerfCounter loadModulesTime
-            = PerfCounter.newPerfCounter("jdk.module.bootstrap.loadModulesTime");
-        static PerfCounter adjustModulesTime
-            = PerfCounter.newPerfCounter("jdk.module.bootstrap.adjustModulesTime");
-        static PerfCounter bootstrapTime
-            = PerfCounter.newPerfCounter("jdk.module.bootstrap.totalTime");
+        SafeModuleFinder(ModuleFinder finder) {
+            this.mrefs = Collections.unmodifiableSet(finder.findAll());
+        }
+        @Override
+        public Optional<ModuleReference> find(String name) {
+            Objects.requireNonNull(name);
+            Map<String, ModuleReference> nameToModule = this.nameToModule;
+            if (nameToModule == null) {
+                this.nameToModule = nameToModule = mrefs.stream()
+                        .collect(Collectors.toMap(m -> m.descriptor().name(),
+                                                  Function.identity()));
+            }
+            return Optional.ofNullable(nameToModule.get(name));
+        }
+        @Override
+        public Set<ModuleReference> findAll() {
+            return mrefs;
+        }
+    }
+
+    /**
+     * Counters for startup performance analysis.
+     */
+    static class Counters {
+        private static final boolean PUBLISH_COUNTERS;
+        private static final boolean PRINT_COUNTERS;
+        private static Map<String, Long> counters;
+        static {
+            String s = System.getProperty("jdk.module.boot.usePerfData");
+            if (s == null) {
+                PUBLISH_COUNTERS = false;
+                PRINT_COUNTERS = false;
+            } else {
+                PUBLISH_COUNTERS = true;
+                PRINT_COUNTERS = s.equals("debug");
+                counters = new LinkedHashMap<>();  // preserve insert order
+            }
+        }
+
+        /**
+         * Add a counter
+         */
+        static void add(String name, long start) {
+            if (PUBLISH_COUNTERS || PRINT_COUNTERS) {
+                counters.put(name, (System.nanoTime() - start));
+            }
+        }
+
+        /**
+         * Publish the counters to the instrumentation buffer or stdout.
+         */
+        static void publish() {
+            if (PUBLISH_COUNTERS || PRINT_COUNTERS) {
+                for (Map.Entry<String, Long> e : counters.entrySet()) {
+                    String name = e.getKey();
+                    long value = e.getValue();
+                    if (PUBLISH_COUNTERS)
+                        PerfCounter.newPerfCounter(name).set(value);
+                    if (PRINT_COUNTERS)
+                        System.out.println(name + " = " + value);
+                }
+            }
+        }
     }
 }
--- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Mon Aug 07 09:45:38 2017 -0700
@@ -200,10 +200,10 @@
     }
 
     /**
-     * Returns true is this module patcher has no patches.
+     * Returns true is this module patcher has patches.
      */
-    public boolean isEmpty() {
-        return map.isEmpty();
+    public boolean hasPatches() {
+        return !map.isEmpty();
     }
 
     /*
--- a/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java	Mon Aug 07 09:45:38 2017 -0700
@@ -68,14 +68,14 @@
     /**
      * Constructs a new instance of this class.
      */
-    ModuleReferenceImpl(ModuleDescriptor descriptor,
-                        URI location,
-                        Supplier<ModuleReader> readerSupplier,
-                        ModulePatcher patcher,
-                        ModuleTarget target,
-                        ModuleHashes recordedHashes,
-                        ModuleHashes.HashSupplier hasher,
-                        ModuleResolution moduleResolution)
+    public ModuleReferenceImpl(ModuleDescriptor descriptor,
+                               URI location,
+                               Supplier<ModuleReader> readerSupplier,
+                               ModulePatcher patcher,
+                               ModuleTarget target,
+                               ModuleHashes recordedHashes,
+                               ModuleHashes.HashSupplier hasher,
+                               ModuleResolution moduleResolution)
     {
         super(descriptor, Objects.requireNonNull(location));
         this.location = location;
--- a/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java	Mon Aug 07 10:02:39 2017 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,469 +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 jdk.internal.module;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleFinder;
-import java.lang.module.ModuleReader;
-import java.lang.module.ModuleReference;
-import java.net.URI;
-import java.net.URLConnection;
-import java.nio.ByteBuffer;
-import java.util.ArrayDeque;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.Spliterator;
-import java.util.function.Consumer;
-import java.util.function.Supplier;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-
-import jdk.internal.jimage.ImageLocation;
-import jdk.internal.jimage.ImageReader;
-import jdk.internal.jimage.ImageReaderFactory;
-import jdk.internal.misc.JavaNetUriAccess;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.ModuleHashes.HashSupplier;
-import jdk.internal.perf.PerfCounter;
-
-/**
- * A {@code ModuleFinder} that finds modules that are linked into the
- * run-time image.
- *
- * The modules linked into the run-time image are assumed to have the
- * Packages attribute.
- */
-
-public class SystemModuleFinder implements ModuleFinder {
-
-    private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
-
-    private static final PerfCounter initTime
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
-    private static final PerfCounter moduleCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
-    private static final PerfCounter packageCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
-    private static final PerfCounter exportsCount
-        = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
-
-    // singleton finder to find modules in the run-time images
-    private static final SystemModuleFinder INSTANCE;
-
-    public static SystemModuleFinder getInstance() {
-        return INSTANCE;
-    }
-
-    /**
-     * For now, the module references are created eagerly on the assumption
-     * that service binding will require all modules to be located.
-     */
-    static {
-        long t0 = System.nanoTime();
-
-        INSTANCE = new SystemModuleFinder();
-
-        initTime.addElapsedTimeFrom(t0);
-    }
-
-    /**
-     * Holder class for the ImageReader
-     */
-    private static class SystemImage {
-        static final ImageReader READER;
-        static {
-            long t0 = System.nanoTime();
-            READER = ImageReaderFactory.getImageReader();
-            initTime.addElapsedTimeFrom(t0);
-        }
-
-        static ImageReader reader() {
-            return READER;
-        }
-    }
-
-    private static boolean isFastPathSupported() {
-       return SystemModules.MODULE_NAMES.length > 0;
-    }
-
-    private static String[] moduleNames() {
-        if (isFastPathSupported())
-            // module names recorded at link time
-            return SystemModules.MODULE_NAMES;
-
-        // this happens when java.base is patched with java.base
-        // from an exploded image
-        return SystemImage.reader().getModuleNames();
-    }
-
-    // the set of modules in the run-time image
-    private final Set<ModuleReference> modules;
-
-    // maps module name to module reference
-    private final Map<String, ModuleReference> nameToModule;
-
-    // module name to hashes
-    private final Map<String, byte[]> hashes;
-
-    private SystemModuleFinder() {
-        String[] names = moduleNames();
-        int n = names.length;
-        moduleCount.add(n);
-
-        // fastpath is enabled by default.
-        // It can be disabled for troubleshooting purpose.
-        boolean disabled =
-            System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
-
-        ModuleDescriptor[] descriptors;
-        ModuleTarget[] targets;
-        ModuleHashes[] recordedHashes;
-        ModuleResolution[] moduleResolutions;
-
-        // fast loading of ModuleDescriptor of system modules
-        if (isFastPathSupported() && !disabled) {
-            descriptors = SystemModules.descriptors();
-            targets = SystemModules.targets();
-            recordedHashes = SystemModules.hashes();
-            moduleResolutions = SystemModules.moduleResolutions();
-        } else {
-            // if fast loading of ModuleDescriptors is disabled
-            // fallback to read module-info.class
-            descriptors = new ModuleDescriptor[n];
-            targets = new ModuleTarget[n];
-            recordedHashes = new ModuleHashes[n];
-            moduleResolutions = new ModuleResolution[n];
-            ImageReader imageReader = SystemImage.reader();
-            for (int i = 0; i < names.length; i++) {
-                String mn = names[i];
-                ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
-                ModuleInfo.Attributes attrs =
-                    ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
-                descriptors[i] = attrs.descriptor();
-                targets[i] = attrs.target();
-                recordedHashes[i] = attrs.recordedHashes();
-                moduleResolutions[i] = attrs.moduleResolution();
-            }
-        }
-
-        Map<String, byte[]> hashes = null;
-        boolean secondSeen = false;
-        // record the hashes to build HashSupplier
-        for (ModuleHashes mh : recordedHashes) {
-            if (mh != null) {
-                // if only one module contain ModuleHashes, use it
-                if (hashes == null) {
-                    hashes = mh.hashes();
-                } else {
-                    if (!secondSeen) {
-                        hashes = new HashMap<>(hashes);
-                        secondSeen = true;
-                    }
-                    hashes.putAll(mh.hashes());
-                }
-            }
-        }
-        this.hashes = (hashes == null) ? Map.of() : hashes;
-
-        ModuleReference[] mods = new ModuleReference[n];
-
-        @SuppressWarnings(value = {"rawtypes", "unchecked"})
-        Entry<String, ModuleReference>[] map
-            = (Entry<String, ModuleReference>[])new Entry[n];
-
-        for (int i = 0; i < n; i++) {
-            ModuleDescriptor md = descriptors[i];
-
-            // create the ModuleReference
-            ModuleReference mref = toModuleReference(md,
-                                                     targets[i],
-                                                     recordedHashes[i],
-                                                     hashSupplier(names[i]),
-                                                     moduleResolutions[i]);
-            mods[i] = mref;
-            map[i] = Map.entry(names[i], mref);
-
-            // counters
-            packageCount.add(md.packages().size());
-            exportsCount.add(md.exports().size());
-        }
-
-        modules = Set.of(mods);
-        nameToModule = Map.ofEntries(map);
-    }
-
-    @Override
-    public Optional<ModuleReference> find(String name) {
-        Objects.requireNonNull(name);
-        return Optional.ofNullable(nameToModule.get(name));
-    }
-
-    @Override
-    public Set<ModuleReference> findAll() {
-        return modules;
-    }
-
-    private ModuleReference toModuleReference(ModuleDescriptor md,
-                                              ModuleTarget target,
-                                              ModuleHashes recordedHashes,
-                                              HashSupplier hasher,
-                                              ModuleResolution mres) {
-        String mn = md.name();
-        URI uri = JNUA.create("jrt", "/".concat(mn));
-
-        Supplier<ModuleReader> readerSupplier = new Supplier<>() {
-            @Override
-            public ModuleReader get() {
-                return new ImageModuleReader(mn, uri);
-            }
-        };
-
-        ModuleReference mref = new ModuleReferenceImpl(md,
-                                                       uri,
-                                                       readerSupplier,
-                                                       null,
-                                                       target,
-                                                       recordedHashes,
-                                                       hasher,
-                                                       mres);
-
-        // may need a reference to a patched module if --patch-module specified
-        mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
-
-        return mref;
-    }
-
-    private HashSupplier hashSupplier(String name) {
-        if (!hashes.containsKey(name))
-            return null;
-
-        return new HashSupplier() {
-            @Override
-            public byte[] generate(String algorithm) {
-                return hashes.get(name);
-            }
-        };
-    }
-
-    /**
-     * A ModuleReader for reading resources from a module linked into the
-     * run-time image.
-     */
-    static class ImageModuleReader implements ModuleReader {
-        private final String module;
-        private volatile boolean closed;
-
-        /**
-         * If there is a security manager set then check permission to
-         * connect to the run-time image.
-         */
-        private static void checkPermissionToConnect(URI uri) {
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                try {
-                    URLConnection uc = uri.toURL().openConnection();
-                    sm.checkPermission(uc.getPermission());
-                } catch (IOException ioe) {
-                    throw new UncheckedIOException(ioe);
-                }
-            }
-        }
-
-        ImageModuleReader(String module, URI uri) {
-            checkPermissionToConnect(uri);
-            this.module = module;
-        }
-
-        /**
-         * Returns the ImageLocation for the given resource, {@code null}
-         * if not found.
-         */
-        private ImageLocation findImageLocation(String name) throws IOException {
-            Objects.requireNonNull(name);
-            if (closed)
-                throw new IOException("ModuleReader is closed");
-            ImageReader imageReader = SystemImage.reader();
-            if (imageReader != null) {
-                return imageReader.findLocation(module, name);
-            } else {
-                // not an images build
-                return null;
-            }
-        }
-
-        @Override
-        public Optional<URI> find(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                URI u = URI.create("jrt:/" + module + "/" + name);
-                return Optional.of(u);
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public Optional<InputStream> open(String name) throws IOException {
-            return read(name).map(this::toInputStream);
-        }
-
-        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
-            try {
-                int rem = bb.remaining();
-                byte[] bytes = new byte[rem];
-                bb.get(bytes);
-                return new ByteArrayInputStream(bytes);
-            } finally {
-                release(bb);
-            }
-        }
-
-        @Override
-        public Optional<ByteBuffer> read(String name) throws IOException {
-            ImageLocation location = findImageLocation(name);
-            if (location != null) {
-                return Optional.of(SystemImage.reader().getResourceBuffer(location));
-            } else {
-                return Optional.empty();
-            }
-        }
-
-        @Override
-        public void release(ByteBuffer bb) {
-            Objects.requireNonNull(bb);
-            ImageReader.releaseByteBuffer(bb);
-        }
-
-        @Override
-        public Stream<String> list() throws IOException {
-            if (closed)
-                throw new IOException("ModuleReader is closed");
-
-            Spliterator<String> s = new ModuleContentSpliterator(module);
-            return StreamSupport.stream(s, false);
-        }
-
-        @Override
-        public void close() {
-            // nothing else to do
-            closed = true;
-        }
-    }
-
-    /**
-     * A Spliterator for traversing the resources of a module linked into the
-     * run-time image.
-     */
-    static class ModuleContentSpliterator implements Spliterator<String> {
-        final String moduleRoot;
-        final Deque<ImageReader.Node> stack;
-        Iterator<ImageReader.Node> iterator;
-
-        ModuleContentSpliterator(String module) throws IOException {
-            moduleRoot = "/modules/" + module;
-            stack = new ArrayDeque<>();
-
-            // push the root node to the stack to get started
-            ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
-            if (dir == null || !dir.isDirectory())
-                throw new IOException(moduleRoot + " not a directory");
-            stack.push(dir);
-            iterator = Collections.emptyIterator();
-        }
-
-        /**
-         * Returns the name of the next non-directory node or {@code null} if
-         * there are no remaining nodes to visit.
-         */
-        private String next() throws IOException {
-            for (;;) {
-                while (iterator.hasNext()) {
-                    ImageReader.Node node = iterator.next();
-                    String name = node.getName();
-                    if (node.isDirectory()) {
-                        // build node
-                        ImageReader.Node dir = SystemImage.reader().findNode(name);
-                        assert dir.isDirectory();
-                        stack.push(dir);
-                    } else {
-                        // strip /modules/$MODULE/ prefix
-                        return name.substring(moduleRoot.length() + 1);
-                    }
-                }
-
-                if (stack.isEmpty()) {
-                    return null;
-                } else {
-                    ImageReader.Node dir = stack.poll();
-                    assert dir.isDirectory();
-                    iterator = dir.getChildren().iterator();
-                }
-            }
-        }
-
-        @Override
-        public boolean tryAdvance(Consumer<? super String> action) {
-            String next;
-            try {
-                next = next();
-            } catch (IOException ioe) {
-                throw new UncheckedIOException(ioe);
-            }
-            if (next != null) {
-                action.accept(next);
-                return true;
-            } else {
-                return false;
-            }
-        }
-
-        @Override
-        public Spliterator<String> trySplit() {
-            return null;
-        }
-
-        @Override
-        public int characteristics() {
-            return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
-        }
-
-        @Override
-        public long estimateSize() {
-            return Long.MAX_VALUE;
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java	Mon Aug 07 09:45:38 2017 -0700
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Constructor;
+import java.net.URI;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import jdk.internal.jimage.ImageLocation;
+import jdk.internal.jimage.ImageReader;
+import jdk.internal.jimage.ImageReaderFactory;
+import jdk.internal.misc.JavaNetUriAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleHashes.HashSupplier;
+
+/**
+ * The factory for SystemModules objects and for creating ModuleFinder objects
+ * that find modules in the runtime image.
+ *
+ * This class supports initializing the module system when the runtime is an
+ * images build, an exploded build, or an images build with java.base patched
+ * by an exploded java.base. It also supports a testing mode that re-parses
+ * the module-info.class resources in the run-time image.
+ */
+
+public final class SystemModuleFinders {
+    private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
+
+    private static final boolean USE_FAST_PATH;
+    static {
+        String value = System.getProperty("jdk.system.module.finder.disableFastPath");
+        if (value == null) {
+            USE_FAST_PATH = true;
+        } else {
+            USE_FAST_PATH = (value.length() > 0) && !Boolean.parseBoolean(value);
+        }
+    }
+
+    // cached ModuleFinder returned from ofSystem
+    private static volatile ModuleFinder cachedSystemModuleFinder;
+
+    private SystemModuleFinders() { }
+
+    /**
+     * Returns the SystemModules object to reconstitute all modules. Returns
+     * null if this is an exploded build or java.base is patched by an exploded
+     * build.
+     */
+    static SystemModules allSystemModules() {
+        if (USE_FAST_PATH) {
+            return SystemModulesMap.allSystemModules();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Returns a SystemModules object to reconstitute the modules for the
+     * given initial module. If the initial module is null then return the
+     * SystemModules object to reconstitute the default modules.
+     *
+     * Return null if there is no SystemModules class for the initial module,
+     * this is an exploded build, or java.base is patched by an exploded build.
+     */
+    static SystemModules systemModules(String initialModule) {
+        if (USE_FAST_PATH) {
+            if (initialModule == null) {
+                return SystemModulesMap.defaultSystemModules();
+            }
+
+            String[] initialModules = SystemModulesMap.moduleNames();
+            for (int i = 0; i < initialModules.length; i++) {
+                String moduleName = initialModules[i];
+                if (initialModule.equals(moduleName)) {
+                    String cn = SystemModulesMap.classNames()[i];
+                    try {
+                        // one-arg Class.forName as java.base may not be defined
+                        Constructor<?> ctor = Class.forName(cn).getConstructor();
+                        return (SystemModules) ctor.newInstance();
+                    } catch (Exception e) {
+                        throw new InternalError(e);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a ModuleFinder that is backed by the given SystemModules object.
+     *
+     * @apiNote The returned ModuleFinder is thread safe.
+     */
+    static ModuleFinder of(SystemModules systemModules) {
+        ModuleDescriptor[] descriptors = systemModules.moduleDescriptors();
+        ModuleTarget[] targets = systemModules.moduleTargets();
+        ModuleHashes[] recordedHashes = systemModules.moduleHashes();
+        ModuleResolution[] moduleResolutions = systemModules.moduleResolutions();
+
+        int moduleCount = descriptors.length;
+        ModuleReference[] mrefs = new ModuleReference[moduleCount];
+        @SuppressWarnings(value = {"rawtypes", "unchecked"})
+        Map.Entry<String, ModuleReference>[] map
+            = (Map.Entry<String, ModuleReference>[])new Map.Entry[moduleCount];
+
+        Map<String, byte[]> nameToHash = generateNameToHash(recordedHashes);
+
+        for (int i = 0; i < moduleCount; i++) {
+            String name = descriptors[i].name();
+            HashSupplier hashSupplier = hashSupplier(nameToHash, name);
+            ModuleReference mref = toModuleReference(descriptors[i],
+                                                     targets[i],
+                                                     recordedHashes[i],
+                                                     hashSupplier,
+                                                     moduleResolutions[i]);
+            mrefs[i] = mref;
+            map[i] = Map.entry(name, mref);
+        }
+
+        return new SystemModuleFinder(mrefs, map);
+    }
+
+    /**
+     * Returns the ModuleFinder to find all system modules. Supports both
+     * images and exploded builds.
+     *
+     * @apiNote Used by ModuleFinder.ofSystem()
+     */
+    public static ModuleFinder ofSystem() {
+        ModuleFinder finder = cachedSystemModuleFinder;
+        if (finder != null) {
+            return finder;
+        }
+
+        // probe to see if this is an images build
+        String home = System.getProperty("java.home");
+        Path modules = Paths.get(home, "lib", "modules");
+        if (Files.isRegularFile(modules)) {
+            if (USE_FAST_PATH) {
+                SystemModules systemModules = allSystemModules();
+                if (systemModules != null) {
+                    finder = of(systemModules);
+                }
+            }
+
+            // fall back to parsing the module-info.class files in image
+            if (finder == null) {
+                finder = ofModuleInfos();
+            }
+
+            cachedSystemModuleFinder = finder;
+            return finder;
+
+        }
+
+        // exploded build (do not cache module finder)
+        Path dir = Paths.get(home, "modules");
+        if (!Files.isDirectory(dir))
+            throw new InternalError("Unable to detect the run-time image");
+        ModuleFinder f = ModulePath.of(ModuleBootstrap.patcher(), dir);
+        return new ModuleFinder() {
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                PrivilegedAction<Optional<ModuleReference>> pa = () -> f.find(name);
+                return AccessController.doPrivileged(pa);
+            }
+            @Override
+            public Set<ModuleReference> findAll() {
+                PrivilegedAction<Set<ModuleReference>> pa = f::findAll;
+                return AccessController.doPrivileged(pa);
+            }
+        };
+    }
+
+    /**
+     * Parses the module-info.class of all module in the runtime image and
+     * returns a ModuleFinder to find the modules.
+     *
+     * @apiNote The returned ModuleFinder is thread safe.
+     */
+    private static ModuleFinder ofModuleInfos() {
+        // parse the module-info.class in every module
+        Map<String, ModuleInfo.Attributes> nameToAttributes = new HashMap<>();
+        Map<String, byte[]> nameToHash = new HashMap<>();
+        ImageReader reader = SystemImage.reader();
+        for (String mn : reader.getModuleNames()) {
+            ImageLocation loc = reader.findLocation(mn, "module-info.class");
+            ModuleInfo.Attributes attrs
+                = ModuleInfo.read(reader.getResourceBuffer(loc), null);
+
+            nameToAttributes.put(mn, attrs);
+            ModuleHashes hashes = attrs.recordedHashes();
+            if (hashes != null) {
+                for (String name : hashes.names()) {
+                    nameToHash.computeIfAbsent(name, k -> hashes.hashFor(name));
+                }
+            }
+        }
+
+        // create a ModuleReference for each module
+        Set<ModuleReference> mrefs = new HashSet<>();
+        Map<String, ModuleReference> nameToModule = new HashMap<>();
+        for (Map.Entry<String, ModuleInfo.Attributes> e : nameToAttributes.entrySet()) {
+            String mn = e.getKey();
+            ModuleInfo.Attributes attrs = e.getValue();
+            HashSupplier hashSupplier = hashSupplier(nameToHash, mn);
+            ModuleReference mref = toModuleReference(attrs.descriptor(),
+                                                     attrs.target(),
+                                                     attrs.recordedHashes(),
+                                                     hashSupplier,
+                                                     attrs.moduleResolution());
+            mrefs.add(mref);
+            nameToModule.put(mn, mref);
+        }
+
+        return new SystemModuleFinder(mrefs, nameToModule);
+    }
+
+    /**
+     * A ModuleFinder that finds module in an array or set of modules.
+     */
+    private static class SystemModuleFinder implements ModuleFinder {
+        final Set<ModuleReference> mrefs;
+        final Map<String, ModuleReference> nameToModule;
+
+        SystemModuleFinder(ModuleReference[] array,
+                           Map.Entry<String, ModuleReference>[] map) {
+            this.mrefs = Set.of(array);
+            this.nameToModule = Map.ofEntries(map);
+        }
+
+        SystemModuleFinder(Set<ModuleReference> mrefs,
+                           Map<String, ModuleReference> nameToModule) {
+            this.mrefs = Collections.unmodifiableSet(mrefs);
+            this.nameToModule = Collections.unmodifiableMap(nameToModule);
+        }
+
+        @Override
+        public Optional<ModuleReference> find(String name) {
+            Objects.requireNonNull(name);
+            return Optional.ofNullable(nameToModule.get(name));
+        }
+
+        @Override
+        public Set<ModuleReference> findAll() {
+            return mrefs;
+        }
+    }
+
+    /**
+     * Creates a ModuleReference to the system module.
+     */
+    static ModuleReference toModuleReference(ModuleDescriptor descriptor,
+                                             ModuleTarget target,
+                                             ModuleHashes recordedHashes,
+                                             HashSupplier hasher,
+                                             ModuleResolution mres) {
+        String mn = descriptor.name();
+        URI uri = JNUA.create("jrt", "/".concat(mn));
+
+        Supplier<ModuleReader> readerSupplier = new Supplier<>() {
+            @Override
+            public ModuleReader get() {
+                return new SystemModuleReader(mn, uri);
+            }
+        };
+
+        ModuleReference mref = new ModuleReferenceImpl(descriptor,
+                                                       uri,
+                                                       readerSupplier,
+                                                       null,
+                                                       target,
+                                                       recordedHashes,
+                                                       hasher,
+                                                       mres);
+
+        // may need a reference to a patched module if --patch-module specified
+        mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
+
+        return mref;
+    }
+
+    /**
+     * Generates a map of module name to hash value.
+     */
+    static Map<String, byte[]> generateNameToHash(ModuleHashes[] recordedHashes) {
+        Map<String, byte[]> nameToHash = null;
+
+        boolean secondSeen = false;
+        // record the hashes to build HashSupplier
+        for (ModuleHashes mh : recordedHashes) {
+            if (mh != null) {
+                // if only one module contain ModuleHashes, use it
+                if (nameToHash == null) {
+                    nameToHash = mh.hashes();
+                } else {
+                    if (!secondSeen) {
+                        nameToHash = new HashMap<>(nameToHash);
+                        secondSeen = true;
+                    }
+                    nameToHash.putAll(mh.hashes());
+                }
+            }
+        }
+        return (nameToHash != null) ? nameToHash : Collections.emptyMap();
+    }
+
+    /**
+     * Returns a HashSupplier that returns the hash of the given module.
+     */
+    static HashSupplier hashSupplier(Map<String, byte[]> nameToHash, String name) {
+        byte[] hash = nameToHash.get(name);
+        if (hash != null) {
+            // avoid lambda here
+            return new HashSupplier() {
+                @Override
+                public byte[] generate(String algorithm) {
+                    return hash;
+                }
+            };
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Holder class for the ImageReader
+     *
+     * @apiNote This class must be loaded before a security manager is set.
+     */
+    private static class SystemImage {
+        static final ImageReader READER = ImageReaderFactory.getImageReader();
+        static ImageReader reader() {
+            return READER;
+        }
+    }
+
+    /**
+     * A ModuleReader for reading resources from a module linked into the
+     * run-time image.
+     */
+    private static class SystemModuleReader implements ModuleReader {
+        private final String module;
+        private volatile boolean closed;
+
+        /**
+         * If there is a security manager set then check permission to
+         * connect to the run-time image.
+         */
+        private static void checkPermissionToConnect(URI uri) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                try {
+                    URLConnection uc = uri.toURL().openConnection();
+                    sm.checkPermission(uc.getPermission());
+                } catch (IOException ioe) {
+                    throw new UncheckedIOException(ioe);
+                }
+            }
+        }
+
+        SystemModuleReader(String module, URI uri) {
+            checkPermissionToConnect(uri);
+            this.module = module;
+        }
+
+        /**
+         * Returns the ImageLocation for the given resource, {@code null}
+         * if not found.
+         */
+        private ImageLocation findImageLocation(String name) throws IOException {
+            Objects.requireNonNull(name);
+            if (closed)
+                throw new IOException("ModuleReader is closed");
+            ImageReader imageReader = SystemImage.reader();
+            if (imageReader != null) {
+                return imageReader.findLocation(module, name);
+            } else {
+                // not an images build
+                return null;
+            }
+        }
+
+        @Override
+        public Optional<URI> find(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                URI u = URI.create("jrt:/" + module + "/" + name);
+                return Optional.of(u);
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public Optional<InputStream> open(String name) throws IOException {
+            return read(name).map(this::toInputStream);
+        }
+
+        private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
+            try {
+                int rem = bb.remaining();
+                byte[] bytes = new byte[rem];
+                bb.get(bytes);
+                return new ByteArrayInputStream(bytes);
+            } finally {
+                release(bb);
+            }
+        }
+
+        @Override
+        public Optional<ByteBuffer> read(String name) throws IOException {
+            ImageLocation location = findImageLocation(name);
+            if (location != null) {
+                return Optional.of(SystemImage.reader().getResourceBuffer(location));
+            } else {
+                return Optional.empty();
+            }
+        }
+
+        @Override
+        public void release(ByteBuffer bb) {
+            Objects.requireNonNull(bb);
+            ImageReader.releaseByteBuffer(bb);
+        }
+
+        @Override
+        public Stream<String> list() throws IOException {
+            if (closed)
+                throw new IOException("ModuleReader is closed");
+
+            Spliterator<String> s = new ModuleContentSpliterator(module);
+            return StreamSupport.stream(s, false);
+        }
+
+        @Override
+        public void close() {
+            // nothing else to do
+            closed = true;
+        }
+    }
+
+    /**
+     * A Spliterator for traversing the resources of a module linked into the
+     * run-time image.
+     */
+    private static class ModuleContentSpliterator implements Spliterator<String> {
+        final String moduleRoot;
+        final Deque<ImageReader.Node> stack;
+        Iterator<ImageReader.Node> iterator;
+
+        ModuleContentSpliterator(String module) throws IOException {
+            moduleRoot = "/modules/" + module;
+            stack = new ArrayDeque<>();
+
+            // push the root node to the stack to get started
+            ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
+            if (dir == null || !dir.isDirectory())
+                throw new IOException(moduleRoot + " not a directory");
+            stack.push(dir);
+            iterator = Collections.emptyIterator();
+        }
+
+        /**
+         * Returns the name of the next non-directory node or {@code null} if
+         * there are no remaining nodes to visit.
+         */
+        private String next() throws IOException {
+            for (;;) {
+                while (iterator.hasNext()) {
+                    ImageReader.Node node = iterator.next();
+                    String name = node.getName();
+                    if (node.isDirectory()) {
+                        // build node
+                        ImageReader.Node dir = SystemImage.reader().findNode(name);
+                        assert dir.isDirectory();
+                        stack.push(dir);
+                    } else {
+                        // strip /modules/$MODULE/ prefix
+                        return name.substring(moduleRoot.length() + 1);
+                    }
+                }
+
+                if (stack.isEmpty()) {
+                    return null;
+                } else {
+                    ImageReader.Node dir = stack.poll();
+                    assert dir.isDirectory();
+                    iterator = dir.getChildren().iterator();
+                }
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super String> action) {
+            String next;
+            try {
+                next = next();
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+            if (next != null) {
+                action.accept(next);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public Spliterator<String> trySplit() {
+            return null;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
+        }
+
+        @Override
+        public long estimateSize() {
+            return Long.MAX_VALUE;
+        }
+    }
+}
--- a/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Mon Aug 07 09:45:38 2017 -0700
@@ -26,94 +26,73 @@
 package jdk.internal.module;
 
 import java.lang.module.ModuleDescriptor;
-import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 
 /**
- * SystemModules class will be generated at link time to create
- * ModuleDescriptor for the system modules directly to improve
- * the module descriptor reconstitution time.
+ * A SystemModules object reconstitutes module descriptors and other modules
+ * attributes in an efficient way to avoid parsing module-info.class files at
+ * startup. Implementations of this class are generated by the "system modules"
+ * jlink plugin.
  *
- * This will skip parsing of module-info.class file and validating
- * names such as module name, package name, service and provider type names.
- * It also avoids taking a defensive copy of any collection.
- *
+ * @see SystemModuleFinders
  * @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
  */
-public final class SystemModules {
-    /**
-     * Name of the system modules.
-     *
-     * This array provides a way for SystemModuleFinder to fallback
-     * and read module-info.class from the run-time image instead of
-     * the fastpath.
-     */
-    public static final String[] MODULE_NAMES = new String[0];
+
+interface SystemModules {
 
     /**
-     * Number of packages in the boot layer from the installed modules.
-     *
-     * Don't make it final to avoid inlining during compile time as
-     * the value will be changed at jlink time.
+     * Returns false if the module reconstituted by this SystemModules object
+     * have no overlapping packages. Returns true if there are overlapping
+     * packages or unknown.
      */
-    public static int PACKAGES_IN_BOOT_LAYER = 1024;
+    boolean hasSplitPackages();
 
     /**
-     * Return true if there are no split packages in the run-time image.
+     * Return false if the modules reconstituted by this SystemModules object
+     * do not include any incubator modules. Returns true if there are
+     * incubating modules or unknown.
      */
-    public static boolean hasSplitPackages() {
-        return true;
-    }
+    boolean hasIncubatorModules();
 
     /**
-     * Returns a non-empty array of ModuleDescriptor objects in the run-time image.
-     *
-     * When running an exploded image it returns an empty array.
+     * Returns the non-empty array of ModuleDescriptor objects.
      */
-    public static ModuleDescriptor[] descriptors() {
-        throw new InternalError("expected to be overridden at link time");
-    }
+    ModuleDescriptor[] moduleDescriptors();
 
     /**
-     * Returns a non-empty array of ModuleTarget objects in the run-time image.
-     *
-     * When running an exploded image it returns an empty array.
+     * Returns the array of ModuleTarget objects. The array elements correspond
+     * to the array of ModuleDescriptor objects.
      */
-    public static ModuleTarget[] targets() {
-        throw new InternalError("expected to be overridden at link time");
-    }
+    ModuleTarget[] moduleTargets();
 
     /**
-     * Returns a non-empty array of ModuleHashes recorded in each module
-     * in the run-time image.
-     *
-     * When running an exploded image it returns an empty array.
+     * Returns the array of ModuleHashes objects. The array elements correspond
+     * to the array of ModuleDescriptor objects.
      */
-    public static ModuleHashes[] hashes() {
-        throw new InternalError("expected to be overridden at link time");
-    }
+    ModuleHashes[] moduleHashes();
 
     /**
-     * Returns a non-empty array of ModuleResolutions in the run-time image.
+     * Returns the array of ModuleResolution objects. The array elements correspond
+     * to the array of ModuleDescriptor objects.
      */
-    public static ModuleResolution[] moduleResolutions() {
-        throw new InternalError("expected to be overridden at link time");
-    }
+    ModuleResolution[] moduleResolutions();
+
+    /**
+     * Returns the map representing readability graph for the modules reconstituted
+     * by this SystemModules object.
+     */
+    Map<String, Set<String>> moduleReads();
 
     /**
      * Returns the map of module concealed packages to open. The map key is the
      * module name, the value is the set of concealed packages to open.
      */
-    public static Map<String, Set<String>> concealedPackagesToOpen() {
-        return Collections.emptyMap();
-    }
+    Map<String, Set<String>> concealedPackagesToOpen();
 
     /**
      * Returns the map of module exported packages to open. The map key is the
      * module name, the value is the set of exported packages to open.
      */
-    public static Map<String, Set<String>> exportedPackagesToOpen() {
-        return Collections.emptyMap();
-    }
+    Map<String, Set<String>> exportedPackagesToOpen();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/SystemModulesMap.java	Mon Aug 07 09:45:38 2017 -0700
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+/**
+ * This class is generated/overridden at link time to return the names of the
+ * SystemModules classes generated at link time.
+ *
+ * @see SystemModuleFinders
+ * @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
+ */
+
+class SystemModulesMap {
+
+    /**
+     * Returns the SystemModules object to reconstitute all modules or null
+     * if this is an exploded build.
+     */
+    static SystemModules allSystemModules() {
+        return null;
+    }
+
+    /**
+     * Returns the SystemModules object to reconstitute default modules or null
+     * if this is an exploded build.
+     */
+    static SystemModules defaultSystemModules() {
+        return null;
+    }
+
+    /**
+     * Returns the array of initial module names identified at link time.
+     */
+    static String[] moduleNames() {
+        return new String[0];
+    }
+
+    /**
+     * Returns the array of of SystemModules class names. The elements
+     * correspond to the elements in the array returned by moduleNames().
+     */
+    static String[] classNames() {
+        return new String[0];
+    }
+}
\ No newline at end of file
--- a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Mon Aug 07 09:45:38 2017 -0700
@@ -316,8 +316,7 @@
      */
     public static boolean isCallerSensitive(Method m) {
         final ClassLoader loader = m.getDeclaringClass().getClassLoader();
-        if (VM.isSystemDomainLoader(loader) ||
-                loader == ClassLoaders.platformClassLoader()) {
+        if (VM.isSystemDomainLoader(loader)) {
             return m.isAnnotationPresent(CallerSensitive.class);
         }
         return false;
--- a/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/sun/nio/ch/SelectorImpl.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, 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,10 +26,18 @@
 package sun.nio.ch;
 
 import java.io.IOException;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
 import java.net.SocketException;
-import java.util.*;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.IllegalSelectorException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.AbstractSelector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
 
 
 /**
@@ -54,23 +62,18 @@
         super(sp);
         keys = new HashSet<>();
         selectedKeys = new HashSet<>();
-        if (Util.atBugLevel("1.4")) {
-            publicKeys = keys;
-            publicSelectedKeys = selectedKeys;
-        } else {
-            publicKeys = Collections.unmodifiableSet(keys);
-            publicSelectedKeys = Util.ungrowableSet(selectedKeys);
-        }
+        publicKeys = Collections.unmodifiableSet(keys);
+        publicSelectedKeys = Util.ungrowableSet(selectedKeys);
     }
 
     public Set<SelectionKey> keys() {
-        if (!isOpen() && !Util.atBugLevel("1.4"))
+        if (!isOpen())
             throw new ClosedSelectorException();
         return publicKeys;
     }
 
     public Set<SelectionKey> selectedKeys() {
-        if (!isOpen() && !Util.atBugLevel("1.4"))
+        if (!isOpen())
             throw new ClosedSelectorException();
         return publicSelectedKeys;
     }
--- a/src/java.base/share/classes/sun/nio/ch/Util.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/sun/nio/ch/Util.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,16 @@
 
 package sun.nio.ch;
 
-import java.lang.reflect.*;
 import java.io.FileDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.nio.ByteBuffer;
 import java.nio.MappedByteBuffer;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.*;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
 import jdk.internal.misc.Unsafe;
 import sun.security.action.GetPropertyAction;
 
@@ -456,21 +459,4 @@
         }
         return dbb;
     }
-
-
-    // -- Bug compatibility --
-
-    private static volatile String bugLevel;
-
-    static boolean atBugLevel(String bl) {              // package-private
-        if (bugLevel == null) {
-            if (!jdk.internal.misc.VM.isBooted())
-                return false;
-            String value = GetPropertyAction
-                    .privilegedGetProperty("sun.nio.ch.bugLevel");
-            bugLevel = (value != null) ? value : "";
-        }
-        return bugLevel.equals(bl);
-    }
-
 }
--- a/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Mon Aug 07 09:45:38 2017 -0700
@@ -79,6 +79,9 @@
     public static final Debug debug = Debug.getInstance("ssl");
 
     // enum HandshakeType:
+    //
+    // Please update the isUnsupported() method accordingly if the handshake
+    // types get updated in the future.
     static final byte   ht_hello_request          = 0;      // RFC 5246
     static final byte   ht_client_hello           = 1;      // RFC 5246
     static final byte   ht_server_hello           = 2;      // RFC 5246
@@ -130,6 +133,24 @@
         return b;
     }
 
+    static boolean isUnsupported(byte handshakeType) {
+        return (handshakeType != ht_hello_request) &&
+               (handshakeType != ht_client_hello) &&
+               (handshakeType != ht_server_hello) &&
+               (handshakeType != ht_hello_verify_request) &&
+               (handshakeType != ht_new_session_ticket) &&
+               (handshakeType != ht_certificate) &&
+               (handshakeType != ht_server_key_exchange) &&
+               (handshakeType != ht_certificate_request) &&
+               (handshakeType != ht_server_hello_done) &&
+               (handshakeType != ht_certificate_verify) &&
+               (handshakeType != ht_client_key_exchange) &&
+               (handshakeType != ht_finished) &&
+               (handshakeType != ht_certificate_url) &&
+               (handshakeType != ht_certificate_status) &&
+               (handshakeType != ht_supplemental_data);
+    }
+
     private static byte[] genPad(int b, int count) {
         byte[] padding = new byte[count];
         Arrays.fill(padding, (byte)b);
--- a/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1034,6 +1034,12 @@
             input.mark(4);
 
             messageType = (byte)input.getInt8();
+            if (HandshakeMessage.isUnsupported(messageType)) {
+                throw new SSLProtocolException(
+                    "Received unsupported or unknown handshake message: " +
+                    messageType);
+            }
+
             messageLen = input.getInt24();
 
             if (input.available() < messageLen) {
--- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, 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
@@ -73,8 +73,8 @@
  * must not be null; the behavior is unspecified if it is.</p>
  *
  * <p>Class loading aspects are detailed in the
- * <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
- * JMX Specification, version 1.4</a> PDF document.</p>
+ * <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html">
+ * JMX Specification, version 1.4</a></p>
  *
  * <p>Most methods in this interface parallel methods in the {@link
  * MBeanServerConnection} interface.  Where an aspect of the behavior
--- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/package.html	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/package.html	Mon Aug 07 09:45:38 2017 -0700
@@ -2,7 +2,7 @@
 <head>
     <title>RMI connector</title>
 <!--
-Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2002, 2017, 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
@@ -316,19 +316,8 @@
     <p>If an RMI connector client or server receives from its peer an
       instance of a class that it does not know, and if dynamic code
       downloading is active for the RMI connection, then the class can
-      be downloaded from a codebase specified by the peer.  The
-      article <a
-    href="{@docRoot}/../technotes/guides/rmi/codebase.html"><em>Dynamic
-    code downloading using Java RMI</em></a> explains this in more
-    detail.</p>
-
-
-    @see <a href="{@docRoot}/../technotes/guides/rmi/index.html">
-	Java&trade; Remote Method
-	Invocation (RMI)</a>
-
-    @see <a href="{@docRoot}/../technotes/guides/jndi/index.html">
-	Java Naming and Directory Interface&trade; (JNDI)</a>
+      be downloaded from a codebase specified by the peer.
+      {@extLink rmi_guide Java RMI Guide} explains this in more detail.</p>
 
     @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045,
     section 6.8, "Base64 Content-Transfer-Encoding"</a>
--- a/src/java.management/share/classes/java/lang/management/ManagementFactory.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management/share/classes/java/lang/management/ManagementFactory.java	Mon Aug 07 09:45:38 2017 -0700
@@ -588,8 +588,8 @@
                                Class<T> mxbeanInterface)
             throws java.io.IOException {
 
-        // Only allow MXBean interfaces from rt.jar loaded by the
-        // bootstrap class loader
+        // Only allow MXBean interfaces from the platform modules loaded by the
+        // bootstrap or platform class loader
         final Class<?> cls = mxbeanInterface;
         ClassLoader loader =
             AccessController.doPrivileged(
--- a/src/java.management/share/classes/javax/management/loading/package.html	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management/share/classes/javax/management/loading/package.html	Mon Aug 07 09:45:38 2017 -0700
@@ -2,7 +2,7 @@
 <head>
 <title>javax.management.loading package</title>
 <!--
-Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
 This code is free software; you can redistribute it and/or modify it
@@ -67,11 +67,8 @@
 	<code>PrivateClassLoader</code>.</p>
 
     <p id="spec">
-    @see <a href="{@docRoot}/../technotes/guides/jmx/">
-      Java Platform documentation on JMX technology</a>,
-    in particular the 
-    <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
-      JMX Specification, version 1.4(pdf).</a>
+    @see <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html">
+      JMX Specification, version 1.4</a>
 
       @since 1.5
 </BODY>
--- a/src/java.management/share/classes/javax/management/modelmbean/package.html	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management/share/classes/javax/management/modelmbean/package.html	Mon Aug 07 09:45:38 2017 -0700
@@ -2,7 +2,7 @@
 <head>
 <title>javax.management.modelmbean package</title>
 <!--
-Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2000, 2017, 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
@@ -114,9 +114,8 @@
 
     <ul>
 	  <li>See the <i>JMX 1.4 Specification</i>
-	     PDF document available from the 
-	     <a href="{@docRoot}/../technotes/guides/jmx/">
-	     Java Platform documentation on JMX technology</a>
+	     <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html">
+             JMX Specification, version 1.4</a>
     </ul>
 
     @since 1.5
--- a/src/java.management/share/classes/javax/management/monitor/package.html	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management/share/classes/javax/management/monitor/package.html	Mon Aug 07 09:45:38 2017 -0700
@@ -2,7 +2,7 @@
 <head>
 <title>javax.management.monitor package</title>
 <!--
-Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 1999, 2017, 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
@@ -184,11 +184,8 @@
 	</li>
       </ul>
     <p id="spec">
-    @see <a href="{@docRoot}/../technotes/guides/jmx/">
-      Java Platform documentation on JMX technology</a>,
-    in particular the 
-    <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
-      JMX Specification, version 1.4(pdf).</a>
+    @see <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html">
+      JMX Specification, version 1.4</a>
       @since 1.5
 
 </BODY>
--- a/src/java.management/share/classes/javax/management/openmbean/package.html	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management/share/classes/javax/management/openmbean/package.html	Mon Aug 07 09:45:38 2017 -0700
@@ -2,7 +2,7 @@
 <head>
 <title>javax.management.openmbean package</title>
 <!--
-Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2001, 2017, 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
@@ -142,10 +142,7 @@
 	then {@code minValue} must not be greater than {@code maxValue}.
     </ul>
 
-    @see <a href="{@docRoot}/../technotes/guides/jmx/">
-      Java Platform documentation on JMX technology</a>,
-    in particular the 
-    <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
+    @see <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html">
       JMX Specification, version 1.4</a>
 
     @since 1.5
--- a/src/java.management/share/classes/javax/management/package.html	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management/share/classes/javax/management/package.html	Mon Aug 07 09:45:38 2017 -0700
@@ -2,7 +2,7 @@
     <head>
         <title>javax.management package</title>
         <!--
-Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 1999, 2017, 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
@@ -389,11 +389,8 @@
         </ul>
 
         <p id="spec">
-        @see <a href="{@docRoot}/../technotes/guides/jmx/index.html">
-        Java Platform documentation on JMX technology</a>
-        in particular the
-        <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
-        JMX Specification, version 1.4(pdf).</a>
+        @see <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html">
+        JMX Specification, version 1.4</a>
 
         @since 1.5
 
--- a/src/java.management/share/classes/javax/management/relation/package.html	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management/share/classes/javax/management/relation/package.html	Mon Aug 07 09:45:38 2017 -0700
@@ -2,7 +2,7 @@
 <head>
 <title>javax.management.relation package</title>
 <!--
-Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2000, 2017, 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
@@ -136,10 +136,7 @@
 // Set of ObjectName containing moduleB
 </pre>
 
-    @see <a href="{@docRoot}/../technotes/guides/jmx/">
-      Java Platform documentation on JMX technology</a>,
-    in particular the 
-    <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
+    @see <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html">
       JMX Specification, version 1.4</a>
 
       @since 1.5
--- a/src/java.management/share/classes/javax/management/remote/package.html	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.management/share/classes/javax/management/remote/package.html	Mon Aug 07 09:45:38 2017 -0700
@@ -2,7 +2,7 @@
 <head>
     <title>JMX&trade; Remote API.</title>
 <!--
-Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
 This code is free software; you can redistribute it and/or modify it
@@ -32,8 +32,8 @@
 	This package defines the essential interfaces for making a JMX
 	MBean server manageable remotely. The specification of this 
         functionality is completed by Part III of the 
-       <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
-	JMX Specification, version 1.4</a> PDF document.</p>
+       <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html">
+	JMX Specification, version 1.4</a></p>
 
       <p>The JMX specification defines the notion of <b>connectors</b>.
 	A connector is attached to a JMX API MBean server and makes it
@@ -194,10 +194,7 @@
 	connector server.</p>
 
 
-    @see <a href="{@docRoot}/../technotes/guides/jmx/">
-      Java Platform documentation on JMX technology</a>,
-    in particular the 
-    <a href="{@docRoot}/../technotes/guides/jmx/JMX_1_4_specification.pdf">
+    @see <a href="https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html">
       JMX Specification, version 1.4</a>
     
     @since 1.5
--- a/src/java.smartcardio/share/classes/javax/smartcardio/CardException.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.smartcardio/share/classes/javax/smartcardio/CardException.java	Mon Aug 07 09:45:38 2017 -0700
@@ -48,7 +48,7 @@
 
     /**
      * Constructs a new CardException with the specified cause and a detail message
-     * of <code>(cause==null ? null : cause.toString())</code>.
+     * of {@code (cause==null ? null : cause.toString())}.
      *
      * @param cause the cause of this exception or null
      */
--- a/src/java.smartcardio/share/classes/javax/smartcardio/CardNotPresentException.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/java.smartcardio/share/classes/javax/smartcardio/CardNotPresentException.java	Mon Aug 07 09:45:38 2017 -0700
@@ -48,7 +48,7 @@
 
     /**
      * Constructs a new CardNotPresentException with the specified cause and a detail message
-     * of <code>(cause==null ? null : cause.toString())</code>.
+     * of {@code (cause==null ? null : cause.toString())}.
      *
      * @param cause the cause of this exception or null
      */
--- a/src/jdk.attach/share/classes/com/sun/tools/attach/AttachPermission.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.attach/share/classes/com/sun/tools/attach/AttachPermission.java	Mon Aug 07 09:45:38 2017 -0700
@@ -42,14 +42,16 @@
  *
  * <table class="striped"><caption style="display:none">Table shows permission
  * target name, what the permission allows, and associated risks</caption>
+ * <thead>
  * <tr>
- * <th>Permission Target Name</th>
- * <th>What the Permission Allows</th>
- * <th>Risks of Allowing this Permission</th>
+ * <th scope="col">Permission Target Name</th>
+ * <th scope="col">What the Permission Allows</th>
+ * <th scope="col">Risks of Allowing this Permission</th>
  * </tr>
- *
+ * </thead>
+ * <tbody>
  * <tr>
- *   <td>attachVirtualMachine</td>
+ *   <th scope="row">attachVirtualMachine</th>
  *   <td>Ability to attach to another Java virtual machine and load agents
  *       into that VM.
  *   </td>
@@ -59,14 +61,14 @@
  * </tr>
  *
  * <tr>
- *   <td>createAttachProvider</td>
+ *   <th scope="row">createAttachProvider</th>
  *   <td>Ability to create an <code>AttachProvider</code> instance.
  *   </td>
  *   <td>This allows an attacker to create an AttachProvider which can
  *       potentially be used to attach to other Java virtual machines.
  *   </td>
  * </tr>
-
+ * </tbody>
  *
  * </table>
 
--- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java	Mon Aug 07 09:45:38 2017 -0700
@@ -59,21 +59,29 @@
  * Paths are matched literally, which means that the strings are compared
  * case sensitively, and with no conversion to or from any encoded forms.
  * For example. Given a HttpServer with the following HttpContexts configured.
- * <table><caption style="display:none">description</caption>
- * <tr><td><i>Context</i></td><td><i>Context path</i></td></tr>
- * <tr><td>ctx1</td><td>"/"</td></tr>
- * <tr><td>ctx2</td><td>"/apps/"</td></tr>
- * <tr><td>ctx3</td><td>"/apps/foo/"</td></tr>
+ * <table class="striped"><caption style="display:none">description</caption>
+ * <thead>
+ * <tr><th scope="col"><i>Context</i></th><th scope="col"><i>Context path</i></th></tr>
+ * </thead>
+ * <tbody>
+ * <tr><th scope="row">ctx1</th><td>"/"</td></tr>
+ * <tr><th scope="row">ctx2</th><td>"/apps/"</td></tr>
+ * <tr><th scope="row">ctx3</th><td>"/apps/foo/"</td></tr>
+ * </tbody>
  * </table>
  * <p>
  * the following table shows some request URIs and which, if any context they would
  * match with.
- * <table><caption style="display:none">description</caption>
- * <tr><td><i>Request URI</i></td><td><i>Matches context</i></td></tr>
- * <tr><td>"http://foo.com/apps/foo/bar"</td><td>ctx3</td></tr>
- * <tr><td>"http://foo.com/apps/Foo/bar"</td><td>no match, wrong case</td></tr>
- * <tr><td>"http://foo.com/apps/app1"</td><td>ctx2</td></tr>
- * <tr><td>"http://foo.com/foo"</td><td>ctx1</td></tr>
+ * <table class="striped"><caption style="display:none">description</caption>
+ * <thead>
+ * <tr><th scope="col"><i>Request URI</i></th><th scope="col"><i>Matches context</i></th></tr>
+ * </thead>
+ * <tbody>
+ * <tr><th scope="row">"http://foo.com/apps/foo/bar"</th><td>ctx3</td></tr>
+ * <tr><th scope="row">"http://foo.com/apps/Foo/bar"</th><td>no match, wrong case</td></tr>
+ * <tr><th scope="row">"http://foo.com/apps/app1"</th><td>ctx2</td></tr>
+ * <tr><th scope="row">"http://foo.com/foo"</th><td>ctx1</td></tr>
+ * </tbody>
  * </table>
  * <p>
  * <b>Note about socket backlogs</b><p>
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpResponse.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpResponse.java	Mon Aug 07 09:45:38 2017 -0700
@@ -618,7 +618,7 @@
          * on one of the given {@code CompletableFuture<Void}s which themselves complete
          * after all individual responses associated with the multi response
          * have completed, or after all push promises have been received.
-         * <p>
+         *
          * @implNote Implementations might follow the pattern shown below
          * <pre>
          * {@code
@@ -633,7 +633,6 @@
          *      }
          * }
          * </pre>
-         * <p>
          *
          * @param onComplete a CompletableFuture which completes after all
          * responses have been received relating to this multi request.
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketTransportService.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketTransportService.java	Mon Aug 07 09:45:38 2017 -0700
@@ -275,6 +275,12 @@
             sa = new InetSocketAddress(localaddress, port);
         }
         ServerSocket ss = new ServerSocket();
+        if (port == 0) {
+            // Only need SO_REUSEADDR if we're using a fixed port. If we
+            // start seeing EADDRINUSE due to collisions in free ports
+            // then we should retry the bind() a few times.
+            ss.setReuseAddress(false);
+        }
         ss.bind(sa);
         return new SocketListenKey(ss);
     }
--- a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, 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
@@ -119,8 +119,26 @@
     return (char *)dbgsysTlsGet(tlsIndex);
 }
 
+/* Set options common to client and server sides */
 static jdwpTransportError
-setOptions(int fd)
+setOptionsCommon(int fd)
+{
+    jvalue dontcare;
+    int err;
+
+    dontcare.i = 0;  /* keep compiler happy */
+
+    err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);
+    if (err < 0) {
+        RETURN_IO_ERROR("setsockopt TCPNODELAY failed");
+    }
+
+    return JDWPTRANSPORT_ERROR_NONE;
+}
+
+/* Set the SO_REUSEADDR option */
+static jdwpTransportError
+setReuseAddrOption(int fd)
 {
     jvalue dontcare;
     int err;
@@ -132,11 +150,6 @@
         RETURN_IO_ERROR("setsockopt SO_REUSEADDR failed");
     }
 
-    err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);
-    if (err < 0) {
-        RETURN_IO_ERROR("setsockopt TCPNODELAY failed");
-    }
-
     return JDWPTRANSPORT_ERROR_NONE;
 }
 
@@ -350,10 +363,21 @@
         RETURN_IO_ERROR("socket creation failed");
     }
 
-    err = setOptions(serverSocketFD);
+    err = setOptionsCommon(serverSocketFD);
     if (err) {
         return err;
     }
+    if (sa.sin_port != 0) {
+        /*
+         * Only need SO_REUSEADDR if we're using a fixed port. If we
+         * start seeing EADDRINUSE due to collisions in free ports
+         * then we should retry the dbgsysBind() a few times.
+         */
+        err = setReuseAddrOption(serverSocketFD);
+        if (err) {
+            return err;
+        }
+    }
 
     err = dbgsysBind(serverSocketFD, (struct sockaddr *)&sa, sizeof(sa));
     if (err < 0) {
@@ -510,12 +534,18 @@
         RETURN_IO_ERROR("unable to create socket");
     }
 
-    err = setOptions(socketFD);
+    err = setOptionsCommon(socketFD);
     if (err) {
         return err;
     }
 
     /*
+     * We don't call setReuseAddrOption() for the non-server socket
+     * case. If we start seeing EADDRINUSE due to collisions in free
+     * ports then we should retry the dbgsysConnect() a few times.
+     */
+
+    /*
      * To do a timed connect we make the socket non-blocking
      * and poll with a timeout;
      */
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Mon Aug 07 09:45:38 2017 -0700
@@ -28,6 +28,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Opens;
@@ -37,12 +38,15 @@
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -50,18 +54,20 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.IntSupplier;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import jdk.internal.module.Checks;
 import jdk.internal.module.ClassFileAttributes;
 import jdk.internal.module.ClassFileConstants;
+import jdk.internal.module.DefaultRoots;
 import jdk.internal.module.IllegalAccessMaps;
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleInfo.Attributes;
 import jdk.internal.module.ModuleInfoExtender;
+import jdk.internal.module.ModuleReferenceImpl;
 import jdk.internal.module.ModuleResolution;
 import jdk.internal.module.ModuleTarget;
-import jdk.internal.module.SystemModules;
 import jdk.internal.org.objectweb.asm.Attribute;
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassVisitor;
@@ -72,33 +78,42 @@
 import static jdk.internal.org.objectweb.asm.Opcodes.*;
 
 import jdk.tools.jlink.internal.ModuleSorter;
+import jdk.tools.jlink.plugin.Plugin;
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.plugin.ResourcePool;
-import jdk.tools.jlink.plugin.Plugin;
 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
 import jdk.tools.jlink.plugin.ResourcePoolEntry;
 
 /**
- * Jlink plugin to reconstitute module descriptors for system modules.
- * It will extend module-info.class with ModulePackages attribute,
- * if not present. It also determines the number of packages of
- * the boot layer at link time.
+ * Jlink plugin to reconstitute module descriptors and other attributes for system
+ * modules. The plugin generates implementations of SystemModules to avoid parsing
+ * module-info.class files at startup. It also generates SystemModulesMap to return
+ * the SystemModules implementation for a specific initial module.
  *
- * This plugin will override jdk.internal.module.SystemModules class
+ * As a side effect, the plugin adds the ModulePackages class file attribute to the
+ * module-info.class files that don't have the attribute.
  *
- * @see jdk.internal.module.SystemModuleFinder
- * @see SystemModules
+ * @see jdk.internal.module.SystemModuleFinders
+ * @see jdk.internal.module.SystemModules
  */
+
 public final class SystemModulesPlugin implements Plugin {
     private static final String NAME = "system-modules";
     private static final String DESCRIPTION =
-        PluginsResourceBundle.getDescription(NAME);
+            PluginsResourceBundle.getDescription(NAME);
+    private static final String SYSTEM_MODULES_MAP_CLASS =
+            "jdk/internal/module/SystemModulesMap";
+    private static final String SYSTEM_MODULES_CLASS_PREFIX =
+            "jdk/internal/module/SystemModules$";
+    private static final String ALL_SYSTEM_MODULES_CLASS =
+            SYSTEM_MODULES_CLASS_PREFIX + "all";
+    private static final String DEFAULT_SYSTEM_MODULES_CLASS =
+            SYSTEM_MODULES_CLASS_PREFIX + "default";
 
     private boolean enabled;
-    private boolean retainModuleTarget;
+
     public SystemModulesPlugin() {
         this.enabled = true;
-        this.retainModuleTarget = false;
     }
 
     @Override
@@ -131,11 +146,7 @@
     public void configure(Map<String, String> config) {
         String arg = config.get(NAME);
         if (arg != null) {
-            if (arg.equals("retainModuleTarget")) {
-                retainModuleTarget = true;
-            } else {
-                throw new IllegalArgumentException(NAME + ": " + arg);
-            }
+            throw new IllegalArgumentException(NAME + ": " + arg);
         }
     }
 
@@ -145,25 +156,56 @@
             throw new PluginException(NAME + " was set");
         }
 
-        SystemModulesClassGenerator generator =
-            new SystemModulesClassGenerator(retainModuleTarget);
+        // validate, transform (if needed), and add the module-info.class files
+        List<ModuleInfo> moduleInfos = transformModuleInfos(in, out);
 
-        // generate the byte code to create ModuleDescriptors
-        // such that the modules linked in the image would skip parsing
-        // of module-info.class and also skip name check
+        // generate and add the SystemModuleMap and SystemModules classes
+        Set<String> generated = genSystemModulesClasses(moduleInfos, out);
+
+        // pass through all other resources
+        in.entries()
+            .filter(data -> !data.path().endsWith("/module-info.class")
+                    && !generated.contains(data.path()))
+            .forEach(data -> out.add(data));
+
+        return out.build();
+    }
+
+    /**
+     * Validates and transforms the module-info.class files in the modules, adding
+     * the ModulePackages class file attribute if needed.
+     *
+     * @return the list of ModuleInfo objects, the first element is java.base
+     */
+    List<ModuleInfo> transformModuleInfos(ResourcePool in, ResourcePoolBuilder out) {
+        List<ModuleInfo> moduleInfos = new ArrayList<>();
 
         // Sort modules in the topological order so that java.base is always first.
         new ModuleSorter(in.moduleView()).sorted().forEach(module -> {
             ResourcePoolEntry data = module.findEntry("module-info.class").orElseThrow(
-                // automatic module not supported yet
+                // automatic modules not supported
                 () ->  new PluginException("module-info.class not found for " +
-                    module.name() + " module")
+                        module.name() + " module")
             );
 
             assert module.name().equals(data.moduleName());
+
             try {
-                // validate the module and add to system modules
-                data = generator.buildModuleInfo(data, module.packages());
+                byte[] content = data.contentBytes();
+                Set<String> packages = module.packages();
+                ModuleInfo moduleInfo = new ModuleInfo(content, packages);
+
+                // link-time validation
+                moduleInfo.validateNames();
+
+                // check if any exported or open package is not present
+                moduleInfo.validatePackages();
+
+                // module-info.class may be overridden to add ModulePackages
+                if (moduleInfo.shouldRewrite()) {
+                    data = data.copyWithContent(moduleInfo.getBytes());
+                }
+                moduleInfos.add(moduleInfo);
 
                 // add resource pool entry
                 out.add(data);
@@ -172,37 +214,134 @@
             }
         });
 
-        // Generate the new class
-        ClassWriter cwriter = generator.getClassWriter();
-        in.entries().forEach(data -> {
-            if (data.path().endsWith("module-info.class"))
-                return;
-            if (generator.isOverriddenClass(data.path())) {
-                byte[] bytes = cwriter.toByteArray();
-                ResourcePoolEntry ndata = data.copyWithContent(bytes);
-                out.add(ndata);
-            } else {
-                out.add(data);
+        return moduleInfos;
+    }
+
+    /**
+     * Generates the SystemModules classes (at least one) and the SystemModulesMap
+     * class to map initial modules to a SystemModules class.
+     *
+     * @return the resource names of the resources added to the pool
+     */
+    private Set<String> genSystemModulesClasses(List<ModuleInfo> moduleInfos,
+                                                ResourcePoolBuilder out) {
+        int moduleCount = moduleInfos.size();
+        ModuleFinder finder = finderOf(moduleInfos);
+        assert finder.findAll().size() == moduleCount;
+
+        // map of initial module name to SystemModules class name
+        Map<String, String> map = new LinkedHashMap<>();
+
+        // the names of resources written to the pool
+        Set<String> generated = new HashSet<>();
+
+        // generate the SystemModules implementation to reconstitute all modules
+        Set<String> allModuleNames = moduleInfos.stream()
+                .map(ModuleInfo::moduleName)
+                .collect(Collectors.toSet());
+        String rn = genSystemModulesClass(moduleInfos,
+                                          resolve(finder, allModuleNames),
+                                          ALL_SYSTEM_MODULES_CLASS,
+                                          out);
+        generated.add(rn);
+
+        // generate, if needed, a SystemModules class to reconstitute the modules
+        // needed for the case that the initial module is the unnamed module.
+        String defaultSystemModulesClassName;
+        Configuration cf = resolve(finder, DefaultRoots.compute(finder));
+        if (cf.modules().size() == moduleCount) {
+            // all modules are resolved so no need to generate a class
+            defaultSystemModulesClassName = ALL_SYSTEM_MODULES_CLASS;
+        } else {
+            defaultSystemModulesClassName = DEFAULT_SYSTEM_MODULES_CLASS;
+            rn = genSystemModulesClass(sublist(moduleInfos, cf),
+                                       cf,
+                                       defaultSystemModulesClassName,
+                                       out);
+            generated.add(rn);
+        }
+
+        // Generate a SystemModules class for each module with a main class
+        int suffix = 0;
+        for (ModuleInfo mi : moduleInfos) {
+            if (mi.descriptor().mainClass().isPresent()) {
+                String moduleName = mi.moduleName();
+                cf = resolve(finder, Set.of(moduleName));
+                if (cf.modules().size() == moduleCount) {
+                    // resolves all modules so no need to generate a class
+                    map.put(moduleName, ALL_SYSTEM_MODULES_CLASS);
+                } else {
+                    String cn = SYSTEM_MODULES_CLASS_PREFIX + (suffix++);
+                    rn = genSystemModulesClass(sublist(moduleInfos, cf), cf, cn, out);
+                    map.put(moduleName, cn);
+                    generated.add(rn);
+                }
             }
-        });
+        }
 
-        return out.build();
+        // generate SystemModulesMap
+        rn = genSystemModulesMapClass(ALL_SYSTEM_MODULES_CLASS,
+                                      defaultSystemModulesClassName,
+                                      map,
+                                      out);
+        generated.add(rn);
+
+        // return the resource names of the generated classes
+        return generated;
+    }
+
+    /**
+     * Resolves a collection of root modules, with service binding, to create
+     * configuration.
+     */
+    private Configuration resolve(ModuleFinder finder, Set<String> roots) {
+        return Configuration.empty().resolveAndBind(finder, ModuleFinder.of(), roots);
+    }
+
+    /**
+     * Returns the list of ModuleInfo objects that correspond to the modules in
+     * the given configuration.
+     */
+    private List<ModuleInfo> sublist(List<ModuleInfo> moduleInfos, Configuration cf) {
+        Set<String> names = cf.modules()
+                .stream()
+                .map(ResolvedModule::name)
+                .collect(Collectors.toSet());
+        return moduleInfos.stream()
+                .filter(mi -> names.contains(mi.moduleName()))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Generate a SystemModules implementation class and add it as a resource.
+     *
+     * @return the name of the class resource added to the pool
+     */
+    private String genSystemModulesClass(List<ModuleInfo> moduleInfos,
+                                         Configuration cf,
+                                         String className,
+                                         ResourcePoolBuilder out) {
+        SystemModulesClassGenerator generator
+            = new SystemModulesClassGenerator(className, moduleInfos);
+        byte[] bytes = generator.getClassWriter(cf).toByteArray();
+        String rn = "/java.base/" + className + ".class";
+        ResourcePoolEntry e = ResourcePoolEntry.create(rn, bytes);
+        out.add(e);
+        return rn;
     }
 
     static class ModuleInfo {
-        private final ByteArrayInputStream bain;
+        private final ByteArrayInputStream bais;
         private final Attributes attrs;
         private final Set<String> packages;
-        private final boolean dropModuleTarget;
         private final boolean addModulePackages;
         private ModuleDescriptor descriptor;  // may be different that the original one
 
-        ModuleInfo(byte[] bytes, Set<String> packages, boolean dropModuleTarget)
-            throws IOException
-        {
-            this.bain = new ByteArrayInputStream(bytes);
+        ModuleInfo(byte[] bytes, Set<String> packages) throws IOException {
+            this.bais = new ByteArrayInputStream(bytes);
             this.packages = packages;
-            this.attrs = jdk.internal.module.ModuleInfo.read(bain, null);
+            this.attrs = jdk.internal.module.ModuleInfo.read(bais, null);
+
             // If ModulePackages attribute is present, the packages from this
             // module descriptor returns the packages in that attribute.
             // If it's not present, ModuleDescriptor::packages only contains
@@ -215,14 +354,6 @@
             // add ModulePackages attribute if this module contains some packages
             // and ModulePackages is not present
             this.addModulePackages = packages.size() > 0 && !hasModulePackages();
-
-            // drop target attribute only if any OS property is present
-            ModuleTarget target = attrs.target();
-            if (dropModuleTarget && target != null) {
-                this.dropModuleTarget = (target.targetPlatform() != null);
-            } else {
-                this.dropModuleTarget = false;
-            }
         }
 
         String moduleName() {
@@ -233,7 +364,6 @@
             return descriptor;
         }
 
-
         Set<String> packages() {
             return packages;
         }
@@ -283,7 +413,6 @@
             }
         }
 
-
         /**
          * Validates if exported and open packages are present
          */
@@ -328,17 +457,15 @@
         }
 
         /**
-         * Returns true if module-info.class should be written
-         * 1. add ModulePackages attribute if not present; or
-         * 2. drop ModuleTarget attribute except java.base
+         * Returns true if module-info.class should be rewritten to add the
+         * ModulePackages attribute.
          */
         boolean shouldRewrite() {
-            return addModulePackages || dropModuleTarget;
+            return addModulePackages;
         }
 
         /**
-         * Returns the bytes for the module-info.class with ModulePackages
-         * attribute added and/or with ModuleTarget attribute dropped.
+         * Returns the bytes for the (possibly updated) module-info.class.
          */
         byte[] getBytes() throws IOException {
             try (InputStream in = getInputStream()) {
@@ -347,13 +474,10 @@
                     if (addModulePackages) {
                         rewriter.addModulePackages(packages);
                     }
-                    if (dropModuleTarget) {
-                        rewriter.dropModuleTarget();
-                    }
                     // rewritten module descriptor
                     byte[] bytes = rewriter.getBytes();
-                    try (ByteArrayInputStream bain = new ByteArrayInputStream(bytes)) {
-                        this.descriptor = ModuleDescriptor.read(bain);
+                    try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) {
+                        this.descriptor = ModuleDescriptor.read(bais);
                     }
                     return bytes;
                 } else {
@@ -366,8 +490,8 @@
          * Returns the input stream of the module-info.class
          */
         InputStream getInputStream() {
-            bain.reset();
-            return bain;
+            bais.reset();
+            return bais;
         }
 
         class ModuleInfoRewriter extends ByteArrayOutputStream {
@@ -383,10 +507,6 @@
                 }
             }
 
-            void dropModuleTarget() {
-                extender.targetPlatform("");
-            }
-
             byte[] getBytes() throws IOException {
                 extender.write(this);
                 return buf;
@@ -395,12 +515,10 @@
     }
 
     /**
-     * ClassWriter of a new jdk.internal.module.SystemModules class
-     * to reconstitute ModuleDescriptor of the system modules.
+     * Generates a SystemModules class to reconstitute the ModuleDescriptor
+     * and other attributes of system modules.
      */
     static class SystemModulesClassGenerator {
-        private static final String CLASSNAME =
-            "jdk/internal/module/SystemModules";
         private static final String MODULE_DESCRIPTOR_BUILDER =
             "jdk/internal/module/Builder";
         private static final String MODULE_DESCRIPTOR_ARRAY_SIGNATURE =
@@ -422,10 +540,6 @@
         private static final String MODULE_RESOLUTIONS_ARRAY_SIGNATURE  =
             "[Ljdk/internal/module/ModuleResolution;";
 
-        // static variables in SystemModules class
-        private static final String MODULE_NAMES = "MODULE_NAMES";
-        private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
-
         private static final int MAX_LOCAL_VARS = 256;
 
         private final int BUILDER_VAR    = 0;
@@ -434,14 +548,14 @@
         private final int MH_VAR         = 1;  // variable for ModuleHashes
         private int nextLocalVar         = 2;  // index to next local variable
 
-        private final ClassWriter cw;
-        private boolean dropModuleTarget;
-
         // Method visitor for generating the SystemModules::modules() method
         private MethodVisitor mv;
 
+        // name of class to generate
+        private final String className;
+
         // list of all ModuleDescriptorBuilders, invoked in turn when building.
-        private final List<ModuleInfo> moduleInfos = new ArrayList<>();
+        private final List<ModuleInfo> moduleInfos;
 
         // A builder to create one single Set instance for a given set of
         // names or modifiers to reduce the footprint
@@ -449,10 +563,11 @@
         private final DedupSetBuilder dedupSetBuilder
             = new DedupSetBuilder(this::getNextLocalVar);
 
-        public SystemModulesClassGenerator(boolean retainModuleTarget) {
-            this.cw = new ClassWriter(ClassWriter.COMPUTE_MAXS +
-                                      ClassWriter.COMPUTE_FRAMES);
-            this.dropModuleTarget = !retainModuleTarget;
+        public SystemModulesClassGenerator(String className,
+                                           List<ModuleInfo> moduleInfos) {
+            this.className = className;
+            this.moduleInfos = moduleInfos;
+            moduleInfos.forEach(mi -> dedups(mi.descriptor()));
         }
 
         private int getNextLocalVar() {
@@ -460,105 +575,10 @@
         }
 
         /*
-         * static initializer initializing the static fields
-         *
-         * static Map<String, ModuleDescriptor> map = new HashMap<>();
-         */
-        private void clinit(int numModules, int numPackages,
-                            boolean hasSplitPackages) {
-            cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME,
-                     null, "java/lang/Object", null);
-
-            // public static String[] MODULE_NAMES = new String[] {....};
-            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULE_NAMES,
-                    "[Ljava/lang/String;", null, null)
-                    .visitEnd();
-
-            // public static int PACKAGES_IN_BOOT_LAYER;
-            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
-                    "I", null, numPackages)
-                    .visitEnd();
-
-            MethodVisitor clinit =
-                cw.visitMethod(ACC_STATIC, "<clinit>", "()V",
-                               null, null);
-            clinit.visitCode();
-
-            // create the MODULE_NAMES array
-            pushInt(clinit, numModules);
-            clinit.visitTypeInsn(ANEWARRAY, "java/lang/String");
-
-            int index = 0;
-            for (ModuleInfo minfo : moduleInfos) {
-                clinit.visitInsn(DUP);                  // arrayref
-                pushInt(clinit, index++);
-                clinit.visitLdcInsn(minfo.moduleName()); // value
-                clinit.visitInsn(AASTORE);
-            }
-
-            clinit.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
-                    "[Ljava/lang/String;");
-
-            clinit.visitInsn(RETURN);
-            clinit.visitMaxs(0, 0);
-            clinit.visitEnd();
-
-            // public static boolean hasSplitPackages();
-            MethodVisitor split =
-                cw.visitMethod(ACC_PUBLIC+ACC_STATIC, "hasSplitPackages",
-                               "()Z", null, null);
-            split.visitCode();
-            split.visitInsn(hasSplitPackages ? ICONST_1 : ICONST_0);
-            split.visitInsn(IRETURN);
-            split.visitMaxs(0, 0);
-            split.visitEnd();
-
-        }
-
-        /*
          * Adds the given ModuleDescriptor to the system module list.
          * It performs link-time validation and prepares mapping from various
          * Sets to SetBuilders to emit an optimized number of sets during build.
          */
-        public ResourcePoolEntry buildModuleInfo(ResourcePoolEntry entry,
-                                                 Set<String> packages)
-            throws IOException
-        {
-            if (moduleInfos.isEmpty() && !entry.moduleName().equals("java.base")) {
-                throw new InternalError("java.base must be the first module to process");
-            }
-
-            ModuleInfo moduleInfo;
-            if (entry.moduleName().equals("java.base")) {
-                moduleInfo = new ModuleInfo(entry.contentBytes(), packages, false);
-                ModuleDescriptor md = moduleInfo.descriptor;
-                // drop ModuleTarget attribute if java.base has all OS properties
-                ModuleTarget target = moduleInfo.target();
-                if (dropModuleTarget && target.targetPlatform() != null) {
-                    dropModuleTarget = true;
-                } else {
-                    dropModuleTarget = false;
-                }
-            } else {
-                moduleInfo = new ModuleInfo(entry.contentBytes(), packages, dropModuleTarget);
-            }
-
-            // link-time validation
-            moduleInfo.validateNames();
-            // check if any exported or open package is not present
-            moduleInfo.validatePackages();
-
-            // module-info.class may be overridden for optimization
-            // 1. update ModuleTarget attribute to drop targetPlartform
-            // 2. add/update ModulePackages attribute
-            if (moduleInfo.shouldRewrite()) {
-                entry = entry.copyWithContent(moduleInfo.getBytes());
-            }
-            moduleInfos.add(moduleInfo);
-            dedups(moduleInfo.descriptor());
-            return entry;
-        }
-
         private void dedups(ModuleDescriptor md) {
             // exports
             for (Exports e : md.exports()) {
@@ -581,47 +601,123 @@
             dedupSetBuilder.stringSet(md.uses());
         }
 
-        /*
-         * Generate bytecode for SystemModules
+        /**
+         * Generate SystemModules class
          */
-        public ClassWriter getClassWriter() {
-            int numModules = moduleInfos.size();
-            Set<String> allPackages = new HashSet<>();
-            int packageCount = 0;
-            for (ModuleInfo minfo : moduleInfos) {
-                allPackages.addAll(minfo.packages);
-                packageCount += minfo.packages.size();
-            }
+        public ClassWriter getClassWriter(Configuration cf) {
+            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                             + ClassWriter.COMPUTE_FRAMES);
+            cw.visit(Opcodes.V1_8,
+                     ACC_FINAL+ACC_SUPER,
+                     className,
+                     null,
+                     "java/lang/Object",
+                     new String[] { "jdk/internal/module/SystemModules" });
 
-            int numPackages = allPackages.size();
-            boolean hasSplitPackages = (numPackages < packageCount);
-            clinit(numModules, numPackages, hasSplitPackages);
+            // generate <init>
+            genConstructor(cw);
 
-            // generate SystemModules::descriptors
-            genDescriptorsMethod();
+            // generate hasSplitPackages
+            genHasSplitPackages(cw);
 
-            // generate SystemModules::targets
-            genTargetsMethod();
+            // generate hasIncubatorModules
+            genIncubatorModules(cw);
 
-            // generate SystemModules::hashes
-            genHashesMethod();
+            // generate moduleDescriptors
+            genModuleDescriptorsMethod(cw);
 
-            // generate SystemModules::moduleResolutions
-            genModuleResolutionsMethod();
+            // generate moduleTargets
+            genModuleTargetsMethod(cw);
 
-            // generate SystemModules::concealedPackagesToOpen and
-            // SystemModules::exportedPackagesToOpen
-            genXXXPackagesToOpenMethods();
+            // generate moduleHashes
+            genModuleHashesMethod(cw);
+
+            // generate moduleResolutions
+            genModuleResolutionsMethod(cw);
+
+            // generate moduleReads
+            genModuleReads(cw, cf);
+
+            // generate concealedPackagesToOpen and exportedPackagesToOpen
+            genXXXPackagesToOpenMethods(cw);
 
             return cw;
         }
 
         /**
-         * Generate bytecode for SystemModules::descriptors method
+         * Generate byteccode for no-arg constructor
          */
-        private void genDescriptorsMethod() {
-            this.mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
-                                     "descriptors",
+        private void genConstructor(ClassWriter cw) {
+            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitMethodInsn(INVOKESPECIAL,
+                               "java/lang/Object",
+                               "<init>",
+                               "()V",
+                               false);
+            mv.visitInsn(RETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+        }
+
+        /**
+         * Generate bytecode for hasSplitPackages method
+         */
+        private void genHasSplitPackages(ClassWriter cw) {
+            boolean distinct = moduleInfos.stream()
+                    .map(ModuleInfo::packages)
+                    .flatMap(Set::stream)
+                    .allMatch(new HashSet<>()::add);
+            boolean hasSplitPackages = !distinct;
+
+            mv = cw.visitMethod(ACC_PUBLIC,
+                                "hasSplitPackages",
+                                "()Z",
+                                "()Z",
+                                null);
+            mv.visitCode();
+            if (hasSplitPackages) {
+                mv.visitInsn(ICONST_1);
+            } else {
+                mv.visitInsn(ICONST_0);
+            }
+            mv.visitInsn(IRETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+        }
+
+        /**
+         * Generate bytecode for hasIncubatorModules method
+         */
+        private void genIncubatorModules(ClassWriter cw) {
+            boolean hasIncubatorModules = moduleInfos.stream()
+                    .map(ModuleInfo::moduleResolution)
+                    .filter(mres -> (mres != null && mres.hasIncubatingWarning()))
+                    .findFirst()
+                    .isPresent();
+
+            mv = cw.visitMethod(ACC_PUBLIC,
+                                "hasIncubatorModules",
+                                "()Z",
+                                "()Z",
+                                null);
+            mv.visitCode();
+            if (hasIncubatorModules) {
+                mv.visitInsn(ICONST_1);
+            } else {
+                mv.visitInsn(ICONST_0);
+            }
+            mv.visitInsn(IRETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+        }
+
+        /**
+         * Generate bytecode for moduleDescriptors method
+         */
+        private void genModuleDescriptorsMethod(ClassWriter cw) {
+            this.mv = cw.visitMethod(ACC_PUBLIC,
+                                     "moduleDescriptors",
                                      "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
                                      "()" + MODULE_DESCRIPTOR_ARRAY_SIGNATURE,
                                      null);
@@ -643,11 +739,11 @@
         }
 
         /**
-         * Generate bytecode for SystemModules::targets method
+         * Generate bytecode for moduleTargets method
          */
-        private void genTargetsMethod() {
-            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
-                                              "targets",
+        private void genModuleTargetsMethod(ClassWriter cw) {
+            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
+                                              "moduleTargets",
                                               "()" + MODULE_TARGET_ARRAY_SIGNATURE,
                                               "()" + MODULE_TARGET_ARRAY_SIGNATURE,
                                               null);
@@ -656,18 +752,34 @@
             mv.visitTypeInsn(ANEWARRAY, MODULE_TARGET_CLASSNAME);
             mv.visitVarInsn(ASTORE, MT_VAR);
 
-            for (int index=0; index < moduleInfos.size(); index++) {
+
+            // if java.base has a ModuleTarget attribute then generate the array
+            // with one element, all other elements will be null.
+
+            ModuleInfo base = moduleInfos.get(0);
+            if (!base.moduleName().equals("java.base"))
+                throw new InternalError("java.base should be first module in list");
+            ModuleTarget target = base.target();
+
+            int count;
+            if (target != null && target.targetPlatform() != null) {
+                count = 1;
+            } else {
+                count = moduleInfos.size();
+            }
+
+            for (int index = 0; index < count; index++) {
                 ModuleInfo minfo = moduleInfos.get(index);
-                if (minfo.target() != null && !minfo.dropModuleTarget) {
+                if (minfo.target() != null) {
                     mv.visitVarInsn(ALOAD, MT_VAR);
                     pushInt(mv, index);
 
-                    // new ModuleTarget(String, String)
+                    // new ModuleTarget(String)
                     mv.visitTypeInsn(NEW, MODULE_TARGET_CLASSNAME);
                     mv.visitInsn(DUP);
                     mv.visitLdcInsn(minfo.target().targetPlatform());
                     mv.visitMethodInsn(INVOKESPECIAL, MODULE_TARGET_CLASSNAME,
-                        "<init>", "(Ljava/lang/String;)V", false);
+                                       "<init>", "(Ljava/lang/String;)V", false);
 
                     mv.visitInsn(AASTORE);
                 }
@@ -680,12 +792,12 @@
         }
 
         /**
-         * Generate bytecode for SystemModules::hashes method
+         * Generate bytecode for moduleHashes method
          */
-        private void genHashesMethod() {
+        private void genModuleHashesMethod(ClassWriter cw) {
             MethodVisitor hmv =
-                cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
-                               "hashes",
+                cw.visitMethod(ACC_PUBLIC,
+                               "moduleHashes",
                                "()" + MODULE_HASHES_ARRAY_SIGNATURE,
                                "()" + MODULE_HASHES_ARRAY_SIGNATURE,
                                null);
@@ -710,11 +822,11 @@
         }
 
         /**
-         * Generate bytecode for SystemModules::methodResoultions method
+         * Generate bytecode for moduleResolutions method
          */
-        private void genModuleResolutionsMethod() {
+        private void genModuleResolutionsMethod(ClassWriter cw) {
             MethodVisitor mresmv =
-                cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+                cw.visitMethod(ACC_PUBLIC,
                                "moduleResolutions",
                                "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
                                "()" + MODULE_RESOLUTIONS_ARRAY_SIGNATURE,
@@ -746,75 +858,88 @@
         }
 
         /**
-         * Generate SystemModules::concealedPackagesToOpen and
-         * SystemModules::exportedPackagesToOpen methods.
+         * Generate bytecode for moduleReads method
          */
-        private void genXXXPackagesToOpenMethods() {
-            List<ModuleDescriptor> descriptors = moduleInfos.stream()
-                    .map(ModuleInfo::descriptor)
-                    .collect(Collectors.toList());
-            ModuleFinder finder = finderOf(descriptors);
-            IllegalAccessMaps maps = IllegalAccessMaps.generate(finder);
-            generate("concealedPackagesToOpen", maps.concealedPackagesToOpen());
-            generate("exportedPackagesToOpen", maps.exportedPackagesToOpen());
+        private void genModuleReads(ClassWriter cw, Configuration cf) {
+            // module name -> names of modules that it reads
+            Map<String, Set<String>> map = cf.modules().stream()
+                    .collect(Collectors.toMap(
+                            ResolvedModule::name,
+                            m -> m.reads().stream()
+                                    .map(ResolvedModule::name)
+                                    .collect(Collectors.toSet())));
+            generate(cw, "moduleReads", map, true);
         }
 
         /**
-         * Generate SystemModules:XXXPackagesToOpen
+         * Generate concealedPackagesToOpen and exportedPackagesToOpen methods.
          */
-        private void generate(String methodName, Map<String, Set<String>> map) {
-            // Map<String, Set<String>> XXXPackagesToOpen()
-            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+        private void genXXXPackagesToOpenMethods(ClassWriter cw) {
+            ModuleFinder finder = finderOf(moduleInfos);
+            IllegalAccessMaps maps = IllegalAccessMaps.generate(finder);
+            generate(cw, "concealedPackagesToOpen", maps.concealedPackagesToOpen(), false);
+            generate(cw, "exportedPackagesToOpen", maps.exportedPackagesToOpen(), false);
+        }
+
+        /**
+         * Generate method to return {@code Map<String, Set<String>>}.
+         *
+         * If {@code dedup} is true then the values are de-duplicated.
+         */
+        private void generate(ClassWriter cw,
+                              String methodName,
+                              Map<String, Set<String>> map,
+                              boolean dedup) {
+            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
                                               methodName,
                                               "()Ljava/util/Map;",
                                               "()Ljava/util/Map;",
                                               null);
             mv.visitCode();
 
-            // new Map$Entry[moduleCount]
+            // map of Set -> local
+            Map<Set<String>, Integer> locals;
+
+            // generate code to create the sets that are duplicated
+            if (dedup) {
+                Collection<Set<String>> values = map.values();
+                Set<Set<String>> duplicateSets = values.stream()
+                        .distinct()
+                        .filter(s -> Collections.frequency(values, s) > 1)
+                        .collect(Collectors.toSet());
+                locals = new HashMap<>();
+                int index = 1;
+                for (Set<String> s : duplicateSets) {
+                    genImmutableSet(mv, s);
+                    mv.visitVarInsn(ASTORE, index);
+                    locals.put(s, index);
+                    if (++index >= MAX_LOCAL_VARS) {
+                        break;
+                    }
+                }
+            } else {
+                locals = Map.of();
+            }
+
+            // new Map$Entry[size]
             pushInt(mv, map.size());
             mv.visitTypeInsn(ANEWARRAY, "java/util/Map$Entry");
 
             int index = 0;
             for (Map.Entry<String, Set<String>> e : map.entrySet()) {
-                String moduleName = e.getKey();
-                Set<String> packages = e.getValue();
-                int packageCount = packages.size();
+                String name = e.getKey();
+                Set<String> s = e.getValue();
 
                 mv.visitInsn(DUP);
                 pushInt(mv, index);
-                mv.visitLdcInsn(moduleName);
+                mv.visitLdcInsn(name);
 
-                // use Set.of(Object[]) when there are more than 2 packages
-                // use Set.of(Object) or Set.of(Object, Object) when fewer packages
-                if (packageCount > 2) {
-                    pushInt(mv, packageCount);
-                    mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
-                    int i = 0;
-                    for (String pn : packages) {
-                        mv.visitInsn(DUP);
-                        pushInt(mv, i);
-                        mv.visitLdcInsn(pn);
-                        mv.visitInsn(AASTORE);
-                        i++;
-                    }
-                    mv.visitMethodInsn(INVOKESTATIC,
-                                       "java/util/Set",
-                                       "of",
-                                       "([Ljava/lang/Object;)Ljava/util/Set;",
-                                       true);
+                // if de-duplicated then load the local, otherwise generate code
+                Integer varIndex = locals.get(s);
+                if (varIndex == null) {
+                    genImmutableSet(mv, s);
                 } else {
-                    StringBuilder sb = new StringBuilder("(");
-                    for (String pn : packages) {
-                        mv.visitLdcInsn(pn);
-                        sb.append("Ljava/lang/Object;");
-                    }
-                    sb.append(")Ljava/util/Set;");
-                    mv.visitMethodInsn(INVOKESTATIC,
-                                       "java/util/Set",
-                                       "of",
-                                       sb.toString(),
-                                       true);
+                    mv.visitVarInsn(ALOAD, varIndex);
                 }
 
                 String desc = "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/Map$Entry;";
@@ -835,19 +960,42 @@
             mv.visitEnd();
         }
 
-        public boolean isOverriddenClass(String path) {
-            return path.equals("/java.base/" + CLASSNAME + ".class");
-        }
+        /**
+         * Generate code to generate an immutable set.
+         */
+        private void genImmutableSet(MethodVisitor mv, Set<String> set) {
+            int size = set.size();
 
-        void pushInt(MethodVisitor mv, int num) {
-            if (num <= 5) {
-                mv.visitInsn(ICONST_0 + num);
-            } else if (num < Byte.MAX_VALUE) {
-                mv.visitIntInsn(BIPUSH, num);
-            } else if (num < Short.MAX_VALUE) {
-                mv.visitIntInsn(SIPUSH, num);
+            // use Set.of(Object[]) when there are more than 2 elements
+            // use Set.of(Object) or Set.of(Object, Object) when fewer
+            if (size > 2) {
+                pushInt(mv, size);
+                mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+                int i = 0;
+                for (String element : set) {
+                    mv.visitInsn(DUP);
+                    pushInt(mv, i);
+                    mv.visitLdcInsn(element);
+                    mv.visitInsn(AASTORE);
+                    i++;
+                }
+                mv.visitMethodInsn(INVOKESTATIC,
+                        "java/util/Set",
+                        "of",
+                        "([Ljava/lang/Object;)Ljava/util/Set;",
+                        true);
             } else {
-                throw new IllegalArgumentException("exceed limit: " + num);
+                StringBuilder sb = new StringBuilder("(");
+                for (String element : set) {
+                    mv.visitLdcInsn(element);
+                    sb.append("Ljava/lang/Object;");
+                }
+                sb.append(")Ljava/util/Set;");
+                mv.visitMethodInsn(INVOKESTATIC,
+                        "java/util/Set",
+                        "of",
+                        sb.toString(),
+                        true);
             }
         }
 
@@ -1564,18 +1712,159 @@
         }
     }
 
-    static ModuleFinder finderOf(Iterable<ModuleDescriptor> descriptors) {
+    /**
+     * Generate SystemModulesMap and add it as a resource.
+     *
+     * @return the name of the class resource added to the pool
+     */
+    private String genSystemModulesMapClass(String allSystemModulesClassName,
+                                            String defaultSystemModulesClassName,
+                                            Map<String, String> map,
+                                            ResourcePoolBuilder out) {
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+        cw.visit(Opcodes.V1_8,
+                 ACC_FINAL+ACC_SUPER,
+                 SYSTEM_MODULES_MAP_CLASS,
+                 null,
+                 "java/lang/Object",
+                 null);
+
+        // <init>
+        MethodVisitor mv = cw.visitMethod(0, "<init>", "()V", null, null);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL,
+                           "java/lang/Object",
+                           "<init>",
+                           "()V",
+                           false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // allSystemModules()
+        mv = cw.visitMethod(ACC_STATIC,
+                            "allSystemModules",
+                            "()Ljdk/internal/module/SystemModules;",
+                            "()Ljdk/internal/module/SystemModules;",
+                            null);
+        mv.visitCode();
+        mv.visitTypeInsn(NEW, allSystemModulesClassName);
+        mv.visitInsn(DUP);
+        mv.visitMethodInsn(INVOKESPECIAL,
+                           allSystemModulesClassName,
+                           "<init>",
+                           "()V",
+                           false);
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // defaultSystemModules()
+        mv = cw.visitMethod(ACC_STATIC,
+                            "defaultSystemModules",
+                            "()Ljdk/internal/module/SystemModules;",
+                            "()Ljdk/internal/module/SystemModules;",
+                            null);
+        mv.visitCode();
+        mv.visitTypeInsn(NEW, defaultSystemModulesClassName);
+        mv.visitInsn(DUP);
+        mv.visitMethodInsn(INVOKESPECIAL,
+                           defaultSystemModulesClassName,
+                           "<init>",
+                           "()V",
+                           false);
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // moduleNames()
+        mv = cw.visitMethod(ACC_STATIC,
+                            "moduleNames",
+                            "()[Ljava/lang/String;",
+                            "()[Ljava/lang/String;",
+                            null);
+        mv.visitCode();
+        pushInt(mv, map.size());
+        mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+
+        int index = 0;
+        for (String moduleName : map.keySet()) {
+            mv.visitInsn(DUP);                  // arrayref
+            pushInt(mv, index);
+            mv.visitLdcInsn(moduleName);
+            mv.visitInsn(AASTORE);
+            index++;
+        }
+
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // classNames()
+        mv = cw.visitMethod(ACC_STATIC,
+                            "classNames",
+                            "()[Ljava/lang/String;",
+                            "()[Ljava/lang/String;",
+                            null);
+        mv.visitCode();
+        pushInt(mv, map.size());
+        mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+
+        index = 0;
+        for (String className : map.values()) {
+            mv.visitInsn(DUP);                  // arrayref
+            pushInt(mv, index);
+            mv.visitLdcInsn(className.replace('/', '.'));
+            mv.visitInsn(AASTORE);
+            index++;
+        }
+
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // write the class file to the pool as a resource
+        String rn = "/java.base/" + SYSTEM_MODULES_MAP_CLASS + ".class";
+        ResourcePoolEntry e = ResourcePoolEntry.create(rn, cw.toByteArray());
+        out.add(e);
+
+        return rn;
+    }
+
+    /**
+     * Pushes an int constant
+     */
+    private static void pushInt(MethodVisitor mv, int value) {
+        if (value <= 5) {
+            mv.visitInsn(ICONST_0 + value);
+        } else if (value < Byte.MAX_VALUE) {
+            mv.visitIntInsn(BIPUSH, value);
+        } else if (value < Short.MAX_VALUE) {
+            mv.visitIntInsn(SIPUSH, value);
+        } else {
+            throw new IllegalArgumentException("exceed limit: " + value);
+        }
+    }
+
+    /**
+     * Returns a module finder that finds all modules in the given list
+     */
+    private static ModuleFinder finderOf(Collection<ModuleInfo> moduleInfos) {
+        Supplier<ModuleReader> readerSupplier = () -> null;
         Map<String, ModuleReference> namesToReference = new HashMap<>();
-        for (ModuleDescriptor descriptor : descriptors) {
-            String name = descriptor.name();
-            URI uri = URI.create("module:/" + name);
-            ModuleReference mref = new ModuleReference(descriptor, uri) {
-                @Override
-                public ModuleReader open() {
-                    throw new UnsupportedOperationException();
-                }
-            };
-            namesToReference.putIfAbsent(name, mref);
+        for (ModuleInfo mi : moduleInfos) {
+            String name = mi.moduleName();
+            ModuleReference mref
+                = new ModuleReferenceImpl(mi.descriptor(),
+                                          URI.create("jrt:/" + name),
+                                          readerSupplier,
+                                          null,
+                                          mi.target(),
+                                          null,
+                                          null,
+                                          mi.moduleResolution());
+            namesToReference.put(name, mref);
         }
 
         return new ModuleFinder() {
--- a/src/jdk.management/share/classes/com/sun/management/DiagnosticCommandMBean.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.management/share/classes/com/sun/management/DiagnosticCommandMBean.java	Mon Aug 07 09:45:38 2017 -0700
@@ -107,35 +107,38 @@
  * diagnostic command are described in the table below:
  *
  * <table class="striped"><caption style="display:none">description</caption>
+ *   <thead>
  *   <tr>
- *     <th>Name</th><th>Type</th><th>Description</th>
+ *     <th scope="col">Name</th><th scope="col">Type</th><th scope="col">Description</th>
  *   </tr>
+ *   </thead>
+ *   <tbody>
  *   <tr>
- *     <td>dcmd.name</td><td>String</td>
+ *     <th scope="row">dcmd.name</th><td>String</td>
  *     <td>The original diagnostic command name (not the operation name)</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.description</td><td>String</td>
+ *     <th scope="row">dcmd.description</th><td>String</td>
  *     <td>The diagnostic command description</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.help</td><td>String</td>
+ *     <th scope="row">dcmd.help</th><td>String</td>
  *     <td>The full help message for this diagnostic command (same output as
  *          the one produced by the 'help' command)</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.vmImpact</td><td>String</td>
+ *     <th scope="row">dcmd.vmImpact</th><td>String</td>
  *     <td>The impact of the diagnostic command,
  *      this value is the same as the one printed in the 'impact'
  *      section of the help message of the diagnostic command, and it
  *      is different from the getImpact() of the MBeanOperationInfo</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.enabled</td><td>boolean</td>
+ *     <th scope="row">dcmd.enabled</th><td>boolean</td>
  *     <td>True if the diagnostic command is enabled, false otherwise</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.permissionClass</td><td>String</td>
+ *     <th scope="row">dcmd.permissionClass</th><td>String</td>
  *     <td>Some diagnostic command might require a specific permission to be
  *          executed, in addition to the MBeanPermission to invoke their
  *          associated MBean operation. This field returns the fully qualified
@@ -143,22 +146,23 @@
  *   </td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.permissionName</td><td>String</td>
+ *     <th scope="row">dcmd.permissionName</th><td>String</td>
  *     <td>The fist argument of the permission required to execute this
  *          diagnostic command or null if no permission is required</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.permissionAction</td><td>String</td>
+ *     <th scope="row">dcmd.permissionAction</th><td>String</td>
  *     <td>The second argument of the permission required to execute this
  *          diagnostic command or null if the permission constructor has only
  *          one argument (like the ManagementPermission) or if no permission
  *          is required</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.arguments</td><td>Descriptor</td>
+ *     <th scope="row">dcmd.arguments</th><td>Descriptor</td>
  *     <td>A Descriptor instance containing the descriptions of options and
  *          arguments supported by the diagnostic command (see below)</td>
  *   </tr>
+ *   </tbody>
  * </table>
  *
  * <p>The description of parameters (options or arguments) of a diagnostic
@@ -168,37 +172,41 @@
  * instance are described in the table below:
  *
  * <table class="striped"><caption style="display:none">description</caption>
+ *   <thead>
  *   <tr>
- *     <th>Name</th><th>Type</th><th>Description</th>
+ *     <th scope="col">Name</th><th scope="col">Type</th><th scope="col">Description</th>
  *   </tr>
+ *   </thead>
+ *   <tbody>
  *   <tr>
- *     <td>dcmd.arg.name</td><td>String</td>
+ *     <th scope="row">dcmd.arg.name</th><td>String</td>
  *     <td>The name of the parameter</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.arg.type</td><td>String</td>
+ *     <th scope="row">dcmd.arg.type</th><td>String</td>
  *     <td>The type of the parameter. The returned String is the name of a type
  *          recognized by the diagnostic command parser. These types are not
  *          Java types and are implementation dependent.
  *          </td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.arg.description</td><td>String</td>
+ *     <th scope="row">dcmd.arg.description</th><td>String</td>
  *     <td>The parameter description</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.arg.isMandatory</td><td>boolean</td>
+ *     <th scope="row">dcmd.arg.isMandatory</th><td>boolean</td>
  *     <td>True if the parameter is mandatory, false otherwise</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.arg.isOption</td><td>boolean</td>
+ *     <th scope="row">dcmd.arg.isOption</th><td>boolean</td>
  *     <td>True if the parameter is an option, false if it is an argument</td>
  *   </tr>
  *   <tr>
- *     <td>dcmd.arg.isMultiple</td><td>boolean</td>
+ *     <th scope="row">dcmd.arg.isMultiple</th><td>boolean</td>
  *     <td>True if the parameter can be specified several times, false
  *          otherwise</td>
  *   </tr>
+ *   </tbody>
  * </table>
  *
  * <p>When the set of diagnostic commands currently supported by the Java
--- a/src/jdk.management/share/classes/com/sun/management/GarbageCollectionNotificationInfo.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.management/share/classes/com/sun/management/GarbageCollectionNotificationInfo.java	Mon Aug 07 09:45:38 2017 -0700
@@ -182,26 +182,30 @@
      * the following attributes:
      * <blockquote>
      * <table class="striped"><caption style="display:none">description</caption>
+     * <thead>
      * <tr>
-     *   <th style="text-align:left">Attribute Name</th>
-     *   <th style="text-align:left">Type</th>
+     *   <th scope="col" style="text-align:left">Attribute Name</th>
+     *   <th scope="col" style="text-align:left">Type</th>
      * </tr>
+     * </thead>
+     * <tbody>
      * <tr>
-     *   <td>gcName</td>
+     *   <th scope="row">gcName</th>
      *   <td>{@code java.lang.String}</td>
      * </tr>
      * <tr>
-     *   <td>gcAction</td>
+     *   <th scope="row">gcAction</th>
      *   <td>{@code java.lang.String}</td>
      * </tr>
      * <tr>
-     *   <td>gcCause</td>
+     *   <th scope="row">gcCause</th>
      *   <td>{@code java.lang.String}</td>
      * </tr>
      * <tr>
-     *   <td>gcInfo</td>
+     *   <th scope="row">gcInfo</th>
      *   <td>{@code javax.management.openmbean.CompositeData}</td>
      * </tr>
+     * </tbody>
      * </table>
      * </blockquote>
      *
--- a/src/jdk.management/share/classes/com/sun/management/GcInfo.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.management/share/classes/com/sun/management/GcInfo.java	Mon Aug 07 09:45:38 2017 -0700
@@ -184,30 +184,34 @@
      *
      * <blockquote>
      * <table class="striped"><caption style="display:none">description</caption>
+     * <thead>
      * <tr>
-     *   <th style="text-align:left">Attribute Name</th>
-     *   <th style="text-align:left">Type</th>
+     *   <th scope="col" style="text-align:left">Attribute Name</th>
+     *   <th scope="col" style="text-align:left">Type</th>
      * </tr>
+     * </thead>
+     * <tbody>
      * <tr>
-     *   <td>index</td>
+     *   <th scope="row">index</th>
      *   <td>{@code java.lang.Long}</td>
      * </tr>
      * <tr>
-     *   <td>startTime</td>
+     *   <th scope="row">startTime</th>
      *   <td>{@code java.lang.Long}</td>
      * </tr>
      * <tr>
-     *   <td>endTime</td>
+     *   <th scope="row">endTime</th>
      *   <td>{@code java.lang.Long}</td>
      * </tr>
      * <tr>
-     *   <td>memoryUsageBeforeGc</td>
+     *   <th scope="row">memoryUsageBeforeGc</th>
      *   <td>{@code javax.management.openmbean.TabularData}</td>
      * </tr>
      * <tr>
-     *   <td>memoryUsageAfterGc</td>
+     *   <th scope="row">memoryUsageAfterGc</th>
      *   <td>{@code javax.management.openmbean.TabularData}</td>
      * </tr>
+     * </tbody>
      * </table>
      * </blockquote>
      *
--- a/src/jdk.management/share/classes/com/sun/management/VMOption.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.management/share/classes/com/sun/management/VMOption.java	Mon Aug 07 09:45:38 2017 -0700
@@ -191,26 +191,30 @@
      *
      * <blockquote>
      * <table class="striped"><caption style="display:none">description</caption>
+     * <thead>
      * <tr>
-     *   <th style="text-align:left">Attribute Name</th>
-     *   <th style="text-align:left">Type</th>
+     *   <th scope="col" style="text-align:left">Attribute Name</th>
+     *   <th scope="col" style="text-align:left">Type</th>
      * </tr>
+     * </thead>
+     * <tbody>
      * <tr>
-     *   <td>name</td>
+     *   <th scope="row">name</th>
      *   <td>{@code java.lang.String}</td>
      * </tr>
      * <tr>
-     *   <td>value</td>
+     *   <th scope="row">value</th>
      *   <td>{@code java.lang.String}</td>
      * </tr>
      * <tr>
-     *   <td>origin</td>
+     *   <th scope="row">origin</th>
      *   <td>{@code java.lang.String}</td>
      * </tr>
      * <tr>
-     *   <td>writeable</td>
+     *   <th scope="row">writeable</th>
      *   <td>{@code java.lang.Boolean}</td>
      * </tr>
+     * </tbody>
      * </table>
      * </blockquote>
      *
--- a/src/jdk.net/share/classes/jdk/net/NetworkPermission.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/src/jdk.net/share/classes/jdk/net/NetworkPermission.java	Mon Aug 07 09:45:38 2017 -0700
@@ -36,25 +36,30 @@
  *
  * <table class="striped"><caption style="display:none">permission target name,
  *  what the target allows,and associated risks</caption>
+ * <thead>
  * <tr>
- *   <th>Permission Target Name</th>
- *   <th>What the Permission Allows</th>
- *   <th>Risks of Allowing this Permission</th>
+ *   <th scope="col">Permission Target Name</th>
+ *   <th scope="col">What the Permission Allows</th>
+ *   <th scope="col">Risks of Allowing this Permission</th>
  * </tr>
+ * </thead>
+ * <tbody>
  * <tr>
- *   <td>setOption.SO_FLOW_SLA</td>
+ *   <th scope="row">setOption.SO_FLOW_SLA</th>
  *   <td>set the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA} option
  *       on any socket that supports it</td>
  *   <td>allows caller to set a higher priority or bandwidth allocation
  *       to sockets it creates, than they might otherwise be allowed.</td>
  * </tr>
  * <tr>
- *   <td>getOption.SO_FLOW_SLA</td>
+ *   <th scope="row">getOption.SO_FLOW_SLA</th>
  *   <td>retrieve the {@link ExtendedSocketOptions#SO_FLOW_SLA SO_FLOW_SLA}
  *       setting from any socket that supports the option</td>
  *   <td>allows caller access to SLA information that it might not
  *       otherwise have</td>
- * </tr></table>
+ * </tr>
+ * </tbody>
+ * </table>
  *
  * @see jdk.net.ExtendedSocketOptions
  *
--- a/test/java/lang/ClassLoader/getResource/GetResource.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/lang/ClassLoader/getResource/GetResource.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, 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,11 +21,45 @@
  * questions.
  */
 
+/*
+ * @test
+ * @bug 6760902
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.ProcessTools
+ * @run testng GetResource
+ * @summary Empty path on bootclasspath is not default to current working
+ *          directory for both class lookup and resource lookup whereas
+ *          empty path on classpath is default to current working directory.
+ */
+
+import java.io.File;
+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.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.testlibrary.JDKToolFinder;
+import static jdk.testlibrary.ProcessTools.*;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
 
 public class GetResource {
+    private static final Path CWD = Paths.get(System.getProperty("user.dir"));
+    private static final String DIR_A = "a";
+    private static final String DIR_B = "b";
+
     private static final String RESOURCE_NAME = "test.properties";
-    public static void main(String[] args) {
+    private static final String GETRESOURCE_CLASS = "GetResource.class";
+
+    public static void main(String... args) {
         String expect = args[0] + "/" + RESOURCE_NAME;
         URL url = GetResource.class.getResource(RESOURCE_NAME);
         System.out.println("getResource found: " + url);
@@ -39,4 +73,98 @@
             throw new RuntimeException(url + " != expected resource " + expect);
         }
     }
+
+    @BeforeTest
+    public void setup() throws IOException {
+        // setup two directories "a" and "b"
+        // each directory contains both test.properties and this test class
+        Path testSrc = Paths.get(System.getProperty("test.src"));
+        Path testClasses = Paths.get(System.getProperty("test.classes"));
+
+        Files.createDirectories(Paths.get(DIR_A));
+        Files.createDirectories(Paths.get(DIR_B));
+
+        Files.copy(testSrc.resolve(RESOURCE_NAME),
+                   Paths.get(DIR_A, RESOURCE_NAME));
+        Files.copy(testSrc.resolve(RESOURCE_NAME),
+                   Paths.get(DIR_B, RESOURCE_NAME));
+
+        Files.copy(testClasses.resolve(GETRESOURCE_CLASS),
+                   Paths.get(DIR_A, GETRESOURCE_CLASS));
+        Files.copy(testClasses.resolve(GETRESOURCE_CLASS),
+                   Paths.get(DIR_B, GETRESOURCE_CLASS));
+    }
+
+    private String concat(String... dirs) {
+        return Stream.of(dirs).collect(Collectors.joining(File.pathSeparator));
+    }
+
+    @DataProvider
+    public Object[][] options() {
+        return new Object[][] {
+            new Object[] { List.of("-Xbootclasspath/a:a"), "a"},
+            new Object[] { List.of("-Xbootclasspath/a:b"), "b"},
+            new Object[] { List.of("-Xbootclasspath/a:" + concat("a", "b")), "a"},
+            new Object[] { List.of("-Xbootclasspath/a:" + concat("b", "a")), "b"},
+
+            new Object[] { List.of("-cp", "a"), "a"},
+            new Object[] { List.of("-cp", "b"), "b"},
+            new Object[] { List.of("-cp", concat("a", "b")), "a"},
+            new Object[] { List.of("-cp", concat("b", "a")), "b"},
+        };
+    }
+
+    @Test(dataProvider = "options")
+    public void test(List<String> options, String expected) throws Throwable {
+        runTest(CWD, options, expected);
+    }
+
+    @DataProvider
+    public Object[][] dirA() {
+        String dirB = ".." + File.separator + "b";
+        return new Object[][] {
+            new Object[] { List.of("-Xbootclasspath/a:."), "a"},
+
+            new Object[] { List.of("-Xbootclasspath/a:" + dirB), "b"},
+            // empty path in first element
+            new Object[] { List.of("-Xbootclasspath/a:" + File.pathSeparator + dirB), "b"},
+
+            new Object[] { List.of("-cp", File.pathSeparator), "a"},
+            new Object[] { List.of("-cp", dirB), "b"},
+            new Object[] { List.of("-cp", File.pathSeparator + dirB), "a"},
+        };
+    }
+
+    @Test(dataProvider = "dirA")
+    public void testCurrentDirA(List<String> options, String expected) throws Throwable {
+        // current working directory is "a"
+        runTest(CWD.resolve(DIR_A), options, expected);
+    }
+
+    private void runTest(Path dir, List<String> options, String expected)
+        throws Throwable
+    {
+        String javapath = JDKToolFinder.getJDKTool("java");
+
+        List<String> cmdLine = new ArrayList<>();
+        cmdLine.add(javapath);
+        options.forEach(cmdLine::add);
+
+        cmdLine.add("GetResource");
+        cmdLine.add(expected);
+
+        System.out.println("Command line: " + cmdLine);
+        ProcessBuilder pb =
+            new ProcessBuilder(cmdLine.stream().toArray(String[]::new));
+
+        // change working directory
+        pb.directory(dir.toFile());
+
+        // remove CLASSPATH environment variable
+        Map<String,String> env = pb.environment();
+        String value = env.remove("CLASSPATH");
+
+        executeCommand(pb).shouldHaveExitValue(0);
+    }
+
 }
--- a/test/java/lang/ClassLoader/getResource/GetResource.sh	Mon Aug 07 10:02:39 2017 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +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.
-#
-
-# @test
-# @bug 6760902
-# @summary Empty path on bootclasspath is not default to current working
-#          directory for both class lookup and resource lookup whereas
-#          empty path on classpath is default to current working directory.
-#
-# @run shell GetResource.sh
-
-if [ -z "$TESTJAVA" ]; then
-  if [ $# -lt 1 ]; then exit 1; fi
-  TESTJAVA="$1"; shift
-  COMPILEJAVA="${TESTJAVA}"
-  TESTSRC="`pwd`"
-  TESTCLASSES="`pwd`"
-fi
-
-# set platform-specific variables
-OS=`uname -s`
-case "$OS" in
-  Windows*)
-    PS=";"
-    ;;
-  CYGWIN* )
-    PS=";"
-    TESTCLASSES=`/usr/bin/cygpath -a -s -m ${TESTCLASSES}`
-    ;;
-  * )
-    PS=":"
-    ;;
-esac
-
-echo TESTSRC=${TESTSRC}
-echo TESTCLASSES=${TESTCLASSES}
-echo TESTJAVA=${TESTJAVA}
-echo ""
-
-${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
-        -d ${TESTCLASSES} \
-        ${TESTSRC}/GetResource.java  || exit 10
-
-setup() {
-    dest=${TESTCLASSES}/$1
-    rm -rf $dest
-    mkdir $dest
-    cp ${TESTSRC}/test.properties $dest
-    cp ${TESTCLASSES}/GetResource.class $dest
-}
-
-
-count=0
-runTest() {
-    expected=$1;
-    vmoption=$2; shift; shift
-    count=`expr $count+1`
-    echo "Test $count : $vmoption $@"
-    ${TESTJAVA}/bin/java ${TESTVMOPTS} "$vmoption" $@ \
-        GetResource $expected     || exit $count
-}
-
-# run test
-setup "a"
-setup "b"
-
-cd ${TESTCLASSES}
-DIR=`pwd`
-
-#    Expected    -classpath
-runTest "a"      -cp a
-runTest "a"      -cp "a${PS}b"
-runTest "b"      -cp b
-runTest "b"      -cp "b${PS}a"
-
-cd ${DIR}/a
-
-# no -classpath
-runTest "a"      -cp "${PS}"                            
-runTest "b"      -cp "../b"                   
-
-# Test empty path in classpath default to current working directory
-runTest "a"      -cp "${PS}../b"
-
--- a/test/java/net/httpclient/security/0.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/0.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/1.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/1.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/10.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/10.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -22,6 +22,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/11.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/11.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -24,6 +24,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/12.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/12.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -24,6 +24,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/14.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/14.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/15.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/15.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -26,6 +26,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/2.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/2.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/3.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/3.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/4.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/4.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -24,6 +24,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/5.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/5.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/6.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/6.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/7.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/7.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/8.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/8.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/9.policy	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/9.policy	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 grant codeBase "jrt:/jdk.incubator.httpclient" {
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
     permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
     permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
 
--- a/test/java/net/httpclient/security/Driver.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/net/httpclient/security/Driver.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -34,7 +34,7 @@
  * @compile ../ProxyServer.java
  * @build Security
  *
- * @run driver/timeout=60 Driver
+ * @run driver/timeout=90 Driver
  */
 
 /**
--- a/test/java/nio/channels/Selector/KeySets.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/nio/channels/Selector/KeySets.java	Mon Aug 07 09:45:38 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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,34 +26,25 @@
  * @summary Check various properties of key and selected-key sets
  *
  * @run main KeySets
- * @run main/othervm -Dsun.nio.ch.bugLevel=1.4 KeySets
  */
 
 import java.io.*;
 import java.nio.channels.*;
 import java.util.*;
 
-
 public class KeySets {
 
-    static boolean compat;
-
     static abstract class Catch {
         abstract void go() throws Exception;
         Catch(Class xc) throws Exception {
             try {
                 go();
             } catch (Exception x) {
-                if (compat)
-                    throw new Exception("Exception thrown", x);
                 if (xc.isInstance(x))
                     return;
                 throw new Exception("Wrong exception", x);
             }
-            if (compat)
-                return;
-            throw new Exception("Not thrown as expected: "
-                                + xc.getName());
+            throw new Exception("Not thrown as expected: " + xc.getName());
         }
     }
 
@@ -74,7 +65,6 @@
                 void go() throws Exception {
                     sel.selectedKeys();
                 }};
-
     }
 
     static void testNoAddition(final Set s) throws Exception {
@@ -174,14 +164,10 @@
         sel.selectedKeys().clear();
         if (!sel.selectedKeys().isEmpty())
             throw new Exception("clear failed");
-
     }
 
     public static void main(String[] args) throws Exception {
-        String bl = System.getProperty("sun.nio.ch.bugLevel");
-        compat = (bl != null) && bl.equals("1.4");
         testClose();
         testMutability();
     }
-
 }
--- a/test/java/rmi/testlibrary/TestSocketFactory.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/rmi/testlibrary/TestSocketFactory.java	Mon Aug 07 09:45:38 2017 -0700
@@ -512,9 +512,8 @@
             } else {
                 if (matchIndex > 0) {
                     // mismatch, write out any that matched already
-                    if (matchIndex > 0) // Only non-trivial matches
-                        DEBUG( "Partial match %s matched %d bytes at offset: %d (0x%04x), expected: x%02x, actual: x%02x%n",
-                                name, matchIndex, bytesOut, bytesOut,  matchBytes[matchIndex], b);
+                    DEBUG("Partial match %s matched %d bytes at offset: %d (0x%04x), expected: x%02x, actual: x%02x%n",
+                            name, matchIndex, bytesOut, bytesOut, matchBytes[matchIndex], b);
                     out.write(matchBytes, 0, matchIndex);
                     log.write(matchBytes, 0, matchIndex);
                     bytesOut += matchIndex;
@@ -530,6 +529,19 @@
             }
         }
 
+        public void flush() throws IOException {
+            if (matchIndex > 0) {
+                // write out any that matched already to avoid consumer hang.
+                // Match/replace across a flush is not supported.
+                DEBUG( "Flush partial match %s matched %d bytes at offset: %d (0x%04x)%n",
+                        name, matchIndex, bytesOut, bytesOut);
+                out.write(matchBytes, 0, matchIndex);
+                log.write(matchBytes, 0, matchIndex);
+                bytesOut += matchIndex;
+                matchIndex = 0;
+            }
+        }
+
         @Override
         public String toString() {
             return String.format("%s: Out: (%d)", name, bytesOut);
--- a/test/java/util/ResourceBundle/modules/layer/run.sh	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/java/util/ResourceBundle/modules/layer/run.sh	Mon Aug 07 09:45:38 2017 -0700
@@ -22,7 +22,7 @@
 #
 
 # @test
-# @bug 8180375
+# @bug 8180375 8185251
 # @summary Tests resource bundles are correctly loaded from
 #   modules through "<packageName>.spi.<simpleName>Provider" types.
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/ResourceBundle/modules/layer/src/m1/p/resources/MyResource_en.properties	Mon Aug 07 09:45:38 2017 -0700
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2017, 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.
+#
+
+# Purposely empty resource bundle
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/IllegalHandshakeMessage.java	Mon Aug 07 09:45:38 2017 -0700
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+//
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8180643
+ * @summary Illegal handshake message
+ *
+ * @run main/othervm IllegalHandshakeMessage
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class IllegalHandshakeMessage {
+
+    public static void main(String args[]) throws Exception {
+        SSLContext context = SSLContext.getDefault();
+
+        SSLEngine cliEngine = context.createSSLEngine();
+        cliEngine.setUseClientMode(true);
+        SSLEngine srvEngine = context.createSSLEngine();
+        srvEngine.setUseClientMode(false);
+
+        SSLSession session = cliEngine.getSession();
+        int netBufferMax = session.getPacketBufferSize();
+        int appBufferMax = session.getApplicationBufferSize();
+
+        ByteBuffer cliToSrv = ByteBuffer.allocateDirect(netBufferMax);
+        ByteBuffer srvToCli = ByteBuffer.allocateDirect(netBufferMax);
+        ByteBuffer srvIBuff = ByteBuffer.allocateDirect(appBufferMax + 50);
+        ByteBuffer cliOBuff = ByteBuffer.wrap("I'm client".getBytes());
+        ByteBuffer srvOBuff = ByteBuffer.wrap("I'm server".getBytes());
+
+
+        System.out.println("client hello (handshake type(0xAB))");
+        SSLEngineResult cliRes = cliEngine.wrap(cliOBuff, cliToSrv);
+        System.out.println("Client wrap result: " + cliRes);
+        cliToSrv.flip();
+        if (cliToSrv.limit() > 7) {
+            cliToSrv.put(5, (byte)0xAB);    // use illegal handshake type
+            cliToSrv.put(7, (byte)0x80);    // use illegal message length
+        } else {
+            // unlikely
+            throw new Exception("No handshage message generated.");
+        }
+
+        try {
+            SSLEngineResult srvRes = srvEngine.unwrap(cliToSrv, srvIBuff);
+            System.out.println("Server unwrap result: " + srvRes);
+            runDelegatedTasks(srvRes, srvEngine);
+
+            srvRes = srvEngine.wrap(srvOBuff, srvToCli);
+            System.out.println("Server wrap result: " + srvRes);
+
+            throw new Exception(
+                "Unsupported handshake message is not handled properly.");
+        } catch (SSLException e) {
+            // get the expected exception
+            System.out.println("Expected exception: " + e);
+        }
+    }
+
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                System.out.println("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            System.out.println("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+}
+
--- a/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/tools/jlink/plugins/SystemModuleDescriptors/SystemModulesTest.java	Mon Aug 07 09:45:38 2017 -0700
@@ -111,16 +111,10 @@
 
     private void checkAttributes(ModuleReference modRef) {
         try {
-            if (modRef.descriptor().name().equals("java.base")) {
-                ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
-                String[] values = mt.targetPlatform().split("-");
-                assertTrue(checkOSName(values[0]));
-                assertTrue(checkOSArch(values[1]));
-            } else {
-                // target platform attribute is dropped by jlink plugin for other modules
-                ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
-                assertTrue(mt == null || mt.targetPlatform() == null);
-            }
+            ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
+            String[] values = mt.targetPlatform().split("-");
+            assertTrue(checkOSName(values[0]));
+            assertTrue(checkOSArch(values[1]));
         } catch (IOException exp) {
             throw new UncheckedIOException(exp);
         }
--- a/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/tools/jlink/plugins/SystemModuleDescriptors/UserModuleTest.java	Mon Aug 07 09:45:38 2017 -0700
@@ -284,7 +284,6 @@
         Set<String> modules = Set.of("m1", "m4");
         assertTrue(JLINK_TOOL.run(System.out, System.out,
             "--output", dir.toString(),
-            "--system-modules", "retainModuleTarget",
             "--exclude-resources", "m4/p4/dummy/*",
             "--add-modules", modules.stream().collect(Collectors.joining(",")),
             "--module-path", mp) == 0);
--- a/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/tools/jlink/plugins/SystemModuleDescriptors/src/m4/p4/Main.java	Mon Aug 07 09:45:38 2017 -0700
@@ -32,7 +32,7 @@
 import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.Collections;
+import java.util.Map;
 import java.util.Set;
 
 import jdk.internal.module.ClassFileAttributes;
@@ -67,8 +67,7 @@
     }
 
     private static boolean hasModuleTarget(String modName) throws IOException {
-        FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
-                                                  Collections.emptyMap());
+        FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Map.of());
         Path path = fs.getPath("/", "modules", modName, "module-info.class");
         try (InputStream in = Files.newInputStream(path)) {
             return hasModuleTarget(in);
@@ -86,8 +85,8 @@
             expectModuleTarget = true;
         }
 
-        // java.base is packaged with osName/osArch/osVersion
-        if (! hasModuleTarget("java.base")) {
+        // java.base is packaged with ModuleTarget
+        if (!hasModuleTarget("java.base")) {
             throw new RuntimeException("ModuleTarget absent for java.base");
         }
 
@@ -109,8 +108,7 @@
         }
 
         // verify ModuleDescriptor from module-info.class read from jimage
-        FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
-            Collections.emptyMap());
+        FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Map.of());
         Path path = fs.getPath("/", "modules", mn, "module-info.class");
         checkModuleDescriptor(ModuleDescriptor.read(Files.newInputStream(path)), packages);
     }
@@ -121,16 +119,9 @@
             throw new RuntimeException(md.mainClass().toString());
         }
 
-        if (expectModuleTarget) {
-            // ModuleTarget attribute is retained
-            if (! hasModuleTarget(md.name())) {
-                throw new RuntimeException("ModuleTarget missing for " + md.name());
-            }
-        } else {
-            // by default ModuleTarget attribute is dropped
-            if (hasModuleTarget(md.name())) {
-                throw new RuntimeException("ModuleTarget present for " + md.name());
-            }
+        // ModuleTarget attribute should be present
+        if (!hasModuleTarget(md.name())) {
+            throw new RuntimeException("ModuleTarget missing for " + md.name());
         }
 
         Set<String> pkgs = md.packages();
--- a/test/tools/launcher/modules/illegalaccess/IllegalAccessTest.java	Mon Aug 07 10:02:39 2017 +0530
+++ b/test/tools/launcher/modules/illegalaccess/IllegalAccessTest.java	Mon Aug 07 09:45:38 2017 -0700
@@ -23,6 +23,7 @@
 
 /**
  * @test
+ * @requires vm.compMode != "Xcomp"
  * @modules java.base/jdk.internal.misc
  *          java.base/sun.security.x509
  *          java.activation
--- a/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java	Mon Aug 07 10:02:39 2017 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * 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.module;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-/*
- * Test --patch-module java.base=jdk/modules/java.base to override
- * java.base with an exploded image
- */
-public final class SystemModules {
-    public static final String[] MODULE_NAMES = new String[0];
-
-    public static int PACKAGES_IN_BOOT_LAYER = 1024;
-
-    public static boolean hasSplitPackages() {
-        return true;
-    }
-
-    public static Map<String, Set<String>> concealedPackagesToOpen() {
-        return Collections.emptyMap();
-    }
-
-    public static Map<String, Set<String>> exportedPackagesToOpen() {
-        return Collections.emptyMap();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModulesMap.java	Mon Aug 07 09:45:38 2017 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, 2017, 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.module;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/*
+ * Test --patch-module java.base=jdk/modules/java.base to override
+ * java.base with an exploded image
+ */
+class SystemModulesMap {
+    static SystemModules allSystemModules() {
+        return null;
+    }
+    static SystemModules defaultSystemModules() {
+        return null;
+    }
+    static String[] moduleNames() {
+        return new String[0];
+    }
+    static String[] classNames() {
+        return new String[0];
+    }
+}